@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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 🇰🇷 한국어: [`i18n/ko/schema/components/pagination/pagination.md`](../../../i18n/ko/schema/components/pagination/pagination.md)
|
|
4
4
|
|
|
5
|
-
Decorative dot-position indicator for one-page-at-a-time pagers — an inline row of 6px dots, one per page, the active dot painted `sys.color.
|
|
5
|
+
Decorative dot-position indicator for one-page-at-a-time pagers — an inline row of 6px dots, one per page, the active dot painted `sys.color.text.default` and the rest `sys.color.border.default`.
|
|
6
6
|
|
|
7
7
|
**Reach for this when** a horizontally-snapping pager needs to show where the user is — carousel cards ([PostCarousel](../carousel/post.md), [ProfileCarousel](../carousel/profile.md)), a swipeable media gallery, an onboarding pager. **Skip when** the position is a task-completion ratio (use [Progress](../progress/progress.md)), the pages need direct tap-to-jump navigation (dots here are non-interactive — use [Tabs](../tabs/tabs.md)), or the pager has only one page (the component renders nothing below two).
|
|
8
8
|
|
|
@@ -22,14 +22,14 @@ import { Pagination } from '@teamblind-chorus/ui';
|
|
|
22
22
|
|
|
23
23
|
## Slots
|
|
24
24
|
|
|
25
|
-
- **dot** *(decorative, one per page)* — 6 × 6 (`ref.space.75`), `sys.radius.full`. Active paints `sys.color.
|
|
25
|
+
- **dot** *(decorative, one per page)* — 6 × 6 (`ref.space.75`), `sys.radius.full`. Active paints `sys.color.text.default`; inactive paints `sys.color.border.default`.
|
|
26
26
|
|
|
27
27
|
## Anatomy
|
|
28
28
|
|
|
29
29
|
| Slot | Token bindings |
|
|
30
30
|
|------|----------------|
|
|
31
31
|
| row | inline element — `display: inline-flex`, intrinsic width, `sys.layout.inline.sm` gap, `aria-hidden`; horizontal placement belongs to the host |
|
|
32
|
-
| dot | 6 × 6 (`ref.space.75`), `sys.radius.full`; active `sys.color.
|
|
32
|
+
| dot | 6 × 6 (`ref.space.75`), `sys.radius.full`; active `sys.color.text.default`, inactive `sys.color.border.default` |
|
|
33
33
|
|
|
34
34
|
## Behavior
|
|
35
35
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "../../spec.schema.json",
|
|
3
3
|
"name": "Pagination",
|
|
4
4
|
"family": "pagination",
|
|
5
|
-
"description": "Decorative dot-position indicator for one-page-at-a-time pagers. An inline element (`span`, `display: inline-flex`) sized to its dots — it never stretches or centers itself; the host owns horizontal placement (the carousels center it via `align-self: center`). Renders one 6px (`ref.space.75`) fully-rounded dot per page in a `sys.layout.inline.sm` row; the active dot paints `sys.color.
|
|
5
|
+
"description": "Decorative dot-position indicator for one-page-at-a-time pagers. An inline element (`span`, `display: inline-flex`) sized to its dots — it never stretches or centers itself; the host owns horizontal placement (the carousels center it via `align-self: center`). Renders one 6px (`ref.space.75`) fully-rounded dot per page in a `sys.layout.inline.sm` row; the active dot paints `sys.color.text.default`, the rest paint `sys.color.border.default`. The row is presentational only (`aria-hidden`): the host pager (PostCarousel, ProfileCarousel, a media gallery) tracks the active index — typically via IntersectionObserver on its snap targets — and passes it down; tapping a dot does not navigate. Renders nothing when `count` < 2 — a one-page pager has no position to indicate.",
|
|
6
6
|
"element": "span",
|
|
7
7
|
"props": {
|
|
8
8
|
"count": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"slots": {
|
|
20
20
|
"dot": {
|
|
21
21
|
"required": true,
|
|
22
|
-
"description": "One per page. 6 × 6 (`ref.space.75`), `sys.radius.full`. Active paints `sys.color.
|
|
22
|
+
"description": "One per page. 6 × 6 (`ref.space.75`), `sys.radius.full`. Active paints `sys.color.text.default`; inactive paints `sys.color.border.default`.",
|
|
23
23
|
"intrinsic": true
|
|
24
24
|
}
|
|
25
25
|
},
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"dotRadius": "sys.radius.full"
|
|
32
32
|
},
|
|
33
33
|
"appearance": {
|
|
34
|
-
"activeDot": "sys.color.
|
|
35
|
-
"inactiveDot": "sys.color.
|
|
34
|
+
"activeDot": "sys.color.text.default",
|
|
35
|
+
"inactiveDot": "sys.color.border.default"
|
|
36
36
|
},
|
|
37
37
|
"states": {
|
|
38
38
|
"default": { "note": "Pagination carries no lifecycle states — the active index is its visual state, and the dots are non-interactive." }
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"forbidden": [
|
|
47
47
|
"Dots rendered as interactive controls (button / link, tap-to-navigate) — that needs a focusable, labelled tab-like contract this family deliberately does not carry; if navigation chrome is required, use a different component",
|
|
48
|
-
"Active dot painted with a chromatic primary / accent / brand tone — the indicator is position chrome, not emphasis; active is `sys.color.
|
|
48
|
+
"Active dot painted with a chromatic primary / accent / brand tone — the indicator is position chrome, not emphasis; active is `sys.color.text.default`, full stop",
|
|
49
49
|
"Pagination used as a step / completion indicator for a linear task — that role is `progress`",
|
|
50
50
|
"Numeric page labels, counters, or arrows composed into the row — the family is the dot row only; numbered pagination is a different pattern",
|
|
51
51
|
"Rendering the row for a single page (`count` < 2) by bypassing the built-in guard — a one-page pager has no position to indicate",
|
|
@@ -30,9 +30,7 @@ import { ProfileHeader } from '@teamblind-chorus/ui';
|
|
|
30
30
|
/>
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
##
|
|
34
|
-
|
|
35
|
-
### Following
|
|
33
|
+
## Following
|
|
36
34
|
|
|
37
35
|
Active state — the trailing button has flipped to `Following` (`surfaceContainerHigh` + hairline outline) so the followed state recedes.
|
|
38
36
|
|
|
@@ -51,7 +49,7 @@ import { ProfileHeader } from '@teamblind-chorus/ui';
|
|
|
51
49
|
/>
|
|
52
50
|
```
|
|
53
51
|
|
|
54
|
-
|
|
52
|
+
## Private
|
|
55
53
|
|
|
56
54
|
Private visibility — paints the [LockIcon](../../icons/svg/Lock.svg) on the meta row in place of the globe. Reach for it when the entity is gated (members-only channel, locked company channel).
|
|
57
55
|
|
|
@@ -69,7 +67,7 @@ import { ProfileHeader } from '@teamblind-chorus/ui';
|
|
|
69
67
|
/>
|
|
70
68
|
```
|
|
71
69
|
|
|
72
|
-
|
|
70
|
+
## Cover image
|
|
73
71
|
|
|
74
72
|
A custom cover photo overrides the placeholder. The image is `object-fit: cover` — aspect ratio preserved, cropped to fill the `375 / 120` cover band (scales with the host column).
|
|
75
73
|
|
|
@@ -87,7 +85,7 @@ import { ProfileHeader } from '@teamblind-chorus/ui';
|
|
|
87
85
|
/>
|
|
88
86
|
```
|
|
89
87
|
|
|
90
|
-
|
|
88
|
+
## Status bar
|
|
91
89
|
|
|
92
90
|
An edge-to-edge / immersive screen — `statusBar` paints an iOS-style app status bar (time + cellular / Wi-Fi / battery) above the overlay nav, at the very top of the cover. Its fill is transparent so the cover image shows through the OS-chrome zone; the glyphs are fixed white, matching the overlay nav. Reach for it when the route renders the cover full-bleed under a translucent system status bar.
|
|
93
91
|
|
|
@@ -116,8 +114,8 @@ import { ProfileHeader } from '@teamblind-chorus/ui';
|
|
|
116
114
|
- **identity** — vertical column under the cover. Pays `sys.layout.container.md` (16px) inline / block-end padding, no block-start padding (the action row's avatar lifts into the cover from y=0). `sys.layout.stack.xs` (8px) stack gap between the action row and the heading sub-group.
|
|
117
115
|
- **actionRow** — top row of the identity column. Avatar leads (overlapping the cover); follow [Toggle Button](../button/toggle.md) trails. The toggle sits `sys.layout.stack.md` (16px) below the cover bottom — independent of the avatar's lower edge — so it reads with its own breathing room.
|
|
118
116
|
- **heading** — sub-group bundling the name and meta row at `sys.layout.stack.2xs` (4px) gap. Sits below the action row.
|
|
119
|
-
- **name** — entity name. `<h1>` at `sys.typo.heading.lg` (24 / Semibold) / `sys.color.
|
|
120
|
-
- **meta** — visibility + follower row. `[visibility icon] [visibility label] · [followers]` in `sys.typo.body.sm` / `sys.color.
|
|
117
|
+
- **name** — entity name. `<h1>` at `sys.typo.heading.lg` (24 / Semibold) / `sys.color.text.default`. Single line; truncates with ellipsis.
|
|
118
|
+
- **meta** — visibility + follower row. `[visibility icon] [visibility label] · [followers]` in `sys.typo.body.sm` / `sys.color.text.subtle`. Single line.
|
|
121
119
|
- **followAction** — trailing [Toggle Button](../button/toggle.md) (`variant={'toggle'}`). `Follow` (inactive) → `Following` (active). Intrinsic width.
|
|
122
120
|
|
|
123
121
|
## Anatomy
|
|
@@ -132,9 +130,9 @@ import { ProfileHeader } from '@teamblind-chorus/ui';
|
|
|
132
130
|
| identity | Flex column, `padding-block: 0 sys.layout.container.md`, `padding-inline: sys.layout.container.md`, `sys.layout.stack.xs` (8) gap |
|
|
133
131
|
| actionRow | Flex row, `space-between` justify, `flex-start` align; follow button carries `margin-top: sys.layout.stack.md` (16) so it sits 16px below cover bottom |
|
|
134
132
|
| heading | Flex column, `sys.layout.stack.2xs` (4) gap between name and meta |
|
|
135
|
-
| name | `<h1>`, `sys.typo.heading.lg` (24 / Semibold), `sys.color.
|
|
136
|
-
| meta | Flex row, `sys.layout.inline.sm` (4) gap, `sys.typo.body.sm` / Regular, `sys.color.
|
|
137
|
-
| meta icon | `sys.icon.md` (16 × 16), `sys.color.
|
|
133
|
+
| name | `<h1>`, `sys.typo.heading.lg` (24 / Semibold), `sys.color.text.default`, single-line ellipsis |
|
|
134
|
+
| meta | Flex row, `sys.layout.inline.sm` (4) gap, `sys.typo.body.sm` / Regular, `sys.color.text.subtle`; `·` separator before followers |
|
|
135
|
+
| meta icon | `sys.icon.md` (16 × 16), `sys.color.text.subtle` |
|
|
138
136
|
| followAction | [Toggle Button](../button/toggle.md) (Toolbar-Button footprint); state tokens delegate to Toggle Button |
|
|
139
137
|
|
|
140
138
|
## States
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"followers": {
|
|
38
38
|
"type": "string",
|
|
39
39
|
"required": true,
|
|
40
|
-
"description": "Follower count line — formatted by the consumer so the unit / locale stays in their hands (e.g. '999 followers', '12.4K followers', '999 팔로워'). Paints in `sys.typo.body.sm` / `sys.color.
|
|
40
|
+
"description": "Follower count line — formatted by the consumer so the unit / locale stays in their hands (e.g. '999 followers', '12.4K followers', '999 팔로워'). Paints in `sys.typo.body.sm` / `sys.color.text.subtle` to the right of a bullet separator on the meta row."
|
|
41
41
|
},
|
|
42
42
|
"followed": {
|
|
43
43
|
"type": "boolean",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"slots": {
|
|
94
94
|
"container": {
|
|
95
95
|
"required": true,
|
|
96
|
-
"description": "Outer `<section>`. Vertical stack — cover band first, identity row second. `sys.color.surface` fill; no outer padding (the cover is full-bleed; the identity row pays its own inline padding).",
|
|
96
|
+
"description": "Outer `<section>`. Vertical stack — cover band first, identity row second. `sys.color.surface.default` fill; no outer padding (the cover is full-bleed; the identity row pays its own inline padding).",
|
|
97
97
|
"intrinsic": true
|
|
98
98
|
},
|
|
99
99
|
"cover": {
|
|
@@ -137,12 +137,12 @@
|
|
|
137
137
|
},
|
|
138
138
|
"name": {
|
|
139
139
|
"required": true,
|
|
140
|
-
"description": "Entity name. Renders as `<h1>` at `sys.typo.heading.lg` (24 / Semibold) / `sys.color.
|
|
140
|
+
"description": "Entity name. Renders as `<h1>` at `sys.typo.heading.lg` (24 / Semibold) / `sys.color.text.default`. Single line; truncates with ellipsis. Sits inside the `heading` sub-group.",
|
|
141
141
|
"accepts": ["text"]
|
|
142
142
|
},
|
|
143
143
|
"meta": {
|
|
144
144
|
"required": true,
|
|
145
|
-
"description": "Visibility + follower meta row. Composed as: [visibility icon] [visibility label] [bullet separator] [follower count]. `sys.typo.body.sm` (14 / Regular) / `sys.color.
|
|
145
|
+
"description": "Visibility + follower meta row. Composed as: [visibility icon] [visibility label] [bullet separator] [follower count]. `sys.typo.body.sm` (14 / Regular) / `sys.color.text.subtle`. Single line. Sits inside the `heading` sub-group, 4px below the name.",
|
|
146
146
|
"intrinsic": true
|
|
147
147
|
},
|
|
148
148
|
"followAction": {
|
|
@@ -153,9 +153,9 @@
|
|
|
153
153
|
}
|
|
154
154
|
},
|
|
155
155
|
"sizing": {
|
|
156
|
-
"containerFill": "sys.color.surface",
|
|
156
|
+
"containerFill": "sys.color.surface.default",
|
|
157
157
|
"coverAspectRatio": "375 / 120 (W × H — the mobile-viewport / cover-band proportion; the band scales with the host column instead of locking to a hard pixel height)",
|
|
158
|
-
"coverFill": "sys.color.
|
|
158
|
+
"coverFill": "sys.color.surface.default (background underlay — the placeholder image paints on top via `object-fit: cover`)",
|
|
159
159
|
"coverImageSource": "Same `/placeholder.png` asset every Chorus image-area slot falls back to. Decorative — `aria-hidden`. Consumers override via the `cover.src` prop.",
|
|
160
160
|
"avatarSize": 56,
|
|
161
161
|
"avatarOverlap": "Avatar's vertical center sits on the cover band's bottom edge — the top half overlaps the cover, the bottom half sits on the identity surface (-28px margin-top). The 2-token `surface`-tone halo that separates the circle from the cover is owned by Thumbnail's `outlined={true}` case — see [Thumbnail § With surface outline](../thumbnail/thumbnail.md#with-surface-outline). The header does not paint a halo of its own on the wrapper; the Thumbnail's outset `box-shadow` is the contract.",
|
|
@@ -170,11 +170,11 @@
|
|
|
170
170
|
"followMarginTop": "sys.layout.stack.md",
|
|
171
171
|
"followMarginTopNote": "Follow Toggle Button sits 16px below the cover bottom edge so the affordance reads with its own breathing room rather than aligning to the avatar's lower edge.",
|
|
172
172
|
"nameTypo": "sys.typo.heading.lg",
|
|
173
|
-
"nameColor": "sys.color.
|
|
173
|
+
"nameColor": "sys.color.text.default",
|
|
174
174
|
"metaTypo": "sys.typo.body.sm",
|
|
175
|
-
"metaColor": "sys.color.
|
|
175
|
+
"metaColor": "sys.color.text.subtle",
|
|
176
176
|
"metaIconSize": "sys.icon.md",
|
|
177
|
-
"metaIconColor": "sys.color.
|
|
177
|
+
"metaIconColor": "sys.color.text.subtle",
|
|
178
178
|
"metaGap": "sys.layout.inline.sm",
|
|
179
179
|
"metaSeparator": "·",
|
|
180
180
|
"followActionRendersAs": "Button variant='toggle' — Toolbar-Button footprint. State tokens delegate entirely to the Toggle Button (Chip-toggle) contract."
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "../../family.schema.json",
|
|
3
3
|
"family": "progress",
|
|
4
4
|
"name": "Progress",
|
|
5
|
-
"description": "Linear progress bar — a slim horizontal track that previews how far a long-running task has advanced. Determinate only: a filled segment parks at the value's ratio. One appearance, no emphasis axis: the track paints `sys.color.
|
|
5
|
+
"description": "Linear progress bar — a slim horizontal track that previews how far a long-running task has advanced. Determinate only: a filled segment parks at the value's ratio. One appearance, no emphasis axis: the track paints `sys.color.background.neutral` (a faint inverse-tone scrim that reads on any host surface tier) and the indicator paints `sys.color.background.inverse` so the filled segment always contrasts against the bare track in either theme. A single 8px fully-rounded rung. If a screen needs a higher-attention progress mark, the emphasis belongs in the surrounding copy (e.g. a Banner), never in a chromatic indicator tone. Single-spec family.",
|
|
6
6
|
"useCases": [
|
|
7
7
|
"upload / download progress",
|
|
8
8
|
"onboarding step progress",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 🇰🇷 한국어: [`i18n/ko/schema/components/progress/progress.md`](../../../i18n/ko/schema/components/progress/progress.md)
|
|
4
4
|
|
|
5
|
-
A single visual rung — 8px tall, fully rounded — that previews how far a long-running task has advanced. Determinate only: a filled indicator parks at the value's ratio. No emphasis axis: track paints with `sys.color.
|
|
5
|
+
A single visual rung — 8px tall, fully rounded — that previews how far a long-running task has advanced. Determinate only: a filled indicator parks at the value's ratio. No emphasis axis: track paints with `sys.color.background.neutral` (the translucent inverse-tone scrim — ~8% black light, ~8% white dark); indicator paints in `inverseSurface` so the filled segment contrasts against the track regardless of theme.
|
|
6
6
|
|
|
7
7
|
**Reach for this when** a screen holds a task long enough that the user would otherwise wonder if anything is happening — file uploads, onboarding step counters, background syncs, account migrations. **Skip when** the task resolves under 300ms, the wait is purely opaque (use [Skeleton](../skeleton/skeleton.md) for content placeholders, busy spinners for short opaque waits), or the metric is primary content rather than chrome (use a chart).
|
|
8
8
|
|
|
@@ -22,15 +22,15 @@ import { Progress } from '@teamblind-chorus/ui';
|
|
|
22
22
|
|
|
23
23
|
## Slots
|
|
24
24
|
|
|
25
|
-
- **track** — fully-rounded background block. 8px tall, `sys.color.
|
|
26
|
-
- **indicator** *(decorative)* — inner filled segment painted in `sys.color.
|
|
25
|
+
- **track** — fully-rounded background block. 8px tall, `sys.color.background.neutral` fill (translucent inverse-tone scrim — black 8% light, white 8% dark), no stroke. Carries `role="progressbar"` and the aria-value attributes.
|
|
26
|
+
- **indicator** *(decorative)* — inner filled segment painted in `sys.color.background.inverse`, `translateX`'d so the trailing edge lands at the value's ratio.
|
|
27
27
|
|
|
28
28
|
## Anatomy
|
|
29
29
|
|
|
30
30
|
| Slot | Token bindings |
|
|
31
31
|
|--------------|----------------|
|
|
32
|
-
| track | `sys.color.
|
|
33
|
-
| indicator | `sys.color.
|
|
32
|
+
| track | `sys.color.background.neutral` fill (translucent inverse-tone scrim), `sys.radius.full`, 8px (`sys.layout.container.xs`) tall |
|
|
33
|
+
| indicator | `sys.color.background.inverse` fill, fully rounded, `transform: translateX(…)` driven |
|
|
34
34
|
| transition | 200ms `ease-out` on indicator transform as `value` changes |
|
|
35
35
|
|
|
36
36
|
## Behavior
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "../../spec.schema.json",
|
|
3
3
|
"name": "Progress",
|
|
4
4
|
"family": "progress",
|
|
5
|
-
"description": "Linear progress bar. A single visual rung — 8px tall, fully rounded — that previews how far a long-running task has advanced. The track paints with `sys.color.
|
|
5
|
+
"description": "Linear progress bar. A single visual rung — 8px tall, fully rounded — that previews how far a long-running task has advanced. The track paints with `sys.color.background.neutral` (the Banner-style inverse-tone scrim — ~8% black in light, ~8% white in dark) so the bar reads cleanly on any host surface tier without colliding with a fixed surface-container step. The indicator paints in `sys.color.background.inverse` so the filled segment always contrasts against the scrim track regardless of theme. The track owns no width of its own — it stretches to fill its host column. Determinate only — `role='progressbar'` with `aria-valuemin / max / now` reflects the value's ratio.",
|
|
6
6
|
"element": "div",
|
|
7
7
|
"props": {
|
|
8
8
|
"value": {
|
|
@@ -24,29 +24,29 @@
|
|
|
24
24
|
"slots": {
|
|
25
25
|
"track": {
|
|
26
26
|
"required": true,
|
|
27
|
-
"description": "Fully-rounded background block. 8px tall, `sys.color.
|
|
27
|
+
"description": "Fully-rounded background block. 8px tall, `sys.color.background.neutral` fill (translucent inverse-tone scrim — black 8% light / white 8% dark), no stroke. Carries `role='progressbar'` and the aria-value attributes.",
|
|
28
28
|
"intrinsic": true
|
|
29
29
|
},
|
|
30
30
|
"indicator": {
|
|
31
31
|
"required": true,
|
|
32
|
-
"description": "Inner filled segment painted in `sys.color.
|
|
32
|
+
"description": "Inner filled segment painted in `sys.color.background.inverse`, translated horizontally so its trailing edge sits at the value's ratio.",
|
|
33
33
|
"intrinsic": true
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
"sizing": {
|
|
37
37
|
"height": "sys.layout.container.xs",
|
|
38
|
-
"trackBackground": "sys.color.
|
|
38
|
+
"trackBackground": "sys.color.background.neutral",
|
|
39
39
|
"trackRadius": "sys.radius.full",
|
|
40
|
-
"indicatorBackground": "sys.color.
|
|
40
|
+
"indicatorBackground": "sys.color.background.inverse",
|
|
41
41
|
"indicatorRadius": "inherit",
|
|
42
42
|
"transitionDuration": "200ms",
|
|
43
43
|
"transitionTiming": "ease-out"
|
|
44
44
|
},
|
|
45
45
|
"appearances": {
|
|
46
46
|
"default": {
|
|
47
|
-
"track": "sys.color.
|
|
48
|
-
"indicator": "sys.color.
|
|
49
|
-
"note": "The only appearance. Track paints `sys.color.
|
|
47
|
+
"track": "sys.color.background.neutral",
|
|
48
|
+
"indicator": "sys.color.background.inverse",
|
|
49
|
+
"note": "The only appearance. Track paints `sys.color.background.neutral` — a faint inverse-tone scrim (~8% black light / ~8% white dark) visible against every surface tier in either theme. Indicator paints in `inverseSurface` so the filled segment always contrasts against the bare track regardless of theme. Progress has no emphasis axis; if a screen needs a higher-attention progress mark, it belongs as a Banner copy nearby, not as a chromatic indicator tone."
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
52
|
"states": {
|
|
@@ -59,21 +59,21 @@ import { StarFillIcon } from '@teamblind-chorus/ui/icons';
|
|
|
59
59
|
label: 'Sourdough Bakers',
|
|
60
60
|
count: <Badge size="small" count={12} />,
|
|
61
61
|
thumbnail: { alt: 'Sourdough Bakers' },
|
|
62
|
-
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorited" aria-pressed="true" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-yellow)' }} onClick={() => {}} />,
|
|
62
|
+
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorited" aria-pressed="true" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-accent-yellow-default)' }} onClick={() => {}} />,
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
value: 'stocks',
|
|
66
66
|
label: 'Stocks & Investing',
|
|
67
67
|
count: <Badge size="small" count={142} />,
|
|
68
68
|
thumbnail: { alt: 'Stocks & Investing' },
|
|
69
|
-
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorited" aria-pressed="true" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-yellow)' }} onClick={() => {}} />,
|
|
69
|
+
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorited" aria-pressed="true" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-accent-yellow-default)' }} onClick={() => {}} />,
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
72
|
value: 'movie-talk',
|
|
73
73
|
label: 'Movie Talk',
|
|
74
74
|
count: <Badge size="small" count={24} />,
|
|
75
75
|
thumbnail: { alt: 'Movie Talk' },
|
|
76
|
-
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorited" aria-pressed="true" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-yellow)' }} onClick={() => {}} />,
|
|
76
|
+
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorited" aria-pressed="true" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-accent-yellow-default)' }} onClick={() => {}} />,
|
|
77
77
|
},
|
|
78
78
|
]}
|
|
79
79
|
/>
|
|
@@ -90,20 +90,20 @@ import { StarFillIcon } from '@teamblind-chorus/ui/icons';
|
|
|
90
90
|
label: 'Career & Jobs',
|
|
91
91
|
count: <Badge size="small" count={24} />,
|
|
92
92
|
thumbnail: { alt: 'Career & Jobs' },
|
|
93
|
-
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorite" aria-pressed="false" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-
|
|
93
|
+
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorite" aria-pressed="false" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-subtle)' }} onClick={() => {}} />,
|
|
94
94
|
},
|
|
95
95
|
{
|
|
96
96
|
value: 'marketplace',
|
|
97
97
|
label: 'Marketplace',
|
|
98
98
|
count: <Badge size="small" count={12} />,
|
|
99
99
|
thumbnail: { alt: 'Marketplace' },
|
|
100
|
-
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorite" aria-pressed="false" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-
|
|
100
|
+
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorite" aria-pressed="false" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-subtle)' }} onClick={() => {}} />,
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
value: 'fashion',
|
|
104
104
|
label: 'Fashion & Beauty',
|
|
105
105
|
thumbnail: { alt: 'Fashion & Beauty' },
|
|
106
|
-
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorite" aria-pressed="false" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-
|
|
106
|
+
trailingIcon: <Button variant="icon" size="medium" aria-label="Favorite" aria-pressed="false" icon={<StarFillIcon />} style={{ color: 'var(--sys-color-icon-subtle)' }} onClick={() => {}} />,
|
|
107
107
|
},
|
|
108
108
|
]}
|
|
109
109
|
/>
|
|
@@ -111,13 +111,11 @@ import { StarFillIcon } from '@teamblind-chorus/ui/icons';
|
|
|
111
111
|
</SideSheet>
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
##
|
|
115
|
-
|
|
116
|
-
### Single section
|
|
114
|
+
## Single section
|
|
117
115
|
|
|
118
116
|
One `SideSheetGroup` with a Header + List(entry) directory. Use for filter rails, settings groups, sub-navigation overlays.
|
|
119
117
|
|
|
120
|
-
|
|
118
|
+
## Pinned commit
|
|
121
119
|
|
|
122
120
|
Set the `footer` prop with a Text Button to pin a primary commit at the bottom (e.g. "Browse all channels", "Apply filters"). Footer stays flush while the body scrolls.
|
|
123
121
|
|
|
@@ -127,7 +125,7 @@ Set the `footer` prop with a Text Button to pin a primary commit at the bottom (
|
|
|
127
125
|
- **card** — off-canvas column. Fixed width, full viewport height, flush against the `anchor` edge. `sys.color.surface` fill + `sys.elevation.sheet` shadow.
|
|
128
126
|
- **body** — vertical scroll surface inside the card. **Full-bleed** — no inline gutter; each child pays its own `container.md` (16) rail. Block padding is `0` at the top (each group's leading Header supplies the 24 top inset itself) and `24px` at the bottom; the body adds no inter-child gap — the Header-driven block rhythm is the single source of truth.
|
|
129
127
|
- **group** *(SideSheetGroup)* — bundle of one Header + a directory primitive (canonical: an embedded [list/entry](../list/entry.md) stack) inside the body. The full-bleed Header drives the rhythm: its `24px` (`layout.stack.lg`) block-start is both the gap **between groups** and the body's top inset for the first group; its `16px` (`layout.stack.md`) block-end is the header↔directory gap. The group adds no sibling margin of its own. Because the body is full-bleed, the `<List variant="entry">` aligns at the same 16 rail as the Header with no opt-out.
|
|
130
|
-
- **footer** *(optional)* — pinned bottom action rail. Single Text Button or compact action node; separated by an `
|
|
128
|
+
- **footer** *(optional)* — pinned bottom action rail. Single Text Button or compact action node; separated by an `border.default` hairline.
|
|
131
129
|
|
|
132
130
|
## Trailing favorite-star contract
|
|
133
131
|
|
|
@@ -135,8 +133,8 @@ When a channel / directory row carries a favorite toggle on its trailing edge, u
|
|
|
135
133
|
|
|
136
134
|
| State | Icon | Colour | aria-pressed |
|
|
137
135
|
|----------|-----------------|---------------------------------|--------------|
|
|
138
|
-
| Active | `StarFillIcon` | `var(--sys-color-icon-yellow)` | `true` |
|
|
139
|
-
| Inactive | `StarFillIcon` | `var(--sys-color-icon-
|
|
136
|
+
| Active | `StarFillIcon` | `var(--sys-color-icon-accent-yellow-default)` | `true` |
|
|
137
|
+
| Inactive | `StarFillIcon` | `var(--sys-color-icon-subtle)` | `false` |
|
|
140
138
|
|
|
141
139
|
The shape stays constant so the trailing edge has a stable hit-target footprint; only the colour token flips. This is the canonical pattern across Side Sheet, channel lists, directory rows.
|
|
142
140
|
|
|
@@ -63,19 +63,19 @@
|
|
|
63
63
|
},
|
|
64
64
|
"footer": {
|
|
65
65
|
"required": false,
|
|
66
|
-
"description": "Pinned bottom action rail. Separated from the body by a `
|
|
66
|
+
"description": "Pinned bottom action rail. Separated from the body by a `border.default` hairline. `16px` inline + block padding."
|
|
67
67
|
}
|
|
68
68
|
},
|
|
69
69
|
"sizing": {
|
|
70
70
|
"scrimColor": "ref.palette.black.600",
|
|
71
|
-
"cardBg": "sys.color.surface",
|
|
71
|
+
"cardBg": "sys.color.surface.default",
|
|
72
72
|
"cardElevation": "sys.elevation.sheet",
|
|
73
73
|
"cardDefaultWidth": "320px",
|
|
74
74
|
"bodyPadding": "sys.layout.container.lg (24) block × sys.layout.container.md (16) inline",
|
|
75
75
|
"bodyStackGap": "sys.layout.stack.lg (24) — between groups",
|
|
76
76
|
"groupStackGap": "sys.layout.stack.md (16) — within group, Header → List",
|
|
77
77
|
"footerPadding": "sys.layout.container.md (16)",
|
|
78
|
-
"footerDivider": "sys.borderWidth.hairline / sys.color.
|
|
78
|
+
"footerDivider": "sys.borderWidth.hairline / sys.color.border.default"
|
|
79
79
|
},
|
|
80
80
|
"states": {
|
|
81
81
|
"open": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 🇰🇷 한국어: [`i18n/ko/schema/components/skeleton/skeleton.md`](../../../i18n/ko/schema/components/skeleton/skeleton.md)
|
|
4
4
|
|
|
5
|
-
A tonal placeholder block that previews where real content will render. Paints with a translucent `
|
|
5
|
+
A tonal placeholder block that previews where real content will render. Paints with a translucent `background.neutral` overlay (~8% black in light mode, ~8% white in dark) and a slow opacity pulse — visible on every host surface tier without colliding with a fixed neutral step. Three shapes — `text` (default 16-line block), `block` (image / card body), `circle` (avatar). Compose multiple Skeletons inside `SkeletonGroup` to mirror the loading content's rhythm.
|
|
6
6
|
|
|
7
7
|
**Reach for this when** a list row, feed post, card cover, or avatar is being fetched and the host would otherwise paint empty. **Skip when** the wait is sub-300ms, the data is unavailable rather than loading (use an empty-state illustration), or the loading scope is the whole screen (use a centered progress indicator at page level).
|
|
8
8
|
|
|
@@ -20,9 +20,7 @@ import { Skeleton } from '@teamblind-chorus/ui';
|
|
|
20
20
|
<Skeleton />
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
##
|
|
24
|
-
|
|
25
|
-
### Block
|
|
23
|
+
## Block
|
|
26
24
|
|
|
27
25
|
A rectangular tonal block. 80px high by default — reads as a card cover, image area, or card body placeholder. Pass `height` to match the real content's footprint.
|
|
28
26
|
|
|
@@ -34,7 +32,7 @@ import { Skeleton } from '@teamblind-chorus/ui';
|
|
|
34
32
|
<Skeleton shape="block" height={120} />
|
|
35
33
|
```
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
## Circle
|
|
38
36
|
|
|
39
37
|
An avatar placeholder. 40 × 40 by default — matches a 40-rung [Thumbnail](../thumbnail/thumbnail.md). Override `width` / `height` for a different rung.
|
|
40
38
|
|
|
@@ -46,7 +44,7 @@ import { Skeleton } from '@teamblind-chorus/ui';
|
|
|
46
44
|
<Skeleton shape="circle" />
|
|
47
45
|
```
|
|
48
46
|
|
|
49
|
-
|
|
47
|
+
## List row
|
|
50
48
|
|
|
51
49
|
A list-row loading state — leading 40-circle next to two stacked text lines. Use the same widths as the real row so the swap to live data doesn't reflow.
|
|
52
50
|
|
|
@@ -64,7 +62,7 @@ import { Skeleton, SkeletonGroup } from '@teamblind-chorus/ui';
|
|
|
64
62
|
</div>
|
|
65
63
|
```
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
## Feed post
|
|
68
66
|
|
|
69
67
|
A feed-post loading state — author row (avatar + name + meta), title, two body lines, and a 16:9 cover block. Mirrors the rhythm of a real feed/post.
|
|
70
68
|
|
|
@@ -90,13 +88,13 @@ import { Skeleton, SkeletonGroup } from '@teamblind-chorus/ui';
|
|
|
90
88
|
|
|
91
89
|
## Slots
|
|
92
90
|
|
|
93
|
-
- **container** — the tonal block. `sys.color.
|
|
91
|
+
- **container** — the tonal block. `sys.color.background.neutral` fill (translucent inverse-tone overlay — black in light, white in dark), shape-dependent radius. Carries the pulse animation. `role='status'` + `aria-live='polite'` so screen readers announce the loading state without yanking focus.
|
|
94
92
|
|
|
95
93
|
## Anatomy
|
|
96
94
|
|
|
97
95
|
| Slot | Token bindings |
|
|
98
96
|
|------------|----------------|
|
|
99
|
-
| container | `sys.color.
|
|
97
|
+
| container | `sys.color.background.neutral` fill, `sys.radius.xs` corners (`text` / `block`) or `sys.radius.full` (`circle`), no stroke |
|
|
100
98
|
| text | Default `ref.space.200` (16px) height × 100% width |
|
|
101
99
|
| block | Default `ref.space.1000` (80px) height × 100% width |
|
|
102
100
|
| circle | Default `ref.space.500` × `ref.space.500` (40 × 40) round |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "../../spec.schema.json",
|
|
3
3
|
"name": "Skeleton",
|
|
4
4
|
"family": "skeleton",
|
|
5
|
-
"description": "Single tonal placeholder block painted on `sys.color.
|
|
5
|
+
"description": "Single tonal placeholder block painted on `sys.color.background.neutral` (~8% inverse-tone overlay — black scrim in light mode, white scrim in dark) with a slow opacity pulse (`0.5 → 1 → 0.5` over 1.6s). The translucent fill stays visible on every host surface tier, so the placeholder reads cleanly whether it sits on a plain page surface, an elevated container, a hero band, or a coloured card. Three shapes select the default footprint and corner radius: `text` (`ref.space.200` / 16px high, full-width — single line of body copy), `block` (`ref.space.1000` / 80px high, full-width — image / card body) and `circle` (`ref.space.500` × `ref.space.500` / 40 × 40, fully rounded — avatar). Consumer-supplied `width` / `height` props override the default footprint. Compose multiple Skeletons inside `SkeletonGroup` to mirror the rhythm of the content being loaded.",
|
|
6
6
|
"element": "span",
|
|
7
7
|
"props": {
|
|
8
8
|
"shape": {
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"slots": {
|
|
33
33
|
"container": {
|
|
34
34
|
"required": true,
|
|
35
|
-
"description": "Tonal block. `sys.color.
|
|
35
|
+
"description": "Tonal block. `sys.color.background.neutral` fill (translucent black/white inverse-tone overlay — visible on every host surface), shape-dependent radius, no stroke. Carries the pulse animation. `role='status'` + `aria-live='polite'` so screen readers announce the loading state without yanking focus.",
|
|
36
36
|
"intrinsic": true
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
39
|
"sizing": {
|
|
40
|
-
"background": "sys.color.
|
|
40
|
+
"background": "sys.color.background.neutral",
|
|
41
41
|
"radiusText": "sys.radius.xs",
|
|
42
42
|
"radiusBlock": "sys.radius.xs",
|
|
43
43
|
"radiusCircle": "sys.radius.full",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"appearances": {
|
|
50
50
|
"default": {
|
|
51
|
-
"background": "sys.color.
|
|
51
|
+
"background": "sys.color.background.neutral",
|
|
52
52
|
"note": "The only fill tone — Skeleton has no emphasis axis. Painted as a translucent ~8% inverse-tone overlay (black in light mode, white in dark) so the placeholder stays visible on every host surface tier (surface, surfaceContainer, surfaceContainerHigh, hero, …) without colliding with a fixed neutral step. The pulse modulates opacity, not hue, so the placeholder reads as anonymous chrome."
|
|
53
53
|
}
|
|
54
54
|
},
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"footprintOverrides": "`width` / `height` props win over the shape's default footprint, including for `circle` (a circle Skeleton at `width=60 height=60` stays a 60-rung round)."
|
|
65
65
|
},
|
|
66
66
|
"forbidden": [
|
|
67
|
-
"skeleton fill stepped to `sys.color.primary` or any chromatic tone — the placeholder must read as anonymous chrome, not as a content tone",
|
|
67
|
+
"skeleton fill stepped to `sys.color.background.primary` or any chromatic tone — the placeholder must read as anonymous chrome, not as a content tone",
|
|
68
68
|
"shimmer / gradient sweep animation — Chorus skeletons modulate opacity only (one motion axis keeps the tier readable under reduced-motion fallback)",
|
|
69
69
|
"skeleton stacked vertically without a SkeletonGroup wrapper — group via SkeletonGroup so the 8px gap stays consistent across compositions",
|
|
70
70
|
"skeleton kept on-screen after the real content resolves — the placeholder must swap out atomically, not cross-fade with the loaded data",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "../../family.schema.json",
|
|
3
3
|
"family": "spinner",
|
|
4
4
|
"name": "Spinner",
|
|
5
|
-
"description": "Indeterminate loading indicator — a rotating arc in `sys.color.primary` that signals a short, progress-unknown wait (under ~1 second of expected delay) on a neutral host surface. Two rungs ride the `icon.*` size ladder: `medium` (`sys.icon.lg` / 24px, default) and `small` (`sys.icon.md` / 16px). An optional `label` slot lets a single line of loading copy sit beside the arc. Reserved to one Spinner per view — for content-shaped waits use `skeleton`, for a known ratio use `progress`. Single-spec family.",
|
|
5
|
+
"description": "Indeterminate loading indicator — a rotating arc in `sys.color.background.primary` that signals a short, progress-unknown wait (under ~1 second of expected delay) on a neutral host surface. Two rungs ride the `icon.*` size ladder: `medium` (`sys.icon.lg` / 24px, default) and `small` (`sys.icon.md` / 16px). An optional `label` slot lets a single line of loading copy sit beside the arc. Reserved to one Spinner per view — for content-shaped waits use `skeleton`, for a known ratio use `progress`. Single-spec family.",
|
|
6
6
|
"useCases": [
|
|
7
7
|
"sub-second indeterminate wait (button submit, inline action)",
|
|
8
8
|
"small surface where a skeleton would be heavier than the wait",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 🇰🇷 한국어: [`i18n/ko/schema/components/spinner/spinner.md`](../../../i18n/ko/schema/components/spinner/spinner.md)
|
|
4
4
|
|
|
5
|
-
An indeterminate loading indicator — a rotating arc in `sys.color.primary` over a faint `
|
|
5
|
+
An indeterminate loading indicator — a rotating arc in `sys.color.background.primary` over a faint `background.neutral` ring that signals a short, progress-unknown wait on a neutral host surface. Two rungs ride the `icon.*` ladder — `medium` (24px, default) and `small` (16px). Pass a `label` for a single line of loading copy beside the arc.
|
|
6
6
|
|
|
7
7
|
**Reach for this when** a wait is brief and indeterminate (under ~1 second) — a button submit, an inline action, or a first-paint loader before a screen's data resolves — and a content-shaped placeholder would be heavier than the wait itself. **Skip when** the wait mirrors a known shape (use [Skeleton](../skeleton/skeleton.md)), the task has a measurable ratio (use [Progress](../progress/progress.md)), or the surface already shows another Spinner — reserve one per view.
|
|
8
8
|
|
|
@@ -20,9 +20,7 @@ import { Spinner } from '@teamblind-chorus/ui';
|
|
|
20
20
|
<Spinner aria-label="Loading" />
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
##
|
|
24
|
-
|
|
25
|
-
### With label
|
|
23
|
+
## Label
|
|
26
24
|
|
|
27
25
|
A single line of loading copy beside the arc. The label doubles as the accessible name, so `aria-label` is not needed.
|
|
28
26
|
|
|
@@ -34,7 +32,7 @@ import { Spinner } from '@teamblind-chorus/ui';
|
|
|
34
32
|
<Spinner label="Loading…" />
|
|
35
33
|
```
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
## Small
|
|
38
36
|
|
|
39
37
|
The 16px rung — for tight inline affordances (a button label, a form-field affix) where the 24px default would crowd.
|
|
40
38
|
|
|
@@ -46,7 +44,7 @@ import { Spinner } from '@teamblind-chorus/ui';
|
|
|
46
44
|
<Spinner size="small" aria-label="Loading" />
|
|
47
45
|
```
|
|
48
46
|
|
|
49
|
-
|
|
47
|
+
## Centered
|
|
50
48
|
|
|
51
49
|
A first-paint loader centered inside the surface that will hold the data. One Spinner per view.
|
|
52
50
|
|
|
@@ -63,18 +61,18 @@ import { Spinner } from '@teamblind-chorus/ui';
|
|
|
63
61
|
## Slots
|
|
64
62
|
|
|
65
63
|
- **container** — inline-flex wrapper. Carries `role='status'` and the accessible name; holds the arc and the optional label, separated by `sys.layout.inline.sm`.
|
|
66
|
-
- **arc** — the rotating ring. `sys.color.primary` foreground arc over a `sys.color.
|
|
67
|
-
- **label** — optional single line of loading copy beside the arc. `sys.typo.body.sm`, `sys.color.
|
|
64
|
+
- **arc** — the rotating ring. `sys.color.background.primary` foreground arc over a `sys.color.background.neutral` track ring, fully rounded, no stroke. Carries the spin animation. Decorative (`aria-hidden`).
|
|
65
|
+
- **label** — optional single line of loading copy beside the arc. `sys.typo.body.sm`, `sys.color.text.subtle`.
|
|
68
66
|
|
|
69
67
|
## Anatomy
|
|
70
68
|
|
|
71
69
|
| Slot | Token bindings |
|
|
72
70
|
|------------|----------------|
|
|
73
71
|
| container | inline-flex, `sys.layout.inline.sm` gap between arc and label |
|
|
74
|
-
| arc | `sys.color.primary` foreground arc, `sys.color.
|
|
72
|
+
| arc | `sys.color.background.primary` foreground arc, `sys.color.background.neutral` track ring, `sys.radius.full`, no stroke |
|
|
75
73
|
| medium | `sys.icon.lg` (24px) diameter — the default rung |
|
|
76
74
|
| small | `sys.icon.md` (16px) diameter |
|
|
77
|
-
| label | `sys.typo.body.sm`, `sys.color.
|
|
75
|
+
| label | `sys.typo.body.sm`, `sys.color.text.subtle` |
|
|
78
76
|
|
|
79
77
|
## Sizes
|
|
80
78
|
|