@teamblind-chorus/ui 1.1.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 +10 -8
- package/agents/components/avatar-rail/avatar-rail.md +2 -4
- package/agents/components/avatar-rail/avatar-rail.spec.json +27 -12
- 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.family.json +3 -1
- package/agents/components/banner/banner.md +66 -15
- package/agents/components/banner/banner.spec.json +37 -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 +25 -8
- package/agents/components/button/fab.md +7 -9
- package/agents/components/button/fab.spec.json +27 -10
- package/agents/components/button/group.spec.json +4 -4
- package/agents/components/button/icon.md +21 -23
- package/agents/components/button/icon.spec.json +29 -12
- package/agents/components/button/standard.md +40 -42
- package/agents/components/button/standard.spec.json +37 -20
- package/agents/components/button/text.md +21 -23
- package/agents/components/button/text.spec.json +30 -13
- package/agents/components/button/toggle.md +7 -9
- package/agents/components/button/toggle.spec.json +27 -10
- 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 +34 -11
- package/agents/components/chip/tag.md +22 -24
- package/agents/components/chip/tag.spec.json +36 -13
- 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.family.json +28 -0
- package/agents/components/empty-state/empty-state.md +69 -0
- package/agents/components/empty-state/empty-state.spec.json +87 -0
- 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 +39 -31
- package/agents/components/form-field/search.md +2 -4
- package/agents/components/form-field/search.spec.json +24 -16
- package/agents/components/form-field/select.md +18 -20
- package/agents/components/form-field/select.spec.json +36 -27
- package/agents/components/form-field/textarea.md +3 -5
- package/agents/components/form-field/textarea.spec.json +37 -29
- 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 +26 -17
- package/agents/components/list/entry.md +59 -81
- package/agents/components/list/entry.spec.json +37 -21
- package/agents/components/list/list.md +2 -2
- package/agents/components/list/radio.md +13 -20
- package/agents/components/list/radio.spec.json +33 -18
- package/agents/components/list/standard.md +88 -64
- package/agents/components/list/standard.spec.json +52 -20
- 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 +25 -16
- 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/page-shell/page-shell.family.json +1 -1
- package/agents/components/page-shell/page-shell.md +33 -0
- package/agents/components/page-shell/page-shell.spec.json +85 -0
- 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 +27 -0
- package/agents/components/spinner/spinner.md +96 -0
- package/agents/components/spinner/spinner.spec.json +82 -0
- 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 +23 -15
- package/agents/components/tab-bar/tab-bar.md +9 -11
- package/agents/components/tab-bar/tab-bar.spec.json +37 -23
- package/agents/components/tabs/rounded.md +6 -8
- package/agents/components/tabs/rounded.spec.json +34 -13
- 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 +31 -14
- 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/manifest.json +8 -6
- package/agents/tokens.usage.json +71 -226
- package/agents/usage.json +12 -0
- package/dist/index.cjs +531 -262
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -13
- package/dist/index.d.ts +57 -13
- package/dist/index.js +530 -263
- package/dist/index.js.map +1 -1
- package/dist/styles.css +560 -379
- 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
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
},
|
|
27
27
|
"card": {
|
|
28
28
|
"required": true,
|
|
29
|
-
"description": "One compact post card per page. `flex: 0 0 calc(100% - sys.layout.inline.md - ref.space.500)` so a 40px peek of the next card always surfaces at the trailing edge. `scroll-snap-align: start`. Inner padding `sys.layout.container.md`, `sys.color.surface` fill, `sys.radius.md` corner, `sys.borderWidth.hairline` outline in `sys.color.
|
|
29
|
+
"description": "One compact post card per page. `flex: 0 0 calc(100% - sys.layout.inline.md - ref.space.500)` so a 40px peek of the next card always surfaces at the trailing edge. `scroll-snap-align: start`. Inner padding `sys.layout.container.md`, `sys.color.surface.default` fill, `sys.radius.md` corner, `sys.borderWidth.hairline` outline in `sys.color.border.default`.",
|
|
30
30
|
"intrinsic": true
|
|
31
31
|
},
|
|
32
32
|
"header": {
|
|
33
33
|
"required": true,
|
|
34
|
-
"description": "Top row of the card: avatar (Thumbnail size 40) + channel name + optional VerifiedIcon (size sys.icon.md, sys.color.primary) + trailing follow affordance. Rendered by the **shared `EntryRow` atom** — the same component [List/entry](../list/entry.md) rows render — wrapped in a carousel-specific `chorus-post-carousel__card-header`. See `behavior.headerReusesEntryCombo`.",
|
|
34
|
+
"description": "Top row of the card: avatar (Thumbnail size 40) + channel name + optional VerifiedIcon (size sys.icon.md, sys.color.background.primary) + trailing follow affordance. Rendered by the **shared `EntryRow` atom** — the same component [List/entry](../list/entry.md) rows render — wrapped in a carousel-specific `chorus-post-carousel__card-header`. See `behavior.headerReusesEntryCombo`.",
|
|
35
35
|
"intrinsic": true
|
|
36
36
|
},
|
|
37
37
|
"avatar": {
|
|
@@ -44,16 +44,16 @@
|
|
|
44
44
|
},
|
|
45
45
|
"verified": {
|
|
46
46
|
"required": false,
|
|
47
|
-
"description": "Inline `VerifiedFillIcon` at `sys.icon.md`, painted in `sys.color.primary` (resolves to `ref.palette.blue.500`). Sits to the **LEFT** of the channel name so the reader's eye lands on the trust signal first, then the name. Decorative — pair with a textual affordance elsewhere if the verified status itself is meaningful.",
|
|
47
|
+
"description": "Inline `VerifiedFillIcon` at `sys.icon.md`, painted in `sys.color.background.primary` (resolves to `ref.palette.blue.500`). Sits to the **LEFT** of the channel name so the reader's eye lands on the trust signal first, then the name. Decorative — pair with a textual affordance elsewhere if the verified status itself is meaningful.",
|
|
48
48
|
"accepts": [
|
|
49
49
|
"icon"
|
|
50
50
|
],
|
|
51
51
|
"defaultIcon": "VerifiedFillIcon",
|
|
52
|
-
"defaultIconColor": "sys.color.
|
|
52
|
+
"defaultIconColor": "sys.color.icon.accent.blue.default"
|
|
53
53
|
},
|
|
54
54
|
"channel": {
|
|
55
55
|
"required": true,
|
|
56
|
-
"description": "Channel / author name. `sys.typo.label.md` / Semibold / `sys.color.
|
|
56
|
+
"description": "Channel / author name. `sys.typo.label.md` / Semibold / `sys.color.text.default`. Single line; truncates. Sits to the right of the optional `verified` mark inside the channel-row sub-container.",
|
|
57
57
|
"accepts": [
|
|
58
58
|
"text"
|
|
59
59
|
]
|
|
@@ -68,28 +68,28 @@
|
|
|
68
68
|
},
|
|
69
69
|
"title": {
|
|
70
70
|
"required": true,
|
|
71
|
-
"description": "Post title. `sys.typo.label.md` / Semibold / `sys.color.
|
|
71
|
+
"description": "Post title. `sys.typo.label.md` / Semibold / `sys.color.text.default`. One line; truncates with ellipsis.",
|
|
72
72
|
"accepts": [
|
|
73
73
|
"text"
|
|
74
74
|
]
|
|
75
75
|
},
|
|
76
76
|
"body": {
|
|
77
77
|
"required": true,
|
|
78
|
-
"description": "Post excerpt. `sys.typo.body.sm` / Regular / `sys.color.
|
|
78
|
+
"description": "Post excerpt. `sys.typo.body.sm` / Regular / `sys.color.text.subtle`. Three-line clamp with trailing ellipsis.",
|
|
79
79
|
"accepts": [
|
|
80
80
|
"text"
|
|
81
81
|
]
|
|
82
82
|
},
|
|
83
83
|
"mention": {
|
|
84
84
|
"required": false,
|
|
85
|
-
"description": "Tap-anywhere mention / tag line below the body. `sys.typo.body.sm` / `sys.color.primary` (no italic — the carousel card reads tags as part of its body block, unlike the Feed · Post card which italicises a single mention).",
|
|
85
|
+
"description": "Tap-anywhere mention / tag line below the body. `sys.typo.body.sm` / `sys.color.background.primary` (no italic — the carousel card reads tags as part of its body block, unlike the Feed · Post card which italicises a single mention).",
|
|
86
86
|
"accepts": [
|
|
87
87
|
"text"
|
|
88
88
|
]
|
|
89
89
|
},
|
|
90
90
|
"footer": {
|
|
91
91
|
"required": true,
|
|
92
|
-
"description": "Bottom row: leading `more` affordance + trailing view count. The 'See more' label renders as a [Text Button](../button/text.md) (`size={'xsmall'}`, `appearance={'secondary'}`) — same family as the card-header follow action — so both card affordances share one state contract. The view count renders as a non-interactive `<span>` matching the same `xsmall` rhythm (`EyeIcon` at `sys.icon.md` + `sys.typo.label.sm` / `sys.color.
|
|
92
|
+
"description": "Bottom row: leading `more` affordance + trailing view count. The 'See more' label renders as a [Text Button](../button/text.md) (`size={'xsmall'}`, `appearance={'secondary'}`) — same family as the card-header follow action — so both card affordances share one state contract. The view count renders as a non-interactive `<span>` matching the same `xsmall` rhythm (`EyeIcon` at `sys.icon.md` + `sys.typo.label.sm` / `sys.color.text.subtle`).",
|
|
93
93
|
"intrinsic": true
|
|
94
94
|
},
|
|
95
95
|
"pagination": {
|
|
@@ -106,8 +106,8 @@
|
|
|
106
106
|
"pagePeek": "ref.space.500",
|
|
107
107
|
"pagePeekNote": "Guaranteed minimum visibility of the next card at the trailing edge. Pinned to `ref.space.500` (40px) — a raw ref step rather than a responsive sys-layout rung — because the carousel wants a fixed-pixel visibility floor independent of the responsive sys-layout shift. The card's flex-basis is `calc(100% - sys.layout.inline.md - ref.space.500)`, so the inter-card gap plus the peek subtract from the pager's inline space in lock-step.",
|
|
108
108
|
"pageSnapAnchor": "Cards stick to the leading edge of the pager (the pager's own `padding-left: sys.layout.container.md`, the 16 rail). `scroll-snap-align: start` on each card plus the pager's `scroll-padding-left: sys.layout.container.md` together guarantee that, after every swipe, the snapped card aligns flush with the 16 rail — and the trailing edge holds the 40px peek of the next card.",
|
|
109
|
-
"cardFill": "sys.color.surface",
|
|
110
|
-
"cardOutline": "sys.borderWidth.hairline sys.color.
|
|
109
|
+
"cardFill": "sys.color.surface.default",
|
|
110
|
+
"cardOutline": "sys.borderWidth.hairline sys.color.border.default",
|
|
111
111
|
"cardRadius": "sys.radius.md",
|
|
112
112
|
"cardPadding": "sys.layout.container.md",
|
|
113
113
|
"cardStackGap": "sys.layout.stack.sm",
|
|
@@ -115,23 +115,23 @@
|
|
|
115
115
|
"cardAvatarSize": 40,
|
|
116
116
|
"cardAvatarRendersAs": "Thumbnail at size 40 — the carousel does not paint its own circular crop or fallback; both come from the Thumbnail family.",
|
|
117
117
|
"cardChannelTypo": "sys.typo.label.md",
|
|
118
|
-
"cardChannelColor": "sys.color.
|
|
118
|
+
"cardChannelColor": "sys.color.text.default",
|
|
119
119
|
"cardVerifiedIcon": "VerifiedFillIcon",
|
|
120
120
|
"cardVerifiedSize": "sys.icon.md",
|
|
121
|
-
"cardVerifiedColor": "sys.color.
|
|
121
|
+
"cardVerifiedColor": "sys.color.text.link",
|
|
122
122
|
"cardVerifiedColorResolved": "ref.palette.blue.500",
|
|
123
123
|
"cardVerifiedPosition": "Leading — sits to the LEFT of the channel name inside the channel-row sub-container.",
|
|
124
124
|
"cardFollowActionRendersAs": "Button variant='text' size='xsmall' appearance='accent' (inactive — link-affordance rule) → appearance='default' (active — followed state recedes). All state tokens delegate to the Text Button family.",
|
|
125
125
|
"cardMoreActionRendersAs": "Button variant='text' size='xsmall' appearance='secondary'. Same Text Button rung as the follow action so the card's two affordances share one state contract.",
|
|
126
126
|
"cardTitleTypo": "sys.typo.label.md",
|
|
127
|
-
"cardTitleColor": "sys.color.
|
|
127
|
+
"cardTitleColor": "sys.color.text.default",
|
|
128
128
|
"cardBodyTypo": "sys.typo.body.sm",
|
|
129
|
-
"cardBodyColor": "sys.color.
|
|
129
|
+
"cardBodyColor": "sys.color.text.subtle",
|
|
130
130
|
"cardBodyLineClamp": 3,
|
|
131
131
|
"cardMentionTypo": "sys.typo.body.sm",
|
|
132
|
-
"cardMentionColor": "sys.color.
|
|
132
|
+
"cardMentionColor": "sys.color.text.mention",
|
|
133
133
|
"cardFooterTypo": "sys.typo.label.sm",
|
|
134
|
-
"cardFooterColor": "sys.color.
|
|
134
|
+
"cardFooterColor": "sys.color.text.subtle",
|
|
135
135
|
"cardFooterIcon": "EyeIcon",
|
|
136
136
|
"cardFooterIconSize": "sys.icon.md",
|
|
137
137
|
"paginationRendersAs": "Pagination component — dot size / gap / radius and active / inactive colors all delegate to the [Pagination](../pagination/pagination.md) spec.",
|
|
@@ -56,9 +56,7 @@ import { Carousel, ProfileCarousel } from '@teamblind-chorus/ui';
|
|
|
56
56
|
</Carousel>
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
##
|
|
60
|
-
|
|
61
|
-
### With header action
|
|
59
|
+
## Header action
|
|
62
60
|
|
|
63
61
|
Extend the header with a trailing `accent` Text Button when there's an index page to route to. Lifts the `headerAction` prop on the `<Carousel>` wrapper.
|
|
64
62
|
|
|
@@ -80,33 +78,12 @@ import { Carousel, ProfileCarousel } from '@teamblind-chorus/ui';
|
|
|
80
78
|
{ icon: 'heart', value: '81%' },
|
|
81
79
|
],
|
|
82
80
|
},
|
|
83
|
-
{
|
|
84
|
-
avatar: { src: '/placeholder.png', alt: 'Tesla' },
|
|
85
|
-
name: 'Tesla',
|
|
86
|
-
followers: '1.4K followers',
|
|
87
|
-
metrics: [
|
|
88
|
-
{ icon: 'star', value: '4.7' },
|
|
89
|
-
{ icon: 'pulse', value: '86' },
|
|
90
|
-
{ icon: 'heart', value: '85.3%' },
|
|
91
|
-
],
|
|
92
|
-
followed: true,
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
avatar: { src: '/placeholder.png', alt: 'Stripe' },
|
|
96
|
-
name: 'Stripe',
|
|
97
|
-
followers: '2.1K followers',
|
|
98
|
-
metrics: [
|
|
99
|
-
{ icon: 'star', value: '4.5' },
|
|
100
|
-
{ icon: 'pulse', value: '92.4' },
|
|
101
|
-
{ icon: 'heart', value: '88%' },
|
|
102
|
-
],
|
|
103
|
-
},
|
|
104
81
|
]}
|
|
105
82
|
/>
|
|
106
83
|
</Carousel>
|
|
107
84
|
```
|
|
108
85
|
|
|
109
|
-
|
|
86
|
+
## With description
|
|
110
87
|
|
|
111
88
|
The metrics row swaps out for a two-line description. Use for editorial collections where the value of each profile is best explained in copy (channel topic, hot pitch) rather than numeric signals. The description block is fixed to the same two-line height as the metrics row, so cards stay flush across both modes even when description copy clamps with an ellipsis.
|
|
112
89
|
|
|
@@ -124,19 +101,6 @@ import { Carousel, ProfileCarousel } from '@teamblind-chorus/ui';
|
|
|
124
101
|
followers: '12.4K followers',
|
|
125
102
|
description: 'Hands-on threads about systems, infra, and the work behind the launch.',
|
|
126
103
|
},
|
|
127
|
-
{
|
|
128
|
-
avatar: { src: '/placeholder.png', alt: 'Compensation' },
|
|
129
|
-
name: 'Compensation',
|
|
130
|
-
followers: '8.1K followers',
|
|
131
|
-
description: 'Salary checks, offer evaluations, and the quiet math of staying versus leaving — the channel that runs longer than any single conversation can.',
|
|
132
|
-
followed: true,
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
avatar: { src: '/placeholder.png', alt: 'Career' },
|
|
136
|
-
name: 'Career',
|
|
137
|
-
followers: '5.3K followers',
|
|
138
|
-
description: 'Promotion packets, scope debates, and the rewrites that actually cleared.',
|
|
139
|
-
},
|
|
140
104
|
]}
|
|
141
105
|
/>
|
|
142
106
|
</Carousel>
|
|
@@ -149,9 +113,9 @@ import { Carousel, ProfileCarousel } from '@teamblind-chorus/ui';
|
|
|
149
113
|
- **card** — one profile card per page; fixed at **176px** wide.
|
|
150
114
|
- **cover** — top band; 88px tall image-area slot. Renders an `<img>` defaulting to `/placeholder.png` (universal Chorus placeholder). `object-fit: cover` crops to fill the band; `sys.color.surfaceContainerHigh` underlies as the no-image fallback. Consumers override via `items[i].cover.src`.
|
|
151
115
|
- **avatar** — [Thumbnail](../thumbnail/thumbnail.md) `size={64}` with [`outlined={true}`](../thumbnail/thumbnail.md#with-surface-outline), centered and overlapping the cover band's bottom edge. The 2-token (`sys.borderWidth.thin`) `surface`-tone outset halo separating the circle from the cover image is owned by Thumbnail's outlined case — the carousel forwards the prop instead of painting a halo on its own wrapper.
|
|
152
|
-
- **name** — entity name; `sys.typo.label.md` / Semibold / `sys.color.
|
|
153
|
-
- **followers** — follower count; `sys.typo.label.sm` / `sys.color.
|
|
154
|
-
- **metrics** *(optional)* — row of `icon + value` chips: `star → StarFillIcon (sys.color.icon.yellow)`, `pulse → PulseFillIcon (sys.color.success)`, `heart → HeartFillIcon (sys.color.icon.red)`. Mutually exclusive with `description`.
|
|
116
|
+
- **name** — entity name; `sys.typo.label.md` / Semibold / `sys.color.text.default`; centered, single line truncate.
|
|
117
|
+
- **followers** — follower count; `sys.typo.label.sm` / `sys.color.text.subtle`; centered.
|
|
118
|
+
- **metrics** *(optional)* — row of `icon + value` chips: `star → StarFillIcon (sys.color.icon.accent.yellow.default)`, `pulse → PulseFillIcon (sys.color.text.success)`, `heart → HeartFillIcon (sys.color.icon.accent.red.default)`. Mutually exclusive with `description`.
|
|
155
119
|
- **description** *(optional)* — two-line clamped paragraph that replaces the metrics row when present. Block height fixed to two lines of `sys.typo.label.sm` regardless of copy length, so card height stays consistent across metrics-carrying and copy-carrying cards.
|
|
156
120
|
- **followAction** — full-width [Toggle Button](../button/text.md) (`variant={'toggle'}`); `Follow` (inactive) / `Following` (active).
|
|
157
121
|
- **pagination** — [Pagination](../pagination/pagination.md) component, one dot per card (`count` = card count, `activeIndex` from scroll position). Decorative — dot tokens and the `aria-hidden` contract live on its spec; the carousel centers the intrinsic-width row (`align-self: center`).
|
|
@@ -164,11 +128,11 @@ import { Carousel, ProfileCarousel } from '@teamblind-chorus/ui';
|
|
|
164
128
|
| card | Fixed `width: 176px`, `sys.color.surface` fill, `sys.radius.md`, inset hairline outline, `scroll-snap-align: start` |
|
|
165
129
|
| cover | 88px tall image-area slot. Default `src` = `/placeholder.png` (universal image placeholder), `object-fit: cover`, `sys.color.surfaceContainerHigh` underlay |
|
|
166
130
|
| avatar | [Thumbnail](../thumbnail/thumbnail.md) `size={64}` `outlined`, vertical center on cover's bottom edge. The 2-token `surface`-tone halo separating the circle from the cover image is painted by Thumbnail's `outlined` case (outset `box-shadow: 0 0 0 sys.borderWidth.thin sys.color.surface`) — wrapper has no halo of its own |
|
|
167
|
-
| name | `sys.typo.label.md`, `sys.color.
|
|
168
|
-
| followers | `sys.typo.label.sm`, `sys.color.
|
|
131
|
+
| name | `sys.typo.label.md`, `sys.color.text.default`, centered |
|
|
132
|
+
| followers | `sys.typo.label.sm`, `sys.color.text.subtle`, centered |
|
|
169
133
|
| metrics row | `sys.layout.inline.md` gap, centered. Fixed-height slot — `calc(sys.typo.label.sm.size * sys.typo.label.sm.line * 2)` so the row always reserves two lines of `label.sm` regardless of content. |
|
|
170
|
-
| metric chip | `sys.icon.md` glyph + `sys.typo.label.sm` value; star → `StarFillIcon` (`sys.color.icon.yellow`), pulse → `PulseFillIcon` (`sys.color.success`), heart → `HeartFillIcon` (`sys.color.icon.red`) |
|
|
171
|
-
| description | `sys.typo.label.sm` / `sys.color.
|
|
134
|
+
| metric chip | `sys.icon.md` glyph + `sys.typo.label.sm` value; star → `StarFillIcon` (`sys.color.icon.accent.yellow.default`), pulse → `PulseFillIcon` (`sys.color.text.success`), heart → `HeartFillIcon` (`sys.color.icon.accent.red.default`) |
|
|
135
|
+
| description | `sys.typo.label.sm` / `sys.color.text.subtle`, centered, two-line clamp with trailing ellipsis. Two-layer DOM — outer container owns the same fixed-height slot as `metrics row` (min/max-height = 2 label.sm lines); inner `<p>` owns the `-webkit-line-clamp: 2` truncation. Split sidesteps a Chrome quirk where `display: -webkit-box` and explicit `height` on one element break the third-line clip. |
|
|
172
136
|
| followAction | [Toggle Button](../button/text.md) (Chip-toggle anatomy), stretched to full card width |
|
|
173
137
|
| pagination dot | [Pagination](../pagination/pagination.md) component delegated verbatim — 6 × 6 dots, active/inactive colors, and row gap bind on its spec |
|
|
174
138
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"card": {
|
|
28
28
|
"required": true,
|
|
29
|
-
"description": "One profile card per page. **Width is fixed at 176px** — every card paints the same footprint regardless of how many entries the rail carries. Vertical stack: cover band → avatar (overlapping) → name → followers → metrics row → follow toggle. `sys.color.surface` fill, `sys.radius.md` corner, `sys.borderWidth.hairline sys.color.
|
|
29
|
+
"description": "One profile card per page. **Width is fixed at 176px** — every card paints the same footprint regardless of how many entries the rail carries. Vertical stack: cover band → avatar (overlapping) → name → followers → metrics row → follow toggle. `sys.color.surface.default` fill, `sys.radius.md` corner, `sys.borderWidth.hairline sys.color.border.default` inset outline. `scroll-snap-align: start`.",
|
|
30
30
|
"intrinsic": true
|
|
31
31
|
},
|
|
32
32
|
"cover": {
|
|
@@ -46,33 +46,33 @@
|
|
|
46
46
|
},
|
|
47
47
|
"name": {
|
|
48
48
|
"required": true,
|
|
49
|
-
"description": "Entity name (channel / profile / company). `sys.typo.label.md` / Semibold / `sys.color.
|
|
49
|
+
"description": "Entity name (channel / profile / company). `sys.typo.label.md` / Semibold / `sys.color.text.default`. Centered; single line, truncates with ellipsis.",
|
|
50
50
|
"accepts": [
|
|
51
51
|
"text"
|
|
52
52
|
]
|
|
53
53
|
},
|
|
54
54
|
"followers": {
|
|
55
55
|
"required": true,
|
|
56
|
-
"description": "Follower count line. `sys.typo.label.sm` / Semibold / `sys.color.
|
|
56
|
+
"description": "Follower count line. `sys.typo.label.sm` / Semibold / `sys.color.text.subtle`. Centered; single line.",
|
|
57
57
|
"accepts": [
|
|
58
58
|
"text"
|
|
59
59
|
]
|
|
60
60
|
},
|
|
61
61
|
"metrics": {
|
|
62
62
|
"required": false,
|
|
63
|
-
"description": "Row of metric chips below the name / followers stack. Each chip is `icon + value` painted in `sys.typo.label.sm` / `sys.color.
|
|
63
|
+
"description": "Row of metric chips below the name / followers stack. Each chip is `icon + value` painted in `sys.typo.label.sm` / `sys.color.text.default`. Three default kinds: { icon: 'star', … } → `StarFillIcon` in `sys.color.icon.accent.yellow.default`; { icon: 'pulse', … } → `PulseFillIcon` in `sys.color.text.success`; { icon: 'heart', … } → `HeartFillIcon` in `sys.color.icon.accent.red.default`. Consumers may pass custom { icon: <ReactNode>, value, color? } entries for other shapes. Mutually exclusive with `description` — when both are present `description` wins.",
|
|
64
64
|
"intrinsic": true
|
|
65
65
|
},
|
|
66
66
|
"description": {
|
|
67
67
|
"required": false,
|
|
68
|
-
"description": "Two-line clamped descriptive paragraph that replaces the metrics row when present. `sys.typo.label.sm` / `sys.color.
|
|
68
|
+
"description": "Two-line clamped descriptive paragraph that replaces the metrics row when present. `sys.typo.label.sm` / `sys.color.text.subtle`, centered. The slot reserves a fixed height of two `label.sm` lines so card height stays consistent across cards that carry metrics and cards that carry copy — extra content clamps with a trailing ellipsis.",
|
|
69
69
|
"accepts": [
|
|
70
70
|
"text"
|
|
71
71
|
]
|
|
72
72
|
},
|
|
73
73
|
"followAction": {
|
|
74
74
|
"required": true,
|
|
75
|
-
"description": "Trailing full-width [Toggle Button](../button/text.md) at the foot of the card. `Follow` (inactive) → `Following` (active). The carousel does not paint its own follow chrome — every state binding lives on the Toggle Button (Chip-toggle) contract, which paints `sys.color.primary` while inactive and a `transparent` fill with a hairline outline while active so the followed state recedes against the card's own `surface` tier without re-painting a tone that would clash.",
|
|
75
|
+
"description": "Trailing full-width [Toggle Button](../button/text.md) at the foot of the card. `Follow` (inactive) → `Following` (active). The carousel does not paint its own follow chrome — every state binding lives on the Toggle Button (Chip-toggle) contract, which paints `sys.color.background.primary` while inactive and a `transparent` fill with a hairline outline while active so the followed state recedes against the card's own `surface` tier without re-painting a tone that would clash.",
|
|
76
76
|
"accepts": [
|
|
77
77
|
"button"
|
|
78
78
|
],
|
|
@@ -90,8 +90,8 @@
|
|
|
90
90
|
"pagePeek": "ref.space.500",
|
|
91
91
|
"pagePeekNote": "Guaranteed minimum visibility of the next card at the trailing edge — pinned to 40px (ref.space.500). Identical contract to PostCarousel.",
|
|
92
92
|
"pageSnapAnchor": "Cards stick to the leading edge of the pager (the pager's own `padding-left`, the 16 rail). `scroll-snap-align: start` plus the pager's `scroll-padding-left: sys.layout.container.md` produce this anchor.",
|
|
93
|
-
"cardFill": "sys.color.surface",
|
|
94
|
-
"cardOutline": "sys.borderWidth.hairline sys.color.
|
|
93
|
+
"cardFill": "sys.color.surface.default",
|
|
94
|
+
"cardOutline": "sys.borderWidth.hairline sys.color.border.default",
|
|
95
95
|
"cardOutlineComposition": "overlay",
|
|
96
96
|
"cardOutlineCompositionNote": "Painted on a dedicated `::after` overlay layer (`position: absolute; inset: 0; z-index: 2; pointer-events: none`), not as an inset `box-shadow` on the card box itself. The card hosts an opaque full-bleed cover band at the top; an inset shadow on the card would be masked by that fill at the top edge. Same overlay idiom DESIGN.md prescribes for the focus ring — so the stroke renders above every child regardless of edge-painting content.",
|
|
97
97
|
"cardRadius": "sys.radius.md",
|
|
@@ -99,25 +99,25 @@
|
|
|
99
99
|
"cardWidthNote": "Fixed pixel width — every profile card paints the same 176px footprint regardless of card count or screen width. The pager scrolls horizontally so the 176px footprint never reflows.",
|
|
100
100
|
"cardStackGap": "sys.layout.stack.sm",
|
|
101
101
|
"coverHeight": "88px",
|
|
102
|
-
"coverFill": "sys.color.
|
|
102
|
+
"coverFill": "sys.color.surface.default (background underlay — the placeholder image paints on top via `object-fit: cover`)",
|
|
103
103
|
"coverImageSource": "Same `/placeholder.png` asset every Chorus image-area slot falls back to. Cropped to fill the 88px band via `object-fit: cover` — the placeholder's centered 'blind' wordmark stays visually centered. Decorative — `aria-hidden`. Consumers can override per-item via `items[i].cover.src` (any image URL preserving the same `object-fit: cover` crop).",
|
|
104
104
|
"avatarSize": 64,
|
|
105
|
-
"avatarOverlap": "Avatar's vertical center sits on the cover band's bottom edge — the bottom half of the avatar bleeds onto the card surface. The 2-token (`sys.borderWidth.thin`) `sys.color.surface` halo separating the avatar from the cover band is owned by Thumbnail's `outlined={true}` case (see [Thumbnail § With surface outline](../thumbnail/thumbnail.md#with-surface-outline)) — outset `box-shadow`, not a wrapper border. Same contract as ProfileHeader's avatar.",
|
|
105
|
+
"avatarOverlap": "Avatar's vertical center sits on the cover band's bottom edge — the bottom half of the avatar bleeds onto the card surface. The 2-token (`sys.borderWidth.thin`) `sys.color.surface.default` halo separating the avatar from the cover band is owned by Thumbnail's `outlined={true}` case (see [Thumbnail § With surface outline](../thumbnail/thumbnail.md#with-surface-outline)) — outset `box-shadow`, not a wrapper border. Same contract as ProfileHeader's avatar.",
|
|
106
106
|
"nameTypo": "sys.typo.label.md",
|
|
107
|
-
"nameColor": "sys.color.
|
|
107
|
+
"nameColor": "sys.color.text.default",
|
|
108
108
|
"followersTypo": "sys.typo.label.sm",
|
|
109
|
-
"followersColor": "sys.color.
|
|
109
|
+
"followersColor": "sys.color.text.subtle",
|
|
110
110
|
"metricsRowGap": "sys.layout.inline.md",
|
|
111
111
|
"metricChipTypo": "sys.typo.label.sm",
|
|
112
|
-
"metricChipColor": "sys.color.
|
|
112
|
+
"metricChipColor": "sys.color.text.default",
|
|
113
113
|
"metricIconSize": "sys.icon.md",
|
|
114
|
-
"metricIconStar": "StarFillIcon — sys.color.icon.yellow",
|
|
115
|
-
"metricIconPulse": "PulseFillIcon — sys.color.success",
|
|
116
|
-
"metricIconHeart": "HeartFillIcon — sys.color.icon.red",
|
|
114
|
+
"metricIconStar": "StarFillIcon — sys.color.icon.accent.yellow.default",
|
|
115
|
+
"metricIconPulse": "PulseFillIcon — sys.color.text.success",
|
|
116
|
+
"metricIconHeart": "HeartFillIcon — sys.color.icon.accent.red.default",
|
|
117
117
|
"midSlotHeight": "calc(sys.typo.label.sm.size * sys.typo.label.sm.line * 2)",
|
|
118
118
|
"midSlotHeightNote": "Shared fixed height for the metrics row and the description slot — exactly two `label.sm` lines (12 × 1.5 × 2 ≈ 36px). Cards that carry metrics and cards that carry a description paint the same outer height.",
|
|
119
119
|
"descriptionTypo": "sys.typo.label.sm",
|
|
120
|
-
"descriptionColor": "sys.color.
|
|
120
|
+
"descriptionColor": "sys.color.text.subtle",
|
|
121
121
|
"descriptionLineClamp": 2,
|
|
122
122
|
"descriptionOverflow": "Two-line clamp with trailing ellipsis; copy exceeding two lines truncates so the slot height stays fixed.",
|
|
123
123
|
"followActionRendersAs": "Button variant='toggle' — Chip-toggle anatomy. Stretched to full card width via a wrapper rule. All state tokens delegate to the Toggle Button (Chip) family.",
|
|
@@ -8,5 +8,5 @@ A small, content-shaped control or label — chip-shaped affordance for two anch
|
|
|
8
8
|
|
|
9
9
|
## Sub-components
|
|
10
10
|
|
|
11
|
-
- **[Filter](./filter.md)** — Selectable filter chip. Capsule (`radius.full`), `surfaceContainerHigh` raised tone with a hairline `
|
|
11
|
+
- **[Filter](./filter.md)** — Selectable filter chip. Capsule (`radius.full`), `surfaceContainerHigh` raised tone with a hairline `border.default` stroke at rest, swaps to an inverse fill when selected. Optional leading and trailing icons.
|
|
12
12
|
- **[Tag](./tag.md)** — Informational tag chip. Square-cornered (`radius.sm`), `secondaryContainer` fill that sits one tonal step *below* the lifted Filter so the label reads as attached metadata rather than a tappable choice. Optional trailing icon only — typically the dismiss "×" for opt-out flows.
|
|
@@ -10,7 +10,7 @@ The selectable chip — a capsule-shaped toggle for refining a set. Unselected i
|
|
|
10
10
|
|
|
11
11
|
## Default
|
|
12
12
|
|
|
13
|
-
At-rest — transparent fill with a hairline `
|
|
13
|
+
At-rest — transparent fill with a hairline `border.default` stroke so the chip sits on any surface without colliding with the surface ladder.
|
|
14
14
|
|
|
15
15
|
```preview
|
|
16
16
|
chip/filter/unselected
|
|
@@ -22,9 +22,7 @@ import { Chip } from '@teamblind-chorus/ui';
|
|
|
22
22
|
</Chip>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
##
|
|
26
|
-
|
|
27
|
-
### Selected
|
|
25
|
+
## Selected
|
|
28
26
|
|
|
29
27
|
Active — inverse-toned fill. Toggle the `selected` flag on the same chip element.
|
|
30
28
|
|
|
@@ -41,7 +39,7 @@ import { Chip } from '@teamblind-chorus/ui';
|
|
|
41
39
|
</Chip>
|
|
42
40
|
```
|
|
43
41
|
|
|
44
|
-
|
|
42
|
+
## Leading icon
|
|
45
43
|
|
|
46
44
|
Facet glyph before the label — tag for category, magnifier for search, check on selection.
|
|
47
45
|
|
|
@@ -59,7 +57,7 @@ import { CheckedIcon } from '@teamblind-chorus/ui/icons';
|
|
|
59
57
|
</Chip>
|
|
60
58
|
```
|
|
61
59
|
|
|
62
|
-
|
|
60
|
+
## Trailing icon
|
|
63
61
|
|
|
64
62
|
Directional/dismiss glyph after the label — chevron-down to expand, *×* to clear.
|
|
65
63
|
|
|
@@ -77,7 +75,7 @@ import { XIcon } from '@teamblind-chorus/ui/icons';
|
|
|
77
75
|
</Chip>
|
|
78
76
|
```
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
## Trailing action
|
|
81
79
|
|
|
82
80
|
Pair the chip rail with a trailing accent [Text Button](../button/text.md) (`size='small'`, `appearance='accent'`) for a destination outside the filter axis — managing the set, opening keyword settings. The button is *not* a filter toggle; the chip track scrolls horizontally with a trailing 48px `mask-image` fade painted only while overflowing, and the button stays pinned outside the scroll viewport at `sys.layout.inline.xl` gap.
|
|
83
81
|
|
|
@@ -128,7 +126,21 @@ import { ArrowDownIcon } from '@teamblind-chorus/ui/icons';
|
|
|
128
126
|
</div>
|
|
129
127
|
```
|
|
130
128
|
|
|
131
|
-
|
|
129
|
+
## Focused
|
|
130
|
+
|
|
131
|
+
Both selection states take the same standard ring; the case below shows unselected.
|
|
132
|
+
|
|
133
|
+
```preview
|
|
134
|
+
chip/filter/focused
|
|
135
|
+
---
|
|
136
|
+
import { Chip } from '@teamblind-chorus/ui';
|
|
137
|
+
|
|
138
|
+
<Chip variant="filter" state="focused">
|
|
139
|
+
All
|
|
140
|
+
</Chip>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Group
|
|
132
144
|
|
|
133
145
|
Adjacent filter chips share a 4px gap (`sys.layout.inline.sm`), left-to-right; selection is independent per chip — Filter does not enforce single-select.
|
|
134
146
|
|
|
@@ -153,20 +165,6 @@ import { Chip } from '@teamblind-chorus/ui';
|
|
|
153
165
|
</div>
|
|
154
166
|
```
|
|
155
167
|
|
|
156
|
-
### Focus indicator
|
|
157
|
-
|
|
158
|
-
Both selection states take the same standard ring; the case below shows unselected.
|
|
159
|
-
|
|
160
|
-
```preview
|
|
161
|
-
chip/filter/focused
|
|
162
|
-
---
|
|
163
|
-
import { Chip } from '@teamblind-chorus/ui';
|
|
164
|
-
|
|
165
|
-
<Chip variant="filter" state="focused">
|
|
166
|
-
All
|
|
167
|
-
</Chip>
|
|
168
|
-
```
|
|
169
|
-
|
|
170
168
|
## Slots
|
|
171
169
|
|
|
172
170
|
- **label** — accessible name. Required, single line.
|
|
@@ -197,8 +195,8 @@ Single visual variant; the selected/unselected toggle swaps the container/label
|
|
|
197
195
|
|
|
198
196
|
| State | Background | Border (1px `sys.borderWidth.hairline`) | Label / icon color |
|
|
199
197
|
|--------------|-------------------------------------|---------------------------------------------------------|-----------------------------------|
|
|
200
|
-
| unselected | `transparent` | `sys.color.
|
|
201
|
-
| selected | `sys.color.
|
|
198
|
+
| unselected | `transparent` | `sys.color.border.default` | `sys.color.text.default` |
|
|
199
|
+
| selected | `sys.color.background.inverse` | `transparent` | `sys.color.text.inverse` |
|
|
202
200
|
|
|
203
201
|
## States
|
|
204
202
|
|
|
@@ -63,16 +63,16 @@
|
|
|
63
63
|
"selectionStates": {
|
|
64
64
|
"unselected": {
|
|
65
65
|
"background": "transparent",
|
|
66
|
-
"label": "sys.color.
|
|
66
|
+
"label": "sys.color.text.default",
|
|
67
67
|
"border": {
|
|
68
68
|
"width": "sys.borderWidth.hairline",
|
|
69
|
-
"color": "sys.color.
|
|
69
|
+
"color": "sys.color.border.default"
|
|
70
70
|
},
|
|
71
71
|
"note": "Transparent fill so the chip adopts whatever surface sits behind it (page, raised card, sheet) without pinning to a fixed neutral step."
|
|
72
72
|
},
|
|
73
73
|
"selected": {
|
|
74
|
-
"background": "sys.color.
|
|
75
|
-
"label": "sys.color.
|
|
74
|
+
"background": "sys.color.background.inverse",
|
|
75
|
+
"label": "sys.color.text.inverse",
|
|
76
76
|
"border": null
|
|
77
77
|
}
|
|
78
78
|
},
|
|
@@ -92,26 +92,49 @@
|
|
|
92
92
|
"opacity": "sys.state.pressed"
|
|
93
93
|
}
|
|
94
94
|
},
|
|
95
|
+
"focused": {
|
|
96
|
+
"overlay": {
|
|
97
|
+
"color": "label",
|
|
98
|
+
"opacity": "sys.state.focus"
|
|
99
|
+
},
|
|
100
|
+
"focusRing": {
|
|
101
|
+
"composition": "outward",
|
|
102
|
+
"layer": "::after overlay — position:absolute, inset:0, no reflow (DESIGN.md Focus ring composition)",
|
|
103
|
+
"innerCounterRing": {
|
|
104
|
+
"width": "sys.borderWidth.hairline",
|
|
105
|
+
"color": "sys.color.border.focused"
|
|
106
|
+
},
|
|
107
|
+
"outerRing": {
|
|
108
|
+
"width": "sys.borderWidth.thin",
|
|
109
|
+
"color": "sys.color.border.focused"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"note": "Keyboard-focus (:focus-visible) visual. Mirrors the `focusIndicator` block (the external-reader contract); kept here so spec-only renderers see focus in the states map. Composes over the lifecycle state the chip is in; never via plain mouse click."
|
|
113
|
+
},
|
|
95
114
|
"disabled": {
|
|
96
115
|
"overlay": null,
|
|
97
|
-
"
|
|
116
|
+
"background": "sys.color.background.disabled",
|
|
117
|
+
"label": "sys.color.text.disabled",
|
|
118
|
+
"border": {
|
|
119
|
+
"width": "sys.borderWidth.hairline",
|
|
120
|
+
"color": "sys.color.border.bold"
|
|
121
|
+
},
|
|
98
122
|
"suppressFocusRing": true,
|
|
99
|
-
"cursor": "not-allowed"
|
|
123
|
+
"cursor": "not-allowed",
|
|
124
|
+
"note": "Explicit disabled (no opacity): neutral disabled fill + bold border so the shape reads on any surface, plus disabled label. Overrides the rest/selected appearance."
|
|
100
125
|
}
|
|
101
126
|
},
|
|
102
127
|
"focusIndicator": {
|
|
103
128
|
"description": "Keyboard-focus visual — an accessibility indicator, not a lifecycle state. Composes over whichever lifecycle state the chip is in. The `states.focused` block above is kept for JSX runtime consumers; this block is the parallel external-reader contract.",
|
|
104
129
|
"composition": "outward",
|
|
105
|
-
"compositionReason": "Action affordance with breathing room around it; the
|
|
130
|
+
"compositionReason": "Action affordance with breathing room around it; the 1px outward ring is reserved by the surrounding layout.",
|
|
106
131
|
"overlay": {
|
|
107
132
|
"color": "label",
|
|
108
133
|
"opacity": "sys.state.focus"
|
|
109
134
|
},
|
|
110
135
|
"ring": {
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"insetWidth": "sys.borderWidth.hairline",
|
|
114
|
-
"insetColor": "sys.color.focusInset"
|
|
136
|
+
"width": "sys.borderWidth.hairline",
|
|
137
|
+
"color": "sys.color.border.focused"
|
|
115
138
|
},
|
|
116
139
|
"trigger": ":focus-visible (keyboard / programmatic focus, never plain mouse click)"
|
|
117
140
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 🇰🇷 한국어: [`i18n/ko/schema/components/chip/tag.md`](../../../i18n/ko/schema/components/chip/tag.md)
|
|
4
4
|
|
|
5
|
-
The informational chip — square-cornered label naming attached metadata (categories, statuses, content labels). Shorter than Filter (24 vs 32 min-height) with `sys.radius.sm` corners. Two appearances: `default` paints a translucent `sys.color.
|
|
5
|
+
The informational chip — square-cornered label naming attached metadata (categories, statuses, content labels). Shorter than Filter (24 vs 32 min-height) with `sys.radius.sm` corners. Two appearances: `default` paints a translucent `sys.color.background.neutral` overlay (~8% inverse-tone, adopts whatever surface sits behind it); `accent` paints a tonal pale-primary container with primary label.
|
|
6
6
|
|
|
7
7
|
**Reach for this when** you're naming attached metadata on rows, cards, or profiles. **Skip when** the marker signals unread / new activity on a host rather than describing it — use [Badge](../badge/badge.md) instead.
|
|
8
8
|
|
|
@@ -22,11 +22,9 @@ import { Chip } from '@teamblind-chorus/ui';
|
|
|
22
22
|
</Chip>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Accent
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Tonal pale-primary fill — `sys.color.primaryContainer` background, `sys.color.primary` label. Use when the tag should pop against the surface (Popular Tags in compose, highlighted hashtags); the default overlay is too quiet there.
|
|
27
|
+
Tonal pale-primary fill — `sys.color.background.selected` background, `sys.color.background.primary` label. Use when the tag should pop against the surface (Popular Tags in compose, highlighted hashtags); the default overlay is too quiet there.
|
|
30
28
|
|
|
31
29
|
```preview
|
|
32
30
|
chip/tag/accent
|
|
@@ -38,7 +36,7 @@ import { Chip } from '@teamblind-chorus/ui';
|
|
|
38
36
|
</Chip>
|
|
39
37
|
```
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
## Dismissable
|
|
42
40
|
|
|
43
41
|
Opt-out — same chip with a trailing *×* to remove the tag. Trailing icon inherits label color via `currentColor`.
|
|
44
42
|
|
|
@@ -56,7 +54,22 @@ import { XIcon } from '@teamblind-chorus/ui/icons';
|
|
|
56
54
|
</Chip>
|
|
57
55
|
```
|
|
58
56
|
|
|
59
|
-
|
|
57
|
+
## Focused
|
|
58
|
+
|
|
59
|
+
Only the dismissable tag is focusable; the case below shows that form. See [Focus ring composition](../../DESIGN.md#focus-ring-composition).
|
|
60
|
+
|
|
61
|
+
```preview
|
|
62
|
+
chip/tag/focused
|
|
63
|
+
---
|
|
64
|
+
import { Chip } from '@teamblind-chorus/ui';
|
|
65
|
+
import { XIcon } from '@teamblind-chorus/ui/icons';
|
|
66
|
+
|
|
67
|
+
<Chip variant="tag" state="focused" trailingIcon={<XIcon />}>
|
|
68
|
+
Newsletter
|
|
69
|
+
</Chip>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Group
|
|
60
73
|
|
|
61
74
|
Adjacent tag chips share a 4px gap on both axes — `sys.layout.inline.sm` between siblings, `sys.layout.stack.2xs` between rows on wrap. Mixing with Filter is allowed — Tag's square + sunken tone vs Filter's pill + raised tone keeps roles legible. Tags are passive metadata, so collections exceeding the container's width **wrap** rather than scroll or truncate (set `display: flex; flex-wrap: wrap` on the container; do not use `overflow-x: auto` — horizontal scrolling belongs to tappable affordances).
|
|
62
75
|
|
|
@@ -76,21 +89,6 @@ import { Chip } from '@teamblind-chorus/ui';
|
|
|
76
89
|
</div>
|
|
77
90
|
```
|
|
78
91
|
|
|
79
|
-
### Focus indicator
|
|
80
|
-
|
|
81
|
-
Only the dismissable tag is focusable; the case below shows that form. See [Focus ring composition](../../DESIGN.md#focus-ring-composition).
|
|
82
|
-
|
|
83
|
-
```preview
|
|
84
|
-
chip/tag/focused
|
|
85
|
-
---
|
|
86
|
-
import { Chip } from '@teamblind-chorus/ui';
|
|
87
|
-
import { XIcon } from '@teamblind-chorus/ui/icons';
|
|
88
|
-
|
|
89
|
-
<Chip variant="tag" state="focused" trailingIcon={<XIcon />}>
|
|
90
|
-
Newsletter
|
|
91
|
-
</Chip>
|
|
92
|
-
```
|
|
93
|
-
|
|
94
92
|
## Slots
|
|
95
93
|
|
|
96
94
|
- **label** — accessible name. Required, single line.
|
|
@@ -120,8 +118,8 @@ Two appearances; Tag never toggles.
|
|
|
120
118
|
|
|
121
119
|
| Appearance | Background | Label / icon color |
|
|
122
120
|
|------------|---------------------------------------------------------------------------------------------|------------------------------|
|
|
123
|
-
| `default` | `sys.color.
|
|
124
|
-
| `accent` | `sys.color.
|
|
121
|
+
| `default` | `sys.color.background.neutral` (translucent inverse-tone overlay — black 8% light / white 8% dark) | `sys.color.text.default` |
|
|
122
|
+
| `accent` | `sys.color.background.selected` (theme-aware) | `sys.color.background.primary` |
|
|
125
123
|
|
|
126
124
|
## States
|
|
127
125
|
|