@teamblind-chorus/ui 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/agents/AGENTS.md +6 -6
- package/agents/DESIGN.md +245 -244
- package/agents/LOVABLE.md +40 -11
- package/agents/catalog.md +4 -4
- package/agents/components/avatar-rail/avatar-rail.md +2 -4
- package/agents/components/avatar-rail/avatar-rail.spec.json +10 -14
- package/agents/components/badge/role.md +7 -9
- package/agents/components/badge/role.spec.json +6 -6
- package/agents/components/badge/update.md +6 -8
- package/agents/components/badge/update.spec.json +5 -5
- package/agents/components/banner/banner.md +16 -18
- package/agents/components/banner/banner.spec.json +14 -14
- package/agents/components/bottom-sheet/bottom-sheet.md +4 -6
- package/agents/components/bottom-sheet/bottom-sheet.spec.json +5 -5
- package/agents/components/bubble/bubble.md +8 -10
- package/agents/components/bubble/bubble.spec.json +11 -11
- package/agents/components/button/button.md +1 -1
- package/agents/components/button/check.md +9 -11
- package/agents/components/button/check.spec.json +8 -10
- package/agents/components/button/fab.md +7 -9
- package/agents/components/button/fab.spec.json +10 -12
- package/agents/components/button/group.spec.json +4 -4
- package/agents/components/button/icon.md +21 -23
- package/agents/components/button/icon.spec.json +12 -14
- package/agents/components/button/standard.md +40 -42
- package/agents/components/button/standard.spec.json +20 -22
- package/agents/components/button/text.md +21 -23
- package/agents/components/button/text.spec.json +13 -15
- package/agents/components/button/toggle.md +7 -9
- package/agents/components/button/toggle.spec.json +10 -12
- package/agents/components/button/toolbar.md +24 -26
- package/agents/components/button/toolbar.spec.json +10 -12
- package/agents/components/carousel/carousel.md +1 -1
- package/agents/components/carousel/post.md +15 -21
- package/agents/components/carousel/post.spec.json +17 -17
- package/agents/components/carousel/profile.md +9 -45
- package/agents/components/carousel/profile.spec.json +17 -17
- package/agents/components/chip/chip.md +1 -1
- package/agents/components/chip/filter.md +22 -24
- package/agents/components/chip/filter.spec.json +17 -13
- package/agents/components/chip/tag.md +22 -24
- package/agents/components/chip/tag.spec.json +19 -15
- package/agents/components/dialog/dialog.md +1 -3
- package/agents/components/dialog/dialog.spec.json +3 -3
- package/agents/components/directory-list/directory-list.md +1 -3
- package/agents/components/directory-list/directory-list.spec.json +2 -2
- package/agents/components/divider/divider.family.json +1 -1
- package/agents/components/divider/divider.md +12 -14
- package/agents/components/divider/divider.spec.json +8 -8
- package/agents/components/empty-state/empty-state.md +9 -9
- package/agents/components/empty-state/empty-state.spec.json +14 -14
- package/agents/components/feed/ad.md +2 -4
- package/agents/components/feed/ad.spec.json +10 -10
- package/agents/components/feed/post.md +41 -43
- package/agents/components/feed/post.spec.json +35 -39
- package/agents/components/form-field/form-field.md +1 -1
- package/agents/components/form-field/input.md +32 -34
- package/agents/components/form-field/input.spec.json +34 -33
- package/agents/components/form-field/search.md +2 -4
- package/agents/components/form-field/search.spec.json +19 -18
- package/agents/components/form-field/select.md +18 -20
- package/agents/components/form-field/select.spec.json +30 -29
- package/agents/components/form-field/textarea.md +3 -5
- package/agents/components/form-field/textarea.spec.json +32 -31
- package/agents/components/header/main.md +4 -6
- package/agents/components/header/main.spec.json +3 -3
- package/agents/components/header/sub.md +6 -8
- package/agents/components/header/sub.spec.json +3 -3
- package/agents/components/list/accordion.md +34 -45
- package/agents/components/list/accordion.spec.json +20 -20
- package/agents/components/list/entry.md +59 -81
- package/agents/components/list/entry.spec.json +20 -23
- package/agents/components/list/list.md +2 -2
- package/agents/components/list/radio.md +13 -20
- package/agents/components/list/radio.spec.json +16 -20
- package/agents/components/list/standard.md +50 -72
- package/agents/components/list/standard.spec.json +18 -21
- package/agents/components/metadata/compact.md +4 -6
- package/agents/components/metadata/compact.spec.json +6 -6
- package/agents/components/metadata/metadata.md +1 -1
- package/agents/components/metadata/standard.md +12 -14
- package/agents/components/metadata/standard.spec.json +10 -10
- package/agents/components/nav-card/nav-card.md +25 -27
- package/agents/components/nav-card/nav-card.spec.json +19 -19
- package/agents/components/nav-list/nav-list.md +2 -8
- package/agents/components/nav-list/nav-list.spec.json +3 -3
- package/agents/components/navigation-bar/main.md +9 -11
- package/agents/components/navigation-bar/main.spec.json +6 -6
- package/agents/components/navigation-bar/search.md +6 -8
- package/agents/components/navigation-bar/search.spec.json +9 -9
- package/agents/components/navigation-bar/sub.md +9 -11
- package/agents/components/navigation-bar/sub.spec.json +7 -7
- package/agents/components/pagination/pagination.family.json +1 -1
- package/agents/components/pagination/pagination.md +3 -3
- package/agents/components/pagination/pagination.spec.json +5 -5
- package/agents/components/profile-header/profile-header.md +9 -11
- package/agents/components/profile-header/profile-header.spec.json +9 -9
- package/agents/components/progress/progress.family.json +1 -1
- package/agents/components/progress/progress.md +5 -5
- package/agents/components/progress/progress.spec.json +8 -8
- package/agents/components/side-sheet/side-sheet.md +11 -13
- package/agents/components/side-sheet/side-sheet.spec.json +3 -3
- package/agents/components/skeleton/skeleton.md +7 -9
- package/agents/components/skeleton/skeleton.spec.json +5 -5
- package/agents/components/spinner/spinner.family.json +1 -1
- package/agents/components/spinner/spinner.md +8 -10
- package/agents/components/spinner/spinner.spec.json +9 -9
- package/agents/components/status-tag/status-tag.md +7 -9
- package/agents/components/status-tag/status-tag.spec.json +5 -5
- package/agents/components/suggestion-list/suggestion-list.md +3 -7
- package/agents/components/suggestion-list/suggestion-list.spec.json +8 -12
- package/agents/components/switch/switch.md +12 -14
- package/agents/components/switch/switch.spec.json +17 -18
- package/agents/components/tab-bar/tab-bar.md +9 -11
- package/agents/components/tab-bar/tab-bar.spec.json +25 -27
- package/agents/components/tabs/rounded.md +6 -8
- package/agents/components/tabs/rounded.spec.json +17 -15
- package/agents/components/tabs/segmented.md +4 -6
- package/agents/components/tabs/segmented.spec.json +4 -8
- package/agents/components/tabs/underline.md +9 -11
- package/agents/components/tabs/underline.spec.json +14 -16
- package/agents/components/thumbnail/thumbnail.md +5 -7
- package/agents/components/thumbnail/thumbnail.spec.json +8 -8
- package/agents/components/toast/toast.md +5 -7
- package/agents/components/toast/toast.spec.json +3 -3
- package/agents/components/tooltip/tooltip.md +6 -8
- package/agents/components/tooltip/tooltip.spec.json +4 -4
- package/agents/tokens.usage.json +71 -226
- package/dist/index.cjs +212 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -16
- package/dist/index.d.ts +16 -16
- package/dist/index.js +212 -223
- package/dist/index.js.map +1 -1
- package/dist/styles.css +386 -387
- package/eslint/rules.js +7 -7
- package/package.json +2 -3
- package/agents/anti-patterns.md +0 -533
- package/agents/compose.md +0 -240
- package/agents/images.md +0 -66
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ Or read the resolved JSON in build tooling:
|
|
|
76
76
|
import lightTokens from '@teamblind-chorus/tokens/resolved.light.json' with { type: 'json' };
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
## Agent-friendly docs (
|
|
79
|
+
## Agent-friendly docs (Cursor, Claude Code, …)
|
|
80
80
|
|
|
81
81
|
The package self-contains the docs an LLM agent needs. After `npm install`, they live under `node_modules/@teamblind-chorus/ui/agents/`:
|
|
82
82
|
|
|
@@ -90,9 +90,9 @@ The package self-contains the docs an LLM agent needs. After `npm install`, they
|
|
|
90
90
|
|
|
91
91
|
Also shipped: `@teamblind-chorus/ui/placeholder.png` — copy once into your app's `public/` and reference as `src="/placeholder.png"`.
|
|
92
92
|
|
|
93
|
-
## Native sibling packages (
|
|
93
|
+
## Native sibling packages (pre-release)
|
|
94
94
|
|
|
95
|
-
The same tokens are generated into Swift and Kotlin sources
|
|
95
|
+
The same tokens are generated into Swift and Kotlin sources, and all 35 component families are ported to both SwiftUI and Compose. The native ports are still pre-release (no version tag yet — expect API movement):
|
|
96
96
|
|
|
97
97
|
- **iOS (SwiftUI):** [`@teamblind-chorus/tokens-ios`](https://github.com/teamblind/chorus/tree/main/packages/tokens-ios) (`ChorusTokens`) + [`@teamblind-chorus/ui-ios`](https://github.com/teamblind/chorus/tree/main/packages/ui-ios) (`ChorusUI`).
|
|
98
98
|
- **Android (Compose):** [`@teamblind-chorus/tokens-android`](https://github.com/teamblind/chorus/tree/main/packages/tokens-android) (`chorus-tokens`) + [`@teamblind-chorus/ui-android`](https://github.com/teamblind/chorus/tree/main/packages/ui-android) (`chorus-ui`).
|
package/agents/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
Entrypoint for AI agents, external renderers, and design tools (
|
|
3
|
+
Entrypoint for AI agents, external renderers, and design tools (v0, Cursor, Figma plugins, Claude Design) consuming Chorus to compose prototypes. Human-facing readme: [`README.md`](README.md). This file is the machine contract.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -9,10 +9,10 @@ Entrypoint for AI agents, external renderers, and design tools (Lovable, v0, Cur
|
|
|
9
9
|
Five directives. Apply in order; later directives never override earlier ones.
|
|
10
10
|
|
|
11
11
|
1. **Design-system-first (Source of Truth).** Chorus is the source of truth for every surface. Start from Chorus tokens, components, and patterns — not generic libraries, screenshot inference, or invented values. Begin every task by reading [`schema/manifest.json`](schema/manifest.json) + [`schema/catalog.md`](schema/catalog.md).
|
|
12
|
-
2. **Component flexibility — extrapolate, don't fork.** Read the intent and respect each component's anatomy invariants (slot grammar, sizing tokens, state contract), but flex composition (slot fill, layout placement, modifier props) to fit context. The contract is the token bindings and spec slot rules, not the example screenshot. The family's `visualReuse` flag in `<family>.family.json` says how far flexibility extends — `"open"` families (avatar-rail, badge, banner, bubble, button, carousel, chip, directory-list, divider, feed, header, list, metadata, nav-card, nav-list, navigation-bar, page-shell, pagination, profile-header, progress, side-sheet, skeleton, status-tag, suggestion-list, switch, tab-bar, tabs, thumbnail) may be picked **on visual-fit grounds even when the brief's intent does not match `useCases` verbatim**; `"locked"` families (dialog, bottom-sheet, toast, tooltip, form-field — interaction-contract primitives) MUST only be used in their canonical role. Never wrap a Chorus component to restyle — re-compose with the slots it already gives you.
|
|
12
|
+
2. **Component flexibility — extrapolate, don't fork.** Read the intent and respect each component's anatomy invariants (slot grammar, sizing tokens, state contract), but flex composition (slot fill, layout placement, modifier props) to fit context. The contract is the token bindings and spec slot rules, not the example screenshot. The family's `visualReuse` flag in `<family>.family.json` says how far flexibility extends — `"open"` families (avatar-rail, badge, banner, bubble, button, carousel, chip, directory-list, divider, empty-state, feed, header, list, metadata, nav-card, nav-list, navigation-bar, page-shell, pagination, profile-header, progress, side-sheet, skeleton, spinner, status-tag, suggestion-list, switch, tab-bar, tabs, thumbnail) may be picked **on visual-fit grounds even when the brief's intent does not match `useCases` verbatim**; `"locked"` families (dialog, bottom-sheet, toast, tooltip, form-field — interaction-contract primitives) MUST only be used in their canonical role. Never wrap a Chorus component to restyle — re-compose with the slots it already gives you.
|
|
13
13
|
3. **New surfaces stay token-true.** When Chorus has no component for what the surface needs, design a new screen or primitive. Every color, spacing, typography, radius, and border-width MUST resolve through Chorus tokens and the foundations in [`schema/DESIGN.md`](schema/DESIGN.md). No raw hex, no off-scale px, no third-party type ramp — regardless of novelty.
|
|
14
14
|
4. **Lego-block composition.** Combine and extend existing components Lego-style — nest, group, sequence, re-purpose. Tokens stay non-negotiable; components are the flexible part. A novel screen should still read as one harmony with the system.
|
|
15
|
-
5. **UX-pattern consistency.** Pick components by expected interaction when interaction is the point — Dialog for modal commits, BottomSheet for committed-sheet flows, Toast for non-blocking feedback, Tooltip for trigger-anchored hints, FormField for real text entry. These five (`visualReuse: "locked"`) MUST NOT be borrowed for shape alone — focus trap, auto-dismiss, ARIA live region, hover/focus trigger, `<input>` semantics are the contract. The other
|
|
15
|
+
5. **UX-pattern consistency.** Pick components by expected interaction when interaction is the point — Dialog for modal commits, BottomSheet for committed-sheet flows, Toast for non-blocking feedback, Tooltip for trigger-anchored hints, FormField for real text entry. These five (`visualReuse: "locked"`) MUST NOT be borrowed for shape alone — focus trap, auto-dismiss, ARIA live region, hover/focus trigger, `<input>` semantics are the contract. The other thirty (`"open"`) carry interaction defaults too — List for menus/pickers, Feed for authored content, Chip vs Button for facet vs commit — but defaults are *suggestions*, not rules; pick by visual fit when the design calls for it. Across a flow, keep behavior/motion/affordance predictable regardless of tier.
|
|
16
16
|
|
|
17
17
|
The "Hard rules" below are the machine-checkable carve-outs — principles tell you *how to think*; hard rules tell you *what not to ship*.
|
|
18
18
|
|
|
@@ -20,7 +20,7 @@ The "Hard rules" below are the machine-checkable carve-outs — principles tell
|
|
|
20
20
|
|
|
21
21
|
## MCP server (preferred access)
|
|
22
22
|
|
|
23
|
-
MCP server at [`apps/mcp-server`](apps/mcp-server) exposes the schema to any MCP client (Claude Desktop, Cursor, Claude Code
|
|
23
|
+
MCP server at [`apps/mcp-server`](apps/mcp-server) exposes the schema to any MCP client (Claude Desktop, Cursor, Claude Code). Tools enumerate families/specs and validate compositions; resources expose `AGENTS.md`, the manifest, the catalog, `DESIGN.md`, and resolved token bundles. Wiring: [`apps/mcp-server/README.md`](apps/mcp-server/README.md). Fall back to direct file reads in the order below if MCP is unavailable.
|
|
24
24
|
|
|
25
25
|
## Read order (do not skip)
|
|
26
26
|
|
|
@@ -45,7 +45,7 @@ Not expressible in JSON Schemas. Agents MUST encode as guardrails.
|
|
|
45
45
|
6. **One geometry across a navigation flow.** Bar/row/chrome heights are stable across screens (e.g. all three `navigation-bar` subs share `56px` min-height, `8/8` padding).
|
|
46
46
|
7. **Preview/demo strings are English.** Even when source screenshots are Korean.
|
|
47
47
|
8. **Link-affordance Text Buttons use `accent`.** Section-header `See all`, card-header `Follow`, inline `View details` — any Text Button reading as a link picks `appearance="accent"` so navigational intent carries chromatic emphasis. `default` is reserved for inline commits that should recede into body copy. Full rule: [text.spec.json:appearances.accent.linkAffordanceRecommendation](schema/components/button/text.spec.json).
|
|
48
|
-
9. **Image areas are image-typed and context-swappable — one universal placeholder.** Any spec field marked `"assetType": "image"` (`Thumbnail.src`/`Thumbnail.image`, `FeedAd.media.src`/`FeedAd.media`, `ProfileCarousel.items[].cover.src`, every future image-typed slot) is a typed asset slot. Fill with `/placeholder.png` — the **single universal Chorus image-area placeholder** — when scaffolding; the same asset wires as the **runtime CSS fallback** (`background-image` on the image-area layer) so a failed `<img>` still resolves to the placeholder rather than an empty surface tone. **The path `/placeholder.png` itself is the canonical contract**; consuming hosts MUST serve the bundled asset (`node_modules/@teamblind-chorus/ui/placeholder.png` — copied to the host's public root, renamed verbatim, never to `placeholder.png` truncated of context, never to `placeholder_thumbnail.png`, never to a renamed variant). The dataURL inlined as `--chorus-placeholder-image` in [`packages/ui/src/styles.css`](packages/ui/src/styles.css) is a runtime CSS-only safety net for `<img>` load failures — external renderers that don't load `styles.css` (
|
|
48
|
+
9. **Image areas are image-typed and context-swappable — one universal placeholder.** Any spec field marked `"assetType": "image"` (`Thumbnail.src`/`Thumbnail.image`, `FeedAd.media.src`/`FeedAd.media`, `ProfileCarousel.items[].cover.src`, every future image-typed slot) is a typed asset slot. Fill with `/placeholder.png` — the **single universal Chorus image-area placeholder** — when scaffolding; the same asset wires as the **runtime CSS fallback** (`background-image` on the image-area layer) so a failed `<img>` still resolves to the placeholder rather than an empty surface tone. **The path `/placeholder.png` itself is the canonical contract**; consuming hosts MUST serve the bundled asset (`node_modules/@teamblind-chorus/ui/placeholder.png` — copied to the host's public root, renamed verbatim, never to `placeholder.png` truncated of context, never to `placeholder_thumbnail.png`, never to a renamed variant). The dataURL inlined as `--chorus-placeholder-image` in [`packages/ui/src/styles.css`](packages/ui/src/styles.css) is a runtime CSS-only safety net for `<img>` load failures — external renderers that don't load `styles.css` (Figma plugins, headless screen-shotters) still resolve the slot via the served path, so omitting the public asset breaks the contract even when the dataURL is present. The placeholder paints the lowercase Blind wordmark on a calm neutral surface, `object-fit: cover` -ed to the slot's intrinsic footprint — aspect ratio preserved, cropped to fill — never reshaping the slot. When the composition gives a clear subject (named channel, known author, brand, topic), swap the placeholder for a context-appropriate image — only the `src` URL changes, never the slot's footprint or chrome. **When no context-appropriate image can be inferred, fall back to `/placeholder.png`** rather than a glyph-in-tinted-circle, inline SVG wordmark, empty `src`, or invented stock URL. Glyph-bearing slots (e.g. `Banner.icon`) are a different contract.
|
|
49
49
|
10. **Icons render as SVG glyph components, never text characters.** Any icon affordance — leading / trailing on a Button, the icon slot on Banner / Status tag / Navigation bar / Header / List row, an inline glyph beside a label — MUST be a Chorus icon component imported from `@teamblind-chorus/ui/icons` (`PlusIcon`, `XIcon`, `CheckIcon`, `ChevronRightIcon`, the entity-family icons, …). Do NOT type ASCII / Unicode characters in label strings or `aria-label`s to stand in for an icon (`'+ Create'`, `'× Close'`, `'→ Continue'`, `'★ Favorite'`, `'⌃'`, `'⌄'`, `'•'`, `'·'`). Text characters bypass the family-wide `currentColor` re-tone ([button.family.json:iconColorNote](schema/components/button/button.family.json)), the per-rung sizing (`icon.md` 16 / `icon.lg` 20 / `icon.xl` 24), the `aria-hidden` decorative contract, and the keyword-driven swap-by-intent map at [`schema/icons/icons.json`](schema/icons/icons.json) — so they read as visible glyphs to screen readers, paint in the wrong colour under hover / disabled / destructive flavors, and drift off the icon rung. Header's `headerAction` accepts `leadingIcon` / `trailingIcon` node slots for exactly this case; reach for them instead of prefixing the label with `+`. The single carve-out is prose that mentions a glyph as a *concept* (fab.md: "universally legible actions (`+`, pencil)") — the rendered FAB itself still fills its `icon` slot with `<PlusIcon>`, never a `+` character.
|
|
50
50
|
11. **Readability is non-negotiable — pair contrast, don't compose it.** Foreground colour for every text run, icon glyph, and graphic boundary MUST resolve to the host surface's pre-paired `on*` token. The pairings ship in `sys.color`: `surface*` ↔ `onSurface` / `onSurfaceVariant`; `primary` ↔ `onPrimary`; `primaryContainer` ↔ `onPrimaryContainer`; same shape for `secondary` / `brand` / `success` / `error` and their `*Container` siblings; `inverseSurface` ↔ `inverseOnSurface`; the dedicated `sys.color.icon.*` palette is tuned for **neutral `surface*` hosts only**. NEVER cross-pair (`onPrimary` on `surface`, `onSurface` on `primary`, a `sys.color.icon.*` paint on a `primary` / `error` / `brand` / `*Container` fill, dark text in an `inverseSurface` chip). When a new surface needs a tint with no pre-paired foreground, the agent MUST (a) compute the WCAG contrast ratio against the actual fill in BOTH light and dark mode; (b) refuse to ship anything below **4.5 : 1 for normal text, 3 : 1 for ≥18pt or Semibold ≥14pt text, 3 : 1 for non-text glyphs and graphic boundaries**; (c) if the chosen pair fails, fall back to the nearest `sys.color` quartet rather than searching for a darker shade. The most common failures the agent MUST refuse: (i) `onSurface` (`neutral.900` light / `neutral.50` dark) text composed onto a non-`surface*` fill — produces near-invisible "black on dark-blue" / "white on light-yellow" results; (ii) `sys.color.icon.muted` (translucent 20 % black / 24 % white) on a colour-tinted host — the alpha mixes against the tint, not the surface, and usually collapses below 3 : 1; (iii) inventing a new fill colour for a hero / banner without re-checking that the existing `onSurface` text still clears AA against the new fill in both themes. When you cannot guarantee AA, **the right answer is to pick a different host fill from the existing surface ladder**, not to hand-tune the foreground.
|
|
51
51
|
|
|
@@ -79,7 +79,7 @@ Not expressible in JSON Schemas. Agents MUST encode as guardrails.
|
|
|
79
79
|
`@teamblind-chorus/ui` is workspace-only and source-distributed. External tools pick ONE:
|
|
80
80
|
|
|
81
81
|
- **(a) Compile JSX directly.** Import from `packages/ui/src/index.js`. Load `packages/ui/src/styles.css` once. JSX emits inline `--<component>-*` plumbing vars; static rules in `styles.css` consume them.
|
|
82
|
-
- **(b) Re-render from the spec.** Read `schema/components/<family>/<sub>.spec.json` and emit equivalent. Path for Figma plugins,
|
|
82
|
+
- **(b) Re-render from the spec.** Read `schema/components/<family>/<sub>.spec.json` and emit equivalent. Path for Figma plugins, spec-driven synth, non-React runtimes. MUST encode all seven hard rules.
|
|
83
83
|
|
|
84
84
|
Prefer (a) — carries no-layout-stroke and focus-ring rules for free.
|
|
85
85
|
|