ネイティブ要素による React 用アクセシブル UI:フィールド、ボタン、表、タブ、ダイアログ、通知、AA 準拠トークン
インストール
genpm add @core/ui含まれるもの
- src/lib/ui/ にソースコード(5 ファイル)。 (19.2 KB)
- src/lib/ui/AGENTS.md に AI ルール、加えて IDE 用のルールファイル。
README
このパッケージには README がありません。
これは AI が src/lib/ui で作業するときに読む内容そのものです。それ以外はコンテキストに追加されません。
@core/ui — rules for AI agents
Purpose
Small accessible component set for React built on native elements (no UI library): Button, TextField,
TextareaField, SelectField, Checkbox, Field (label + help + error wiring), DataTable (with aria-sort),
Pagination, Tabs (WAI-ARIA, arrow keys), Dialog (native <dialog>), Alert, Badge, Card, Toasts,
Spinner, Skeleton. Styling lives in ui.css as CSS variables (light/dark, WCAG AA contrast) and ui-* classes.
Used by @core/admin, @core/blocks and the kits.
Map
index.ts— all components andcx().components.ts— implementation.ui.css— tokens and styles.
Integration
- Import the stylesheet once in the root layout:
import '@/lib/ui/ui.css'and addclassName="ui-root"to<body>. - Use components:
<TextField label="Email" type="email" required error={errors.email} />,<Button variant="primary" loading={saving}>Save</Button>. - Theme: change
--ui-*variables in your CSS; force a theme with<html data-theme="dark">. - Verify: tab through a form; every control has a visible focus ring and a label.
Conventions
- Every field gets a visible label (use
hideLabelonly when context makes it obvious); errors go inerror, not in placeholders. - Interactive elements are real
<button>/<a>/inputs; don't add click handlers to<div>. - Pass translated
labelstoPaginationanddismissLabeltoToasts.
Don't
- Don't lower contrast below 4.5:1 when changing tokens, or remove the focus outline.
- Don't add app-specific components here; keep them in your app or kit.
# @core/ui — rules for AI agents
## Purpose
Small accessible component set for React built on native elements (no UI library): `Button`, `TextField`,
`TextareaField`, `SelectField`, `Checkbox`, `Field` (label + help + error wiring), `DataTable` (with `aria-sort`),
`Pagination`, `Tabs` (WAI-ARIA, arrow keys), `Dialog` (native `<dialog>`), `Alert`, `Badge`, `Card`, `Toasts`,
`Spinner`, `Skeleton`. Styling lives in `ui.css` as CSS variables (light/dark, WCAG AA contrast) and `ui-*` classes.
Used by @core/admin, @core/blocks and the kits.
## Map
- `index.ts` — all components and `cx()`.
- `components.ts` — implementation. `ui.css` — tokens and styles.
## Integration
1. Import the stylesheet once in the root layout: `import '@/lib/ui/ui.css'` and add `className="ui-root"` to `<body>`.
2. Use components: `<TextField label="Email" type="email" required error={errors.email} />`, `<Button variant="primary" loading={saving}>Save</Button>`.
3. Theme: change `--ui-*` variables in your CSS; force a theme with `<html data-theme="dark">`.
4. Verify: tab through a form; every control has a visible focus ring and a label.
## Conventions
- Every field gets a visible label (use `hideLabel` only when context makes it obvious); errors go in `error`, not in placeholders.
- Interactive elements are real `<button>`/`<a>`/inputs; don't add click handlers to `<div>`.
- Pass translated `labels` to `Pagination` and `dismissLabel` to `Toasts`.
## Don't
- Don't lower contrast below 4.5:1 when changing tokens, or remove the focus outline.
- Don't add app-specific components here; keep them in your app or kit.
.genpmignore 適用後に組み込まれる正確なツリーです。固定先:
/* @core/ui — tokens y estilos base. Cambia el tema editando las variables; no hace falta tocar los componentes. */
:root {
--ui-font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--ui-radius: 8px;
--ui-space: 0.5rem;
--ui-bg: #ffffff;
--ui-surface: #f7f7f8;
--ui-text: #18181b;
--ui-muted: #52525b;
--ui-border: #d4d4d8;
--ui-primary: #1d4ed8;
--ui-primary-text: #ffffff;
--ui-danger: #b91c1c;
--ui-success: #15803d;
--ui-warning: #a16207;
--ui-focus: #2563eb;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--ui-bg: #0b0b0e;
--ui-surface: #17171c;
--ui-text: #f4f4f5;
--ui-muted: #a1a1aa;
--ui-border: #3f3f46;
--ui-primary: #60a5fa;
--ui-primary-text: #0b0b0e;
--ui-danger: #f87171;
--ui-success: #4ade80;
--ui-warning: #facc15;
--ui-focus: #93c5fd;
}
}
:root[data-theme="dark"] {
--ui-bg: #0b0b0e;
--ui-surface: #17171c;
--ui-text: #f4f4f5;
--ui-muted: #a1a1aa;
--ui-border: #3f3f46;
--ui-primary: #60a5fa;
--ui-primary-text: #0b0b0e;
--ui-danger: #f87171;
--ui-success: #4ade80;
--ui-warning: #facc15;
--ui-focus: #93c5fd;
}
.ui-root { font-family: var(--ui-font); color: var(--ui-text); background: var(--ui-bg); line-height: 1.5; }
.ui-root :focus-visible { outline: 2px solid var(--ui-focus); outline-offset: 2px; }
.ui-visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.ui-button { display: inline-flex; align-items: center; gap: var(--ui-space); padding: 0.5rem 1rem; border-radius: var(--ui-radius); border: 1px solid var(--ui-border); background: var(--ui-bg); color: var(--ui-text); font: inherit; cursor: pointer; min-height: 2.5rem; }
.ui-button--primary { background: var(--ui-primary); border-color: var(--ui-primary); color: var(--ui-primary-text); }
.ui-button--danger { border-color: var(--ui-danger); color: var(--ui-danger); }
.ui-button--ghost { border-color: transparent; background: transparent; }
.ui-button--sm { padding: 0.25rem 0.625rem; min-height: 2rem; }
.ui-button[disabled], .ui-button[aria-busy="true"] { opacity: 0.6; cursor: not-allowed; }
.ui-input, .ui-select, .ui-textarea { width: 100%; padding: 0.5rem 0.75rem; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); background: var(--ui-bg); color: var(--ui-text); font: inherit; min-height: 2.5rem; }
.ui-input[aria-invalid="true"], .ui-select[aria-invalid="true"], .ui-textarea[aria-invalid="true"] { border-color: var(--ui-danger); }
.ui-field { display: grid; gap: 0.25rem; margin-block-end: 1rem; }
.ui-field__label { font-weight: 600; }
.ui-field__help { color: var(--ui-muted); font-size: 0.875rem; }
.ui-field__error { color: var(--ui-danger); font-size: 0.875rem; }
.ui-checkbox { display: inline-flex; gap: var(--ui-space); align-items: center; }
.ui-card { border: 1px solid var(--ui-border); border-radius: var(--ui-radius); background: var(--ui-surface); padding: 1rem; }
.ui-badge { display: inline-block; padding: 0 0.5rem; border-radius: 999px; font-size: 0.75rem; border: 1px solid var(--ui-border); }
.ui-badge--success { color: var(--ui-success); border-color: var(--ui-success); }
.ui-badge--warning { color: var(--ui-warning); border-color: var(--ui-warning); }
.ui-badge--danger { color: var(--ui-danger); border-color: var(--ui-danger); }
.ui-alert { border: 1px solid var(--ui-border); border-inline-start-width: 4px; border-radius: var(--ui-radius); padding: 0.75rem 1rem; }
.ui-alert--error { border-color: var(--ui-danger); }
.ui-alert--success { border-color: var(--ui-success); }
.ui-alert--warning { border-color: var(--ui-warning); }
.ui-table { width: 100%; border-collapse: collapse; }
.ui-table th, .ui-table td { text-align: start; padding: 0.5rem; border-block-end: 1px solid var(--ui-border); }
.ui-dialog { border: 1px solid var(--ui-border); border-radius: var(--ui-radius); padding: 1.5rem; max-width: min(32rem, 90vw); background: var(--ui-bg); color: var(--ui-text); }
.ui-dialog::backdrop { background: rgb(0 0 0 / 0.5); }
.ui-tabs__list { display: flex; gap: 0.25rem; border-block-end: 1px solid var(--ui-border); }
.ui-tabs__tab { padding: 0.5rem 1rem; border: 0; background: none; color: var(--ui-muted); font: inherit; cursor: pointer; border-block-end: 2px solid transparent; }
.ui-tabs__tab[aria-selected="true"] { color: var(--ui-text); border-block-end-color: var(--ui-primary); }
.ui-pagination { display: flex; gap: 0.25rem; align-items: center; }
.ui-skeleton { background: var(--ui-surface); border-radius: var(--ui-radius); min-height: 1rem; }
.ui-spinner { width: 1rem; height: 1rem; border: 2px solid currentColor; border-inline-end-color: transparent; border-radius: 50%; animation: ui-spin 0.8s linear infinite; }
.ui-toasts { position: fixed; inset-block-end: 1rem; inset-inline-end: 1rem; display: grid; gap: 0.5rem; z-index: 50; }
@keyframes ui-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ui-spinner { animation-duration: 2.4s; } }
このパッケージは MCP サーバーを宣言していません。
| バージョン | コミット | 公開日 | スキャン |
|---|---|---|---|
| 1.0.1 | 9955ea1 | 5 時間前 | スキャン合格 |
- genpm
- なし
- 提案
- GenPM は npm コマンドを提案し、あなたが承認した場合にのみ実行します。
- スキャン
- スキャン合格 · 指摘 0 件
- コミット
- v1.0.1 → 9955ea1d72f43b5cecdc5f3d244507c8bc2e4bc9 · 取得後に検証済み
- スクリプト
- なし。GenPM はパッケージのコードを実行しません。
- ライセンス
- MIT
- 品質
- 100/100
- 認識されたライセンス達成
- AGENTS.md に目的の説明がある達成
- AGENTS.md に統合手順がある達成
- AGENTS.md に規約や禁止事項がある達成
- テストを含む達成
- セキュリティスキャンに合格達成
- 過去 6 か月以内に公開達成
- 認証済みの公開者達成
- 概要とキーワード達成
- 報告
- 問題を見つけましたか?