@felloinnovations/brand-kit 0.4.0 → 0.5.1
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/AGENTS.md +198 -24
- package/CHANGELOG.md +221 -0
- package/README.md +38 -9
- package/design-system/01-how-claude-decides.md +26 -17
- package/design-system/02-principles.md +11 -6
- package/design-system/03-colour.md +135 -47
- package/design-system/04-type.md +45 -23
- package/design-system/05-space-and-layout.md +175 -52
- package/design-system/06-sizing-profiles.md +4 -4
- package/design-system/07-scrolling.md +66 -20
- package/design-system/08-choosing-components.md +50 -22
- package/design-system/09-charts.md +71 -28
- package/design-system/10-patterns.md +33 -10
- package/design-system/11-page-recipes.md +110 -23
- package/design-system/12-content.md +2 -1
- package/design-system/13-motion.md +330 -47
- package/design-system/14-accessibility.md +47 -24
- package/design-system/15-ai-experiences.md +11 -6
- package/design-system/16-creativity.md +1 -1
- package/design-system/17-decisions.md +367 -1
- package/design-system/18-checklist.md +79 -16
- package/design-system/19-public-pages.md +6 -4
- package/design-system/20-palettes.md +275 -0
- package/design-system/README.md +30 -17
- package/design-system/components/ActionList/README.md +96 -10
- package/design-system/components/ActionList/preview.html +52 -7
- package/design-system/components/ActionList/style.css +64 -0
- package/design-system/components/ActivityGrid/README.md +38 -2
- package/design-system/components/ActivityGrid/preview.html +1 -1
- package/design-system/components/ActivityGrid/style.css +35 -0
- package/design-system/components/AppShell/README.md +205 -75
- package/design-system/components/AppShell/preview.html +339 -58
- package/design-system/components/AppShell/style.css +154 -0
- package/design-system/components/Avatar/README.md +37 -10
- package/design-system/components/Avatar/preview.html +13 -4
- package/design-system/components/Avatar/style.css +14 -0
- package/design-system/components/Badge/README.md +41 -19
- package/design-system/components/Badge/preview.html +13 -10
- package/design-system/components/Badge/style.css +23 -0
- package/design-system/components/Banner/README.md +30 -9
- package/design-system/components/Banner/preview.html +1 -1
- package/design-system/components/Banner/style.css +19 -0
- package/design-system/components/Breadcrumb/README.md +58 -46
- package/design-system/components/Breadcrumb/preview.html +16 -16
- package/design-system/components/Breadcrumb/style.css +17 -0
- package/design-system/components/Button/README.md +113 -55
- package/design-system/components/Button/preview.html +98 -25
- package/design-system/components/Button/style.css +86 -0
- package/design-system/components/Card/README.md +158 -49
- package/design-system/components/Card/preview.html +141 -19
- package/design-system/components/Card/style.css +115 -0
- package/design-system/components/CardBoard/README.md +58 -37
- package/design-system/components/CardBoard/preview.html +26 -29
- package/design-system/components/ChatCard/README.md +115 -29
- package/design-system/components/ChatCard/preview.html +149 -32
- package/design-system/components/ChatCard/style.css +49 -0
- package/design-system/components/ChatShell/README.md +116 -0
- package/design-system/components/ChatShell/preview.html +201 -0
- package/design-system/components/ChatShell/style.css +86 -0
- package/design-system/components/ChatTurn/README.md +78 -35
- package/design-system/components/ChatTurn/preview.html +60 -28
- package/design-system/components/ChatTurn/style.css +50 -0
- package/design-system/components/CheckRow/README.md +141 -0
- package/design-system/components/CheckRow/preview.html +140 -0
- package/design-system/components/CheckRow/style.css +88 -0
- package/design-system/components/Checkbox/README.md +58 -22
- package/design-system/components/Checkbox/preview.html +112 -50
- package/design-system/components/Checkbox/style.css +45 -0
- package/design-system/components/Chip/README.md +78 -47
- package/design-system/components/Chip/preview.html +29 -4
- package/design-system/components/Chip/style.css +17 -0
- package/design-system/components/Combobox/README.md +44 -11
- package/design-system/components/Combobox/preview.html +35 -12
- package/design-system/components/Combobox/style.css +54 -0
- package/design-system/components/Composer/README.md +137 -35
- package/design-system/components/Composer/preview.html +115 -40
- package/design-system/components/Composer/style.css +81 -0
- package/design-system/components/ConfirmDialog/README.md +73 -52
- package/design-system/components/ConfirmDialog/preview.html +70 -26
- package/design-system/components/ConfirmDialog/style.css +5 -0
- package/design-system/components/Cover/preview.html +3 -3
- package/design-system/components/Cover/style.css +19 -0
- package/design-system/components/DateInput/README.md +77 -12
- package/design-system/components/DateInput/preview.html +27 -12
- package/design-system/components/DateInput/style.css +38 -0
- package/design-system/components/Dialog/README.md +112 -44
- package/design-system/components/Dialog/preview.html +141 -18
- package/design-system/components/Dialog/style.css +74 -0
- package/design-system/components/EmptyState/README.md +42 -12
- package/design-system/components/EmptyState/preview.html +11 -11
- package/design-system/components/EmptyState/style.css +9 -0
- package/design-system/components/EntryShell/README.md +73 -48
- package/design-system/components/EntryShell/preview.html +60 -27
- package/design-system/components/EntryShell/style.css +19 -0
- package/design-system/components/FeatureGrid/README.md +61 -39
- package/design-system/components/FeatureGrid/preview.html +2 -2
- package/design-system/components/FeatureGrid/style.css +20 -0
- package/design-system/components/FileUpload/README.md +33 -3
- package/design-system/components/FileUpload/preview.html +18 -4
- package/design-system/components/FileUpload/style.css +23 -0
- package/design-system/components/FilterBar/README.md +114 -0
- package/design-system/components/FilterBar/preview.html +82 -0
- package/design-system/components/FilterBar/style.css +22 -0
- package/design-system/components/Fold/README.md +84 -26
- package/design-system/components/Fold/preview.html +77 -34
- package/design-system/components/Fold/style.css +48 -0
- package/design-system/components/Footer/README.md +62 -39
- package/design-system/components/Footer/preview.html +5 -5
- package/design-system/components/Footer/style.css +30 -0
- package/design-system/components/FunnelBars/README.md +24 -3
- package/design-system/components/FunnelBars/preview.html +5 -5
- package/design-system/components/FunnelBars/style.css +13 -0
- package/design-system/components/GoalBars/README.md +54 -10
- package/design-system/components/GoalBars/preview.html +69 -28
- package/design-system/components/GoalBars/style.css +51 -0
- package/design-system/components/GoalTicks/README.md +74 -58
- package/design-system/components/GoalTicks/preview.html +41 -118
- package/design-system/components/GoalTicks/style.css +37 -0
- package/design-system/components/GoalTubes/README.md +29 -3
- package/design-system/components/GoalTubes/preview.html +6 -6
- package/design-system/components/GoalTubes/style.css +23 -0
- package/design-system/components/Heatmap/README.md +133 -0
- package/design-system/components/Heatmap/preview.html +168 -0
- package/design-system/components/Heatmap/style.css +119 -0
- package/design-system/components/Hero/README.md +58 -40
- package/design-system/components/Hero/preview.html +1 -1
- package/design-system/components/Hero/style.css +19 -0
- package/design-system/components/HoverCard/README.md +114 -0
- package/design-system/components/HoverCard/preview.html +107 -0
- package/design-system/components/HoverCard/style.css +59 -0
- package/design-system/components/IconButton/README.md +69 -38
- package/design-system/components/IconButton/preview.html +77 -43
- package/design-system/components/IconButton/style.css +45 -0
- package/design-system/components/Input/README.md +36 -11
- package/design-system/components/Input/preview.html +1 -1
- package/design-system/components/Input/style.css +23 -0
- package/design-system/components/KanbanBoard/README.md +93 -45
- package/design-system/components/KanbanBoard/preview.html +159 -43
- package/design-system/components/KanbanBoard/style.css +53 -0
- package/design-system/components/Kbd/README.md +25 -9
- package/design-system/components/Kbd/preview.html +6 -2
- package/design-system/components/Kbd/style.css +9 -0
- package/design-system/components/KitButton/README.md +81 -47
- package/design-system/components/KitButton/preview.html +35 -13
- package/design-system/components/KitButton/style.css +46 -0
- package/design-system/components/KitCard/README.md +75 -44
- package/design-system/components/KitCard/preview.html +18 -10
- package/design-system/components/KitCard/style.css +15 -0
- package/design-system/components/KitInput/README.md +54 -39
- package/design-system/components/KitInput/preview.html +7 -7
- package/design-system/components/KitInput/style.css +23 -0
- package/design-system/components/Leaderboard/README.md +76 -49
- package/design-system/components/Leaderboard/preview.html +61 -26
- package/design-system/components/Leaderboard/style.css +44 -0
- package/design-system/components/ListDetail/README.md +222 -0
- package/design-system/components/ListDetail/preview.html +213 -0
- package/design-system/components/ListDetail/style.css +148 -0
- package/design-system/components/LoadBar/README.md +79 -0
- package/design-system/components/LoadBar/preview.html +40 -0
- package/design-system/components/LoadBar/style.css +17 -0
- package/design-system/components/MarketingNav/README.md +76 -42
- package/design-system/components/MarketingNav/preview.html +37 -8
- package/design-system/components/MarketingNav/style.css +45 -0
- package/design-system/components/Matrix/README.md +129 -0
- package/design-system/components/Matrix/preview.html +99 -0
- package/design-system/components/Matrix/style.css +84 -0
- package/design-system/components/Menu/README.md +117 -41
- package/design-system/components/Menu/preview.html +85 -23
- package/design-system/components/Menu/style.css +61 -0
- package/design-system/components/Meter/README.md +39 -4
- package/design-system/components/Meter/preview.html +18 -1
- package/design-system/components/Meter/style.css +23 -0
- package/design-system/components/MetricTile/README.md +237 -0
- package/design-system/components/MetricTile/preview.html +241 -0
- package/design-system/components/MetricTile/style.css +129 -0
- package/design-system/components/Morph/README.md +106 -0
- package/design-system/components/Morph/preview.html +103 -0
- package/design-system/components/Morph/style.css +31 -0
- package/design-system/components/Motion/README.md +164 -0
- package/design-system/components/Motion/preview.html +2537 -0
- package/design-system/components/NumberInput/README.md +27 -8
- package/design-system/components/NumberInput/preview.html +21 -5
- package/design-system/components/NumberInput/style.css +34 -0
- package/design-system/components/PaceBar/README.md +75 -0
- package/design-system/components/PaceBar/preview.html +67 -0
- package/design-system/components/PaceBar/style.css +25 -0
- package/design-system/components/Page/README.md +57 -18
- package/design-system/components/Page/preview.html +15 -17
- package/design-system/components/Page/style.css +7 -0
- package/design-system/components/PageBar/README.md +90 -34
- package/design-system/components/PageBar/preview.html +60 -19
- package/design-system/components/PageBar/style.css +35 -0
- package/design-system/components/PageHero/README.md +87 -51
- package/design-system/components/PageHero/preview.html +35 -6
- package/design-system/components/PageHero/style.css +31 -0
- package/design-system/components/Pagination/README.md +70 -49
- package/design-system/components/Pagination/preview.html +24 -15
- package/design-system/components/Pagination/style.css +12 -0
- package/design-system/components/Panel/README.md +109 -51
- package/design-system/components/Panel/preview.html +118 -20
- package/design-system/components/Panel/style.css +51 -0
- package/design-system/components/PasswordInput/README.md +50 -18
- package/design-system/components/PasswordInput/preview.html +71 -21
- package/design-system/components/PasswordInput/style.css +31 -0
- package/design-system/components/Plate/README.md +75 -17
- package/design-system/components/Plate/preview.html +40 -7
- package/design-system/components/Plate/style.css +37 -0
- package/design-system/components/Popover/README.md +70 -49
- package/design-system/components/Popover/preview.html +44 -22
- package/design-system/components/Popover/style.css +41 -0
- package/design-system/components/PricingTable/README.md +69 -49
- package/design-system/components/PricingTable/preview.html +21 -21
- package/design-system/components/PricingTable/style.css +21 -0
- package/design-system/components/ProgressPetals/README.md +31 -3
- package/design-system/components/ProgressPetals/preview.html +14 -15
- package/design-system/components/ProgressPetals/style.css +27 -0
- package/design-system/components/README.md +151 -0
- package/design-system/components/Radio/README.md +40 -17
- package/design-system/components/Radio/preview.html +16 -1
- package/design-system/components/Radio/style.css +21 -0
- package/design-system/components/RankBar/README.md +29 -2
- package/design-system/components/RankBar/preview.html +14 -12
- package/design-system/components/RankBar/style.css +18 -0
- package/design-system/components/Ring/README.md +61 -11
- package/design-system/components/Ring/preview.html +55 -10
- package/design-system/components/Ring/style.css +49 -0
- package/design-system/components/ScoreHero/README.md +91 -0
- package/design-system/components/ScoreHero/preview.html +104 -0
- package/design-system/components/ScoreHero/style.css +32 -0
- package/design-system/components/Section/README.md +72 -33
- package/design-system/components/Section/preview.html +46 -16
- package/design-system/components/Section/style.css +18 -0
- package/design-system/components/Segmented/README.md +100 -55
- package/design-system/components/Segmented/preview.html +107 -26
- package/design-system/components/Segmented/style.css +94 -0
- package/design-system/components/SegmentedProgress/README.md +64 -0
- package/design-system/components/SegmentedProgress/preview.html +69 -0
- package/design-system/components/SegmentedProgress/style.css +11 -0
- package/design-system/components/Select/README.md +47 -12
- package/design-system/components/Select/preview.html +28 -2
- package/design-system/components/Select/style.css +22 -0
- package/design-system/components/ShareBar/README.md +69 -0
- package/design-system/components/ShareBar/preview.html +72 -0
- package/design-system/components/ShareBar/style.css +25 -0
- package/design-system/components/SideList/README.md +147 -0
- package/design-system/components/SideList/preview.html +139 -0
- package/design-system/components/SideList/style.css +94 -0
- package/design-system/components/Skeleton/README.md +53 -16
- package/design-system/components/Skeleton/preview.html +35 -23
- package/design-system/components/Skeleton/style.css +17 -0
- package/design-system/components/Slider/README.md +95 -0
- package/design-system/components/Slider/preview.html +49 -0
- package/design-system/components/Slider/style.css +13 -0
- package/design-system/components/Split/README.md +112 -0
- package/design-system/components/Split/preview.html +105 -0
- package/design-system/components/Split/style.css +30 -0
- package/design-system/components/Starter/README.md +21 -9
- package/design-system/components/Starter/preview.html +5 -5
- package/design-system/components/Stat/README.md +64 -43
- package/design-system/components/Stat/preview.html +3 -3
- package/design-system/components/Stat/style.css +15 -0
- package/design-system/components/StatTiles/README.md +88 -44
- package/design-system/components/StatTiles/preview.html +142 -71
- package/design-system/components/StatTiles/style.css +64 -0
- package/design-system/components/StatusLine/README.md +85 -0
- package/design-system/components/StatusLine/preview.html +49 -0
- package/design-system/components/StatusLine/style.css +14 -0
- package/design-system/components/StatusScreen/README.md +49 -35
- package/design-system/components/StatusScreen/preview.html +20 -5
- package/design-system/components/StatusScreen/style.css +9 -0
- package/design-system/components/StepLine/README.md +97 -0
- package/design-system/components/StepLine/preview.html +108 -0
- package/design-system/components/StepLine/style.css +62 -0
- package/design-system/components/Stepper/README.md +35 -13
- package/design-system/components/Stepper/style.css +13 -0
- package/design-system/components/StreakCalendar/README.md +22 -1
- package/design-system/components/StreakCalendar/preview.html +10 -10
- package/design-system/components/StreakCalendar/style.css +12 -0
- package/design-system/components/SuggestionChip/README.md +87 -0
- package/design-system/components/SuggestionChip/preview.html +42 -0
- package/design-system/components/SuggestionChip/style.css +20 -0
- package/design-system/components/Switch/README.md +44 -24
- package/design-system/components/Switch/preview.html +23 -8
- package/design-system/components/Switch/style.css +31 -0
- package/design-system/components/Table/README.md +129 -58
- package/design-system/components/Table/preview.html +106 -72
- package/design-system/components/Table/style.css +104 -0
- package/design-system/components/Tabs/README.md +71 -46
- package/design-system/components/Tabs/preview.html +56 -24
- package/design-system/components/Tabs/style.css +44 -0
- package/design-system/components/Testimonial/README.md +48 -32
- package/design-system/components/Testimonial/preview.html +14 -14
- package/design-system/components/Testimonial/style.css +12 -0
- package/design-system/components/TextArea/README.md +27 -11
- package/design-system/components/TextArea/preview.html +8 -2
- package/design-system/components/TextArea/style.css +12 -0
- package/design-system/components/ThemeSwitch/README.md +116 -0
- package/design-system/components/ThemeSwitch/preview.html +57 -0
- package/design-system/components/ThemeSwitch/style.css +6 -0
- package/design-system/components/TickRow/README.md +52 -36
- package/design-system/components/TickRow/preview.html +64 -41
- package/design-system/components/TickRow/style.css +23 -0
- package/design-system/components/TickStrip/README.md +95 -0
- package/design-system/components/TickStrip/preview.html +88 -0
- package/design-system/components/TickStrip/style.css +42 -0
- package/design-system/components/Tile/README.md +79 -18
- package/design-system/components/Tile/preview.html +91 -40
- package/design-system/components/Tile/style.css +36 -0
- package/design-system/components/Timeline/README.md +68 -48
- package/design-system/components/Timeline/preview.html +27 -15
- package/design-system/components/Timeline/style.css +25 -0
- package/design-system/components/Toast/README.md +70 -38
- package/design-system/components/Toast/preview.html +43 -8
- package/design-system/components/Toast/style.css +25 -0
- package/design-system/components/Tooltip/README.md +93 -35
- package/design-system/components/Tooltip/preview.html +69 -15
- package/design-system/components/Tooltip/style.css +78 -0
- package/design-system/components/TopBar/README.md +67 -53
- package/design-system/components/TopBar/preview.html +14 -27
- package/design-system/components/TopBar/style.css +35 -0
- package/design-system/components/TopicRail/README.md +108 -0
- package/design-system/components/TopicRail/preview.html +58 -0
- package/design-system/components/TopicRail/style.css +48 -0
- package/design-system/components/TrendBars/README.md +52 -14
- package/design-system/components/TrendBars/preview.html +65 -32
- package/design-system/components/TrendBars/style.css +25 -0
- package/design-system/components/TrendLine/README.md +164 -0
- package/design-system/components/TrendLine/preview.html +373 -0
- package/design-system/components/TrendLine/style.css +155 -0
- package/design-system/components/Well/README.md +64 -22
- package/design-system/components/Well/preview.html +14 -14
- package/design-system/components/Well/style.css +22 -0
- package/design-system/components/_house.css +324 -0
- package/design-system/components/bundle.css +4086 -744
- package/design-system/tokens.json +1310 -124
- package/dist/fello-core.css +2 -2
- package/dist/fello.css +6 -1369
- package/dist/fello.scoped.css +7 -0
- package/dist/index.d.ts +109 -10
- package/dist/index.js +781 -96
- package/dist/palettes.d.ts +464 -0
- package/dist/palettes.js +497 -0
- package/dist/scoped.d.ts +3 -0
- package/dist/scoped.js +16 -0
- package/dist/toast.d.ts +14 -0
- package/dist/toast.js +33 -29
- package/dist/tokens.d.ts +1686 -62
- package/dist/tokens.js +1668 -61
- package/package.json +20 -4
- package/scripts/check-palette.mjs +295 -0
- package/scripts/token-model.mjs +552 -0
- package/tokens/_dark.css +173 -0
- package/tokens/_palettes.css +46 -0
- package/tokens/_product.css +266 -53
- package/tokens/_source.hubl.css +39 -19
- package/tokens/design-tokens.json +319 -0
- package/tokens/palettes.ts +504 -0
- package/tokens/shadcn-compat.css +19 -19
- package/tokens/shadcn-compat.hsl.css +76 -0
- package/tokens/tokens.css +1287 -62
- package/tokens/tokens.md +587 -61
- package/tokens/tokens.root.css +1293 -62
- package/tokens/tokens.ts +1677 -64
|
@@ -1,58 +1,341 @@
|
|
|
1
1
|
# Motion
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Seth's motion, taken from his North app and named by role (D7). Things grow out of where they were and go back the same
|
|
4
|
+
way, quicker. The frame moves first; its details settle after. Hover is a colour, never a lift. Under reduced motion
|
|
5
|
+
everything is still.
|
|
5
6
|
|
|
6
|
-
##
|
|
7
|
+
## The rule
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
**Motion comes from the kit.** Build with the component's markup and classes and it already moves: the press, the
|
|
10
|
+
sliding indicators, the folds, the enters and exits are in `fello.css`, on Seth's springs. Never type a duration, a
|
|
11
|
+
curve, a `cubic-bezier()`, a spring or a `@keyframes` by hand, and never restyle a kit element's transition.
|
|
12
|
+
|
|
13
|
+
When a part is genuinely your own (nothing in the catalog has it), it still moves on the kit's role tokens, inside
|
|
14
|
+
`@media (prefers-reduced-motion: no-preference)`:
|
|
15
|
+
|
|
16
|
+
- **A spring for what the person drives** (a press, the pointer, a choice, a panel): `--ws-spring-<name>` over
|
|
17
|
+
`--ws-spring-<name>-duration`, always the pair. Each is Seth's spring written out as a CSS `linear()` curve, its own
|
|
18
|
+
small overshoot kept, and the time it takes to settle. A spring can be interrupted and picks up from where it is.
|
|
19
|
+
- **A duration and a curve for what the system plays** (a draw, a build, a loop): `--ws-duration-*` and
|
|
20
|
+
`--ws-ease-*` (Role tokens, below).
|
|
21
|
+
|
|
22
|
+
```css
|
|
23
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
24
|
+
.my-thumb { transition: translate var(--ws-spring-indicator-duration) var(--ws-spring-indicator); }
|
|
25
|
+
.my-note { animation: ws-settle var(--ws-duration-settle) var(--ws-ease-soft) backwards; }
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
In React with the motion library, the same springs are presets: `import { springs, eases } from
|
|
30
|
+
'@felloinnovations/brand-kit/tokens'` (`transition={springs.press}`), and every motion tree sits in
|
|
31
|
+
`<MotionConfig reducedMotion="user">`.
|
|
32
|
+
|
|
33
|
+
## By situation
|
|
34
|
+
|
|
35
|
+
### Hover
|
|
36
|
+
|
|
37
|
+
A colour, never a lift: no shadow, rise or grow on hover. Kit controls and rows carry their own wash; anything of yours
|
|
38
|
+
takes `.ws-hover-tint` (`--faint` for a list row, the default for a nav or menu row, `--strong` for an icon button or a
|
|
39
|
+
quiet act). It turns over `--ws-duration-hover` (200 ms) on `--ws-ease-soft`, only where a pointer hovers
|
|
40
|
+
(`@media (hover: hover)`), so a tap never leaves it on. Why: a colour answers the pointer without moving the layout; a
|
|
41
|
+
lift says "this floats", and a control does not. What hover reveals (a close, an arrow, a row's acts) also shows on
|
|
42
|
+
`:focus-visible` and on a tap; an arrow may step forward by `--ws-nudge`.
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<li class="lead-row ws-hover-tint ws-hover-tint--faint">...</li>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Press
|
|
49
|
+
|
|
50
|
+
`.ws-btn`, `.ws-icon-btn`, `.ws-suggestion-chip` and a chip that acts (`button.ws-chip`, `a.ws-chip`) give under a
|
|
51
|
+
press and spring back, on `--ws-spring-press` (Seth's "Button press (mic, add)"): to `--ws-press-scale` (0.97), a round
|
|
52
|
+
act (`ws-icon-btn--round`, `.ws-press--round`) to 0.94, the send act (`.ws-press--send`) to 0.92. Their colours turn at
|
|
53
|
+
once going in and over `--ws-duration-hover` coming out. Words that act (`--link`, `--text`), a disabled control and a
|
|
54
|
+
busy one do not move. Rows, list rows, menu rows and cards never scale: a press tints them a step darker
|
|
55
|
+
(`--ws-surface-press`). Why: the spring's small give says "pressed" without changing the layout, and it rides `scale`,
|
|
56
|
+
so the control's own transform is untouched. Your own pressable thing adds `.ws-press`.
|
|
57
|
+
|
|
58
|
+
```html
|
|
59
|
+
<button type="button" class="report-tile ws-press">Open the report</button>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### A choice moving: sliding indicators
|
|
63
|
+
|
|
64
|
+
When the choice changes, its mark slides from the old item to the new one instead of jumping. No script and no extra
|
|
65
|
+
markup: the chosen item is a CSS anchor and the track's own pseudo-element slides to it. Mark the choice the way the
|
|
66
|
+
component's README says and it moves.
|
|
67
|
+
|
|
68
|
+
| Component | What slides | Spring (Seth's label) |
|
|
9
69
|
| --- | --- | --- |
|
|
10
|
-
| `
|
|
11
|
-
| `
|
|
12
|
-
| `
|
|
13
|
-
| `
|
|
14
|
-
| `ws-duration-instant` | 120 ms | hover, press, focus, a chip flipping, a dialog's exit |
|
|
15
|
-
| `ws-duration-gentle` | 200 ms | the default: a row or card arriving, a menu, a drawer leaving |
|
|
16
|
-
| `ws-duration-settle` | 320 ms | a pane, dialog or drawer in, a screen changing, a pop, a tile rising |
|
|
17
|
-
| `ws-duration-calm` | 420 ms | content replacing a skeleton, a chart drawing, a figure counting |
|
|
18
|
-
| `ws-stagger` | 30 ms (40 slow), at most 6 items | a list's first paint only |
|
|
19
|
-
| `ws-sweep` | 220 ms | a chart's parts filling first to last |
|
|
20
|
-
| `ws-rise` | 6 px | how far things rise as they arrive (the person's message 12) |
|
|
21
|
-
| `ws-press-scale` | 0.97 | a control under a press; 1 with reduced motion |
|
|
22
|
-
| `ws-loop` / `ws-loop-slow` | 1.2 s / 2.4 s | the working beat; a big quiet area's |
|
|
70
|
+
| `Segmented` | the thumb | `--ws-spring-indicator` ("Toggle pill slide") |
|
|
71
|
+
| `Tabs` | the underline | `--ws-spring-tab` ("Department card underline") |
|
|
72
|
+
| `AppShell` | the sidebar's current-row pill | `--ws-spring-nav` ("Sidebar active row slide") |
|
|
73
|
+
| `SideList`, `ListDetail` | the selected row's fill | `--ws-spring-highlight` ("List highlight slide") |
|
|
23
74
|
|
|
24
|
-
|
|
75
|
+
Only a real choice moves it: at rest the chosen item paints its own ground, and the slide takes over while the track is
|
|
76
|
+
pointed at or holds focus, so a resize or a late font lands at once. Why a spring: the person drives it, and a second
|
|
77
|
+
click mid-slide turns it from where it is.
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<div class="ws-segmented" role="group" aria-label="View">
|
|
81
|
+
<button type="button" class="ws-segmented__item" aria-pressed="true">Bars</button>
|
|
82
|
+
<button type="button" class="ws-segmented__item" aria-pressed="false">Line</button>
|
|
83
|
+
</div>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Something opening in place: folds
|
|
87
|
+
|
|
88
|
+
What opens in place grows from nothing to its height and fades in, then closes back the same way, on `--ws-spring-fold`
|
|
89
|
+
(Seth's "Sidebar sections open / close", no bounce); a chevron turns on the same spring. Every kit `<details>` does it
|
|
90
|
+
on its own (`Fold`, or any `<details>` inside a kit element). A body your script shows and hides with the `hidden`
|
|
91
|
+
attribute wears `.ws-unfold` (as `CheckRow`'s detail does), and its padding and margins grow with it, so nothing
|
|
92
|
+
jumps. Why: what sits below is pushed down smoothly instead of leaping, and the person sees where the new part came
|
|
93
|
+
from.
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<button type="button" aria-expanded="false" aria-controls="why">Why this move</button>
|
|
97
|
+
<div class="ws-unfold" id="why" hidden>...</div>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Something appearing over the page: enters and exits
|
|
101
|
+
|
|
102
|
+
It grows out of what opened it and goes back there, **quicker**: every exit is shorter than its entrance. Why: the eye
|
|
103
|
+
follows cause to effect on the way in; on the way out the person has already moved on.
|
|
104
|
+
|
|
105
|
+
| Component | Enters | Leaves | How the exit gets to play |
|
|
106
|
+
| --- | --- | --- | --- |
|
|
107
|
+
| `Menu`, `Popover` | out of the corner it hangs from, 4 px toward its control, from `--ws-open-scale` (0.97), on `--ws-spring-settle` ("Messages and steps settle") | back into that corner over `--ws-duration-exit` (120 ms) on `--ws-ease-exit` | a native `popover`: `@starting-style` and `allow-discrete` keep its box while it leaves, and a close mid-entrance turns back. Mounted by the app: `data-leaving`, then remove it |
|
|
108
|
+
| `Dialog` | the scrim fades; the window rises 14 px out of `--ws-open-scale-pane` (0.98) on `--ws-spring-settle`, its parts settling in after it | 8 px down over `--ws-duration-exit` | a native `<dialog>` (`showModal()`, `close()`), the same way. A drawer slides in from its edge over `--ws-duration-grow` on `--ws-ease-grow` and back over `--ws-duration-shrink` |
|
|
109
|
+
| `Toast` | up out of `--ws-open-scale-toast` (0.96) on `--ws-spring-settle` | 4 px down over `--ws-duration-exit` | `data-leaving`, then remove it |
|
|
110
|
+
| `Tooltip` | pops from 0.9, 4 px toward its control, on `--ws-spring-pop` ("Tooltip pop-in"), after the 40 ms hover intent; at once on keyboard focus | fades off over 180 ms | CSS alone: hover, focus or `ws-tooltip--open` |
|
|
111
|
+
| `HoverCard` | pops from 0.9 on `--ws-spring-pop`, its rows settling 45 ms apart; `--follow` glides after the pointer on `--ws-spring-follow`, which never bounces | to `--ws-pop-scale` over `--ws-duration-exit` | `data-leaving`, then remove it |
|
|
112
|
+
| `Panel`, `ChatShell` | out of 0.97 from the edge it docks to, out of an 8 px blur, on `--ws-spring-panel` ("Opens / moves / docks") | back over 160 ms | `data-leaving` (or `ws-panel--leaving`), then remove it |
|
|
113
|
+
|
|
114
|
+
An element the app mounts and unmounts keeps its node until its exit has played. Wait on its own animations, never a
|
|
115
|
+
number of your own (under reduced motion there are none, so it goes at once):
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
toast.dataset.leaving = '';
|
|
119
|
+
Promise.allSettled(toast.getAnimations().map((a) => a.finished)).then(() => toast.remove());
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### A card going full screen, or the chat changing mode: `morph()`
|
|
123
|
+
|
|
124
|
+
A thing that changes its place or size goes there as itself, never as a copy sliding in. `morph(update, { as, el })`
|
|
125
|
+
runs your class or state change as a view transition on Seth's curve for `as`: `full` (a chat card to full screen and
|
|
126
|
+
back, `--ws-duration-morph` on `--ws-ease-morph`), `grow` and `shrink` (a tile opening across its row over
|
|
127
|
+
`--ws-duration-grow`, closing back over the quicker `--ws-duration-shrink`, both on `--ws-ease-grow`), `shift` (the chat
|
|
128
|
+
between bar, docked and full, `--ws-duration-shift` on `--ws-ease-shift`). Words never scale: they ride in the frame's
|
|
129
|
+
corner, fade off and fade back. `full` also lifts the element into the top layer, so it covers the whole window from
|
|
130
|
+
inside any ancestor, moves focus in, and Escape (or its own Back button) brings it home. Why: the person sees the card
|
|
131
|
+
they tapped become the full screen, and finds it again in its place when it closes.
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { morph } from '@felloinnovations/brand-kit';
|
|
135
|
+
morph(() => card.classList.toggle('ws-chat-card--full'), { as: 'full', el: card });
|
|
136
|
+
morph(() => flushSync(() => setMode('docked')), { as: 'shift', el: shellRef.current }); // React: flush inside
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### A list reordering: `reorder()`
|
|
25
140
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- Nothing loops on its own except the working signal (typing dots, a pressed button's dot, a live face's ring, an
|
|
34
|
-
indeterminate bar), all on `ws-loop`.
|
|
35
|
-
- Reduced motion: keyframes do not run, presses do not scale, dialogs cross-fade, folds snap, scrolling is instant, figures
|
|
36
|
-
show their value, a chart shows its final figure drawn.
|
|
141
|
+
Rows that change places glide to their new places instead of jumping: a sort, a filter, a card dropped in another
|
|
142
|
+
column. `reorder(update, within)` snapshots the rows before and after your update and moves each as one piece on
|
|
143
|
+
`--ws-spring-reorder` (Seth's "List rows reorder", no bounce); a row that arrives or leaves fades, and a card that
|
|
144
|
+
changes column flies above the ones it passes. It knows the kit's rows (`KanbanBoard` cards, `ListDetail` rows,
|
|
145
|
+
`SideList` picks); pass a selector as the third argument for others. Give each row an `id` or `data-key` so it is
|
|
146
|
+
followed across a re-render. Why: the person keeps their place in the list and sees where each row went. A stagger
|
|
147
|
+
never replays on a re-filter: rows that stay reorder in place.
|
|
37
148
|
|
|
38
|
-
|
|
149
|
+
```ts
|
|
150
|
+
import { reorder } from '@felloinnovations/brand-kit';
|
|
151
|
+
reorder(() => flushSync(() => setRows(sorted)), listRef.current);
|
|
152
|
+
```
|
|
39
153
|
|
|
40
|
-
|
|
154
|
+
### Build-in (a dashboard on arrival)
|
|
41
155
|
|
|
42
|
-
|
|
156
|
+
Amit, 5 Nov 2026: North's Home intro is the kit's default for every dashboard, not North's alone. A page or a section
|
|
157
|
+
of cards wears `.ws-build`; each card in it wears `.ws-build__card` with `--ws-i` (0, 1, 2 ... in reading order).
|
|
158
|
+
|
|
159
|
+
- **The cards** rise in (`ws-rise`: 6 px and a fade, 320 ms on `settle`), each 70 ms after the one before
|
|
160
|
+
(`ws-stagger-part`; North's cards are 71 ms apart, a .21 share of its 1.7 s rail). A card's start is
|
|
161
|
+
`--ws-build-at` (`--ws-i` x 70 ms).
|
|
162
|
+
- **The charts in a card** that carry their draw (`--draw` on a `MetricTile`, `SideList`, `PaceBar`, `GoalBars`,
|
|
163
|
+
`TickStrip`, `TickRow`, `ShareBar`, `StepLine`; `.ws-ring__value--draw`; `--build` on a `Heatmap`; `ws-grow-up`
|
|
164
|
+
on `TrendBars` and `GoalTubes`) add `--ws-build-at` to their own delays, so each draws as its card lands. A tile's
|
|
165
|
+
columns grow from the baseline one after another, its line draws left to right and its dots pop, then its foot's
|
|
166
|
+
figure rises in; a goal list's bars fill in order. Those two run over the card's share of `ws-duration-fill-page`
|
|
167
|
+
(1343 ms, North's "Metric + goal bars fill"); every other chart keeps its own draw (900 ms in a card).
|
|
168
|
+
- **When**: on arrival, once. Where the browser has scroll-triggered animation (a `timeline-trigger` on the card's own
|
|
169
|
+
`view()` timeline, `animation-trigger: play-once`), a card waits, hidden, until a tenth of it has come into view and
|
|
170
|
+
then plays; scrolling back never replays it. Elsewhere it all plays on first paint, so a card below the fold has
|
|
171
|
+
finished, its final state, by the time it is reached. It is a scroll trigger, not a scroll-driven timeline: the
|
|
172
|
+
build plays in time and is never scrubbed by the scroll.
|
|
173
|
+
- **Budget**: the first screen's build, cards and draws, stays under `ws-duration-build` (2400 ms). Number the cards
|
|
174
|
+
that arrive together from 0: a card below the fold plays when it is reached, so its `--ws-i` orders it only among the
|
|
175
|
+
cards that come into view with it (a row of tiles 0 to 3, the next row 0 to 3 again).
|
|
176
|
+
- **What stays still**: hover is still a tint (a tile's frame darkens, its arrow steps); a headline figure shows its
|
|
177
|
+
value at once (it never counts); a re-filter or a resize replays nothing. A fresh element builds in again, so an
|
|
178
|
+
app keeps its cards' elements (stable keys) when only their numbers change.
|
|
179
|
+
- **Reduced motion**: no build. Every card and chart is in its final state from the first frame.
|
|
180
|
+
- North's cards also arrive at 1.15 and shrink to their place; the kit leaves the scale out (a card larger than its
|
|
181
|
+
column pushes a phone's page sideways while it lands) and keeps North's curve, stagger and draws.
|
|
182
|
+
|
|
183
|
+
```html
|
|
184
|
+
<section class="ws-build">
|
|
185
|
+
<div class="ws-metric-tiles"><div class="ws-metric-tiles__grid">
|
|
186
|
+
<button type="button" class="ws-metric-tile ws-metric-tile--draw ws-build__card" style="--ws-i: 0;" aria-label="...">...</button>
|
|
187
|
+
<button type="button" class="ws-metric-tile ws-metric-tile--draw ws-build__card" style="--ws-i: 1;" aria-label="...">...</button>
|
|
188
|
+
</div></div>
|
|
189
|
+
<div class="ws-side-list ws-side-list--draw ws-build__card" style="--ws-i: 2;">...</div>
|
|
190
|
+
<section class="ws-card ws-build__card" style="--ws-i: 3;">... <div class="ws-pace-bar ws-pace-bar--draw">...</div></section>
|
|
191
|
+
</section>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Loading
|
|
195
|
+
|
|
196
|
+
Content on its way is a ghost the size of what it stands for with the shimmer passing over it: one quiet tone, the
|
|
197
|
+
ghost grey and a lighter pass of the same grey, never a chart hue (`Skeleton`, or `.ws-shimmer` on a block of your own:
|
|
198
|
+
every `--ws-loop-shimmer`, 1.8 s, on `--ws-ease-shimmer`), never a spinner. When the content lands, its details settle in top to bottom (`.ws-settle` with `--ws-i` on each, 22 ms
|
|
199
|
+
apart). An answer at work shows a `StatusLine`; a long load with no figure a `LoadBar`; a pressed button waiting keeps
|
|
200
|
+
its width and shows its working dot on `--ws-loop`. Why: the layout is already in place, so nothing jumps when the real
|
|
201
|
+
thing arrives. Under reduced motion the shimmer stops on its ghost and the words say what is loading.
|
|
202
|
+
|
|
203
|
+
```html
|
|
204
|
+
<div class="ws-skeleton ws-skeleton--line" aria-hidden="true"></div>
|
|
205
|
+
<p class="ws-settle" style="--ws-i: 0;">Your calls this week</p>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Charts drawing
|
|
209
|
+
|
|
210
|
+
A chart builds in when it arrives: its `--draw` variant (the list under Build-in) or, for `TrendLine`, on its own. A
|
|
211
|
+
draw is one progress: marks start at their share (mark `i` of `n` at `i / (n - 1) x 0.55` of the draw) and ease on
|
|
212
|
+
`--ws-ease-settle`; values written in the chart follow it. A chart draws over `--ws-duration-draw` (900 ms) in a card,
|
|
213
|
+
`--ws-duration-draw-chat` in the chat, and over its card's share of `--ws-duration-fill-page` in a `.ws-build`. Why: one
|
|
214
|
+
sweep reads as the data arriving; marks sliding in from an edge read as noise.
|
|
215
|
+
|
|
216
|
+
- **On hover** the hovered column's band slides over `--ws-duration-settle`; the rest dims to `--ws-dim`; a hovered
|
|
217
|
+
tick or wedge grows to `--ws-grow-scale` from its base.
|
|
218
|
+
- **Bars to a line** (`TrendLine`): the columns collapse into their tops on `--ws-spring-morph-chart` ("Bars to line
|
|
219
|
+
morph") while the line draws left to right; back, they grow down from the dots. Switch the class; the CSS does the
|
|
220
|
+
rest.
|
|
221
|
+
- **A headline figure never counts up**: it shows its value.
|
|
222
|
+
- **Nothing that carries data loops.**
|
|
223
|
+
|
|
224
|
+
```html
|
|
225
|
+
<div class="ws-goal-bars ws-goal-bars--draw">...</div>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Which spring, when
|
|
229
|
+
|
|
230
|
+
From `motion.springs` in `tokens/design-tokens.json`: Seth's tuned springs, each as `--ws-spring-<name>` and
|
|
231
|
+
`--ws-spring-<name>-duration` in CSS and `springs.<name>` in JS. Reach for the one whose label matches the move; the
|
|
232
|
+
components already use theirs.
|
|
233
|
+
|
|
234
|
+
| Spring | Seth's label | For |
|
|
43
235
|
| --- | --- | --- |
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
236
|
+
| `press` | Button press (mic, add) | a button or chip under a press (house press) |
|
|
237
|
+
| `follow` | Tooltip follows cursor | something trailing the pointer; never bounces (`HoverCard --follow`) |
|
|
238
|
+
| `pop` | Tooltip pop-in | a tip or a hover card popping in (`Tooltip`, `HoverCard`) |
|
|
239
|
+
| `settle` | Messages and steps settle | menus, popovers, dialogs, toasts, a message settling |
|
|
240
|
+
| `fold` | Sidebar sections open / close | a height opening or closing, and its chevron (`<details>`, `.ws-unfold`) |
|
|
241
|
+
| `indicator` | Toggle pill slide | a segmented thumb (`Segmented`) |
|
|
242
|
+
| `tab` | Department card underline | a tab's underline (`Tabs`) |
|
|
243
|
+
| `nav` | Sidebar active row slide | the sidebar's current pill (`AppShell`) |
|
|
244
|
+
| `highlight` | List highlight slide | a list's selected fill (`SideList`, `ListDetail`) |
|
|
245
|
+
| `reorder` | List rows reorder | rows moving to new places (`reorder()`) |
|
|
246
|
+
| `tile` | Tile grows open / closes | a heatmap square opening (`Heatmap`) |
|
|
247
|
+
| `mark` | Pace dot on an opened square | a small mark popping in (`Heatmap`) |
|
|
248
|
+
| `panel` | Opens / moves / docks (spring) | a panel or the chat opening, moving, docking (`Panel`, `ChatShell`) |
|
|
249
|
+
| `card` | Chart card arrives | a chart card arriving in the thread (`ChatCard`) |
|
|
250
|
+
| `glow`, `roll` | Focus glow; Placeholder roll | the composer's focus glow and rolling placeholder (`Composer`) |
|
|
251
|
+
| `morphChart` | Bars to line morph | a chart changing form (`TrendLine`) |
|
|
252
|
+
| `lane` | Department: lane detail opens / closes | a lane's detail opening (token only) |
|
|
253
|
+
| `lens` | Lens switch (chart swap) | one chart swapping for another inside an open tile (token only) |
|
|
254
|
+
| `swap` | Old chart out / new chart in | a board chart replaced by another (token only) |
|
|
255
|
+
| `flag` | Trend flag follows the pointer (spring) | a read-out following the pointer along a chart (token only) |
|
|
256
|
+
| `text` | Metric card text swap | a card's words swapping (token only) |
|
|
257
|
+
| `badge` | Nav count badge pop | a count badge popping when it changes (token only) |
|
|
258
|
+
| `chip` | Attention chip to card | a chip opening into its card (token only) |
|
|
259
|
+
| `orb` | Agent orb arriving | an agent's orb arriving (token only) |
|
|
260
|
+
| `default` | Anything not tuned | anything the person drives that no spring above fits |
|
|
261
|
+
|
|
262
|
+
"Token only": no kit component moves this way yet; build it on the token and report it as new.
|
|
263
|
+
|
|
264
|
+
## Role tokens
|
|
265
|
+
|
|
266
|
+
For your own part, by role. Values are in `tokens.md`.
|
|
267
|
+
|
|
268
|
+
| Duration | For |
|
|
269
|
+
| --- | --- |
|
|
270
|
+
| `--ws-duration-instant`, `--ws-duration-exit` (120 ms) | a press going in; every exit |
|
|
271
|
+
| `--ws-duration-hover` (200 ms) | hover colour, tint, edge and opacity; a scrim |
|
|
272
|
+
| `--ws-duration-text` (250 ms) | words changing colour, small fades |
|
|
273
|
+
| `--ws-duration-settle` (320 ms) | details settling in, a chart's hover band |
|
|
274
|
+
| `--ws-duration-reveal` (350 ms) | an underline growing, a bar's ground |
|
|
275
|
+
| `--ws-duration-shrink` (400 ms), `--ws-duration-grow` (550 ms) | a tile closing back; a tile or drawer growing open |
|
|
276
|
+
| `--ws-duration-morph` (450 ms), `--ws-duration-shift` (550 ms) | a shared element in flight; layout moving (docking, columns, the sidebar folding) |
|
|
277
|
+
| `--ws-duration-fill` (700 ms), `--ws-duration-draw` (900 ms) | a bar filling; a chart drawing in a card, a ring filling |
|
|
278
|
+
| `--ws-duration-draw-chat`, `--ws-duration-fill-page`, `--ws-duration-build` | a chart in the chat; a dashboard's charts; a page's whole build, at most |
|
|
279
|
+
|
|
280
|
+
| Curve | For |
|
|
281
|
+
| --- | --- |
|
|
282
|
+
| `--ws-ease-soft` | the default: content arriving, a hover, a fold |
|
|
283
|
+
| `--ws-ease-settle` | things that land and rest: a mark, a bar filling, a card building in |
|
|
284
|
+
| `--ws-ease-grow`, `--ws-ease-shift`, `--ws-ease-morph` | a shape changing size; layout moving; one element in flight |
|
|
285
|
+
| `--ws-ease-exit` | everything leaving |
|
|
286
|
+
| `--ws-ease-steady` | linear: a draw's overall progress, a live ring keeping pace |
|
|
287
|
+
| `--ws-ease-sweep`, `--ws-ease-commit` | a chart sweeping in the chat; a decisive one-shot (sending, a check mark) |
|
|
288
|
+
| `--ws-ease-shimmer`, `--ws-ease-loop`, `--ws-ease-ambient` | a loading sweep; every loop; the one slow brand sheen |
|
|
289
|
+
| `--ws-ease-pop`, `--ws-ease-lift` | overshoot, for marks under 24 px only |
|
|
290
|
+
|
|
291
|
+
Staggers: `--ws-stagger` (30 ms, a list's rows on first paint), `--ws-stagger-detail` (22 ms, details in an opening
|
|
292
|
+
part, `.ws-settle`), `--ws-stagger-row` (45 ms, a hover card's rows), `--ws-stagger-part` (70 ms, cards building in).
|
|
293
|
+
Loops: `--ws-loop` (the working dots), `--ws-loop-status`, `--ws-loop-shimmer`, `--ws-loop-slow`, `--ws-loop-ambient`
|
|
294
|
+
(the one ambient sheen, never on data). Distances: `--ws-nudge` (4 px), `--ws-rise` (6 px), `--ws-drop` (12 px);
|
|
295
|
+
`--ws-blur-arrive` (3 px) and `--ws-blur-panel` (8 px) on arrival.
|
|
296
|
+
|
|
297
|
+
## Rules
|
|
298
|
+
|
|
299
|
+
- **What may move**: transform, `scale`, `translate`, opacity, colour, a blur up to 8 px on arrival, `clip-path`, and a
|
|
300
|
+
shimmer's `background-position`. Size, padding and grid tracks move only in a fold, a dock, the sidebar folding or a
|
|
301
|
+
`morph()`; never on hover.
|
|
302
|
+
- **From where it belongs**: a tip from the edge nearest its mark, a menu from its corner, the chat from its mode's
|
|
303
|
+
edge, a tile out of its slot, a card out of its place in the thread and back to it.
|
|
304
|
+
- **Two phases**: the frame lands, then its details settle top to bottom (`.ws-settle`, `--ws-i` on each).
|
|
305
|
+
- **Interruptible**: a change picks up from where it is; animation never moves focus, and none blocks input except a
|
|
306
|
+
`morph()` for the length of its own move (the browser's rule for a view transition).
|
|
307
|
+
- **Overshoot** only on marks under 24 px and indicators, never a card, a panel, a field or words.
|
|
308
|
+
- **A stagger runs when content arrives** (first paint, an open, a new answer), never on a re-filter.
|
|
309
|
+
- **Never moves**: content below a chart while its card changes size, a field as it takes focus (the ring appears,
|
|
310
|
+
nothing else), anything during a resize drag, a scroll reset or a theme change (every surface turns at once).
|
|
311
|
+
|
|
312
|
+
## Reduced motion, and browsers without a feature
|
|
313
|
+
|
|
314
|
+
**Reduced motion is still: the final state, at once.** Under `prefers-reduced-motion: reduce` the kit's net makes every
|
|
315
|
+
transition and animation on a kit element instant: presses do not scale, indicators land, folds snap, menus and dialogs
|
|
316
|
+
appear and go, a dashboard shows its end, a chart its final drawing, a shimmer its still ghost (with a word: "Loading
|
|
317
|
+
your calls"), the working dot is still and its words say it. `morph()` and `reorder()` run the update at once (`full`
|
|
318
|
+
still lifts the card). Your own motion goes inside `@media (prefers-reduced-motion: no-preference)` so it is still too;
|
|
319
|
+
in React, `<MotionConfig reducedMotion="user">` turns the springs off.
|
|
320
|
+
|
|
321
|
+
**A browser without a feature shows the change at once**, never half-moved: without `linear()` the spring transitions
|
|
322
|
+
are dropped; without anchor positioning an indicator jumps to the choice; without `interpolate-size` or
|
|
323
|
+
`::details-content` a fold opens at once; without `@starting-style` a menu or dialog simply appears; without view
|
|
324
|
+
transitions `morph()` and `reorder()` just run the update; without scroll-triggered animation a `.ws-build` plays on
|
|
325
|
+
first paint, and a chart below the fold is whole when it is reached.
|
|
326
|
+
|
|
327
|
+
## See it
|
|
328
|
+
|
|
329
|
+
The `Motion` card (`components/Motion/preview.html`, hosted at
|
|
330
|
+
`https://brand-kit-site-production.up.railway.app/latest/components/Motion/preview.html`):
|
|
331
|
+
|
|
332
|
+
- **Try it**, the playground: a product screen built only from kit components, with a numbered hint at each move
|
|
333
|
+
(hover a card, press a button, switch Bars / Line, open the menu, open the chart full screen, fold a section, save
|
|
334
|
+
for a toast, open the drawer, move the chat, sort the list, replay the arrival) and a Slow motion switch that runs
|
|
335
|
+
everything four times slower.
|
|
336
|
+
- **Reference for developers**: 206 behaviours by Seth's own label, each with North's values, the kit's token, class
|
|
337
|
+
or helper, a live demo and how close the kit is (exact, close, JS helper, not yet).
|
|
338
|
+
|
|
339
|
+
Compare what you built against it, side by side. In the kit's repo, `node scripts/check-geometry.mjs --only <Name>
|
|
340
|
+
--hover` shoots each control at rest, hovered and focused, and flags a hover that lifts and anything still moving under
|
|
341
|
+
reduced motion; add `--motion` to run the same pass with motion on, which catches a lift that only plays then.
|
|
@@ -4,38 +4,61 @@ The audience skews older and mobile-heavy. These are floors, part of the definit
|
|
|
4
4
|
|
|
5
5
|
## Floors
|
|
6
6
|
|
|
7
|
-
- **Contrast**: 4.5:1 for words under 24 px (3:1 at 24 px or
|
|
8
|
-
mark that carries meaning.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
- **Contrast**: 4.5:1 for words under 24 px (3:1 at 24 px or 18.66 px bold and up), 3:1 for every border, focus ring,
|
|
8
|
+
icon or mark that carries meaning. Every word token is computed on all eight grounds (cream, white, plate, tray,
|
|
9
|
+
raised, shell, press, well) in light, night and the navy ground; the tables are in tokens.md and Colour. A word in a
|
|
10
|
+
tone uses the tone's word token, never the mark's tone (D2).
|
|
11
|
+
- **Focus**: every element that takes keyboard focus shows a 2 px navy ring 2 px outside it on `:focus-visible`
|
|
12
|
+
(`ws-focus-color`, `ws-focus-width`, `ws-focus-offset`; `shadow-focus-ring` is the same ring as a shadow). Inside a
|
|
13
|
+
dense row, a well, a list, a segmented track or a clipped container the same ring is drawn inside (`ws-focus-inset`).
|
|
14
|
+
Never `outline: none` without a visible replacement; a tint alone is not focus. The 2 px gap keeps the ring off a white
|
|
15
|
+
field. It is 12.3:1 on the cream and at least 10.2:1 on any light ground; in night at least 12.2:1 (D8).
|
|
16
|
+
- **Targets**: WCAG 2.2 (2.5.8, AA) asks 24 by 24 px or the spacing to match. The team's floors are higher, at every
|
|
17
|
+
pointer for words and on touch for boxes: 40 px for a boxed control on a touch screen (a button, a field, an icon
|
|
18
|
+
button through its hit area, a segmented item, a tab, a menu item, a date cell); 24 px tall for words that act; 44 px
|
|
19
|
+
for every act on a public page (`ws-touch-public`; `KitButton` large is 45). The kit's coarse-pointer block sets these;
|
|
20
|
+
a component's own min-height stays at or above them. A small face that acts gets 4 px of room round it.
|
|
12
21
|
- **Fields**: a white ground (`ws-field`) on the cream, a visible edge and a label above; a field that blends into the
|
|
13
|
-
page reads as no field. `autocomplete` and the right `type` on every field about the person (1.3.5).
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
page reads as no field. `autocomplete` and the right `type` on every field about the person (1.3.5). A checkbox's edge
|
|
23
|
+
at rest reaches 3:1.
|
|
24
|
+
- **Keyboard**: everything reachable and operable; arrow keys inside a tab row, a segmented switch, a menu, a radio
|
|
25
|
+
group, a list with a detail; Home and End to the ends; Escape closes a dialog, a drawer, a menu, a panel and returns
|
|
26
|
+
focus to what opened it; Enter saves an inline edit, Escape reverts.
|
|
27
|
+
- **Native first**: `<button>`, `<a>`, `<input type="checkbox">`, `<input type="range">`, `<fieldset>` with a `legend`,
|
|
28
|
+
`<details>` for a fold, a native `<dialog>`, the `popover` attribute for a menu in the top layer. Roving focus and
|
|
29
|
+
arrow keys come from Radix where native cannot. A sidebar's rows are real links with `aria-current="page"`.
|
|
19
30
|
- **Names**: every icon button has a label (read out and its tooltip); every card is a region named by its title; a chart is
|
|
20
|
-
a `figure` whose label says the answer and the numbers; a
|
|
31
|
+
a `figure` whose label says the answer and the numbers; a tick strip is hidden and its figure said in words; a figure
|
|
32
|
+
is read at its value.
|
|
21
33
|
- **Errors**: a message, wired with `aria-describedby` and `aria-invalid`; never a colour change alone. A pending control says
|
|
22
|
-
`aria-busy
|
|
23
|
-
|
|
24
|
-
|
|
34
|
+
`aria-busy` and stays focusable (`aria-disabled`); a toggle says `aria-pressed`; the current tab `aria-selected`; the
|
|
35
|
+
current page `aria-current`; an open row `aria-expanded`.
|
|
36
|
+
- **Reduced motion**: under `prefers-reduced-motion: reduce` everything is still (D7) and every state is still
|
|
37
|
+
reachable; the working signal is still and its words say it. How the kit does it, and what each thing looks like, is
|
|
38
|
+
in Motion.
|
|
25
39
|
- **Zoom and reflow**: text at 200% (1.4.4) and the page at 320 px wide (1.4.10, the same as 400% zoom): columns stack, the
|
|
26
40
|
panel is the screen, nothing scrolls sideways, nothing is clipped, and every region holding more than it shows scrolls.
|
|
27
41
|
A product drawn at a UI zoom divides viewport heights back by it.
|
|
28
42
|
- **WCAG 2.2 additions**: a sticky header, act or banner never covers the focused control (2.4.11); anything dragged (a
|
|
29
|
-
sheet, a card on a board) also works by a press (2.5.7); sign-in allows paste and password
|
|
30
|
-
pasted (3.3.8); nothing asked twice in one flow (3.3.7); help sits in the same place on
|
|
31
|
-
|
|
32
|
-
- **
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
sheet, a card on a board, a slider's thumb) also works by a press or the keys (2.5.7); sign-in allows paste and password
|
|
44
|
+
managers, and a code can be pasted (3.3.8); nothing asked twice in one flow (3.3.7); help sits in the same place on
|
|
45
|
+
every page (3.2.6).
|
|
46
|
+
- **No hover-only content**: what a hover shows (a row's acts, a close, a cell's full words in a tooltip, a hover card's
|
|
47
|
+
reading) touch and keyboard show too, on focus and on a tap (1.4.13). A tip stays while the pointer moves onto it and
|
|
48
|
+
closes on Escape.
|
|
49
|
+
- **Colour independence**: every state has a word or a mark; success and danger differ in lightness, never red and green
|
|
50
|
+
by hue alone; a falling number is mid blue; a rating says its band in words ("Strong", "Needs work").
|
|
51
|
+
- **Reading order** is the DOM order is the phone's order: a board's columns are stacked in the order the first column
|
|
52
|
+
reads; a list that goes above its detail on a phone comes first in the markup.
|
|
53
|
+
- **Dark**: every pair above holds in dark. In a product the theme is the person's choice (`ThemeSwitch`) or their
|
|
54
|
+
system's; a page drawn dark for everyone (an event page on the navy ground) passes the same pairs. Switching it moves
|
|
55
|
+
nothing.
|
|
35
56
|
- **Language**: plain words, sentence case, no abbreviations a person outside the trade would not know.
|
|
36
57
|
|
|
37
58
|
## Checks
|
|
38
59
|
|
|
39
|
-
Automated (axe or the Storybook a11y addon) catch the markup and contrast subset; the
|
|
40
|
-
|
|
41
|
-
|
|
60
|
+
Automated (axe or the Storybook a11y addon) catch the markup and contrast subset; the geometry check catches small
|
|
61
|
+
targets, focus that looks like rest, clipping and text off its line (`node scripts/check-geometry.mjs --hover`, light and
|
|
62
|
+
dark); the audit crawl (every page, each role, desktop and phone) catches sideways scroll, fields with no ground and
|
|
63
|
+
pages that cannot scroll. A keyboard walk, a 200% zoom, a screen reader pass (VoiceOver on a phone) and a reduced-motion
|
|
64
|
+
run are done by hand on every new screen.
|
|
@@ -7,19 +7,23 @@ references, never copies.
|
|
|
7
7
|
|
|
8
8
|
Only in its chat (one chat per assistant; an umbrella assistant may sit over several). No in-page assistant, no mission panel, no "ask to change" box
|
|
9
9
|
on a page. A page's one link to the agent is "Ask about this", which opens the chat with the thing attached ("About: Jordan
|
|
10
|
-
Lee")
|
|
10
|
+
Lee"); a drawer may carry a compact ask field that asks the same chat. The chat sits in its shell (`ChatShell`): a bar
|
|
11
|
+
over a page, docked beside it (the page steps aside, never covered), floating, or full screen; it moves between them as
|
|
12
|
+
itself. Voice goes through the one Talk button, which carries the assistant's mark; when a product's own call takes the
|
|
11
13
|
microphone, the assistant steps aside and comes back after.
|
|
12
14
|
|
|
13
15
|
## The turn
|
|
14
16
|
|
|
15
|
-
The agent's words are plain text,
|
|
16
|
-
|
|
17
|
+
The agent's words are plain text, no bubble, no avatar beside every line (the face is in the header). The person's words
|
|
18
|
+
sit in a bubble with navy text (`ChatTurn` has the sizes). Starters sit under the composer as `SuggestionChip`s; one long
|
|
19
|
+
conversation is marked by topic (`TopicRail`), never split into threads the person did not ask for. A reply is words plus at most one card, never both saying the
|
|
17
20
|
same thing. An act is a one-line receipt ("Drafted the opener for Nellie"), not a paragraph. A question is not echoed back.
|
|
18
21
|
|
|
19
22
|
## Streaming, working and cancelling
|
|
20
23
|
|
|
21
|
-
A reply arrives as it is written;
|
|
22
|
-
|
|
24
|
+
A reply arrives as it is written; while it works, a status line (`StatusLine`) says who is working, what it is doing and
|
|
25
|
+
the step, and the typing dots breathe on the one beat; a long job shows its steps as a `Stepper` in a card with Stop in its
|
|
26
|
+
band. Under reduced motion the answer shows whole and the status line is still. Stop is always one press away and says what was kept. The person can type the next
|
|
23
27
|
message while a reply streams.
|
|
24
28
|
|
|
25
29
|
## Cards from an agent
|
|
@@ -27,7 +31,8 @@ message while a reply streams.
|
|
|
27
31
|
A card is a reference with at most one act: a kind in its head ("Suggestion", "Task", "Question"), a title that says the
|
|
28
32
|
thing, one sentence, facts on a plate, the band with the app's door on the left and the buttons on the right (secondary then
|
|
29
33
|
the one navy). A rich card (a chart, a long list, a comparison) shows as one line in the chat and whole in the panel beside
|
|
30
|
-
it. Asks and pick lists stay in the chat. Taps answer at once (the button shows its pending state).
|
|
34
|
+
it. Asks and pick lists stay in the chat. Taps answer at once (the button shows its pending state). A thread's first
|
|
35
|
+
open follows Page recipes, 22: the app's face and one line, one example on the team's own numbers, the app's tiles.
|
|
31
36
|
|
|
32
37
|
## What waits on you
|
|
33
38
|
|
|
@@ -20,7 +20,7 @@ system does not have.
|
|
|
20
20
|
| --- | --- | --- |
|
|
21
21
|
| An operational page or panel (most of the product) | little | the right chart, a sharp title, one well-placed act, cards arriving in order |
|
|
22
22
|
| A chat card | some | a drawing on the dots that says the answer at a glance; a plate that holds exactly the facts |
|
|
23
|
-
| A hero (Team, Progress) | more | a 40 px line, a still faint wash (`ws-cool-glow`, `ws-team-glow`), a vertical-tube chart |
|
|
23
|
+
| A hero (Team, Progress, a report's score) | more | a 40 px line or the 96 px score, a still faint wash (`ws-cool-glow`, `ws-team-glow`), a vertical-tube chart |
|
|
24
24
|
| An entry page or a welcome step | more | the three faces glancing round, sample cards rising in beside |
|
|
25
25
|
| A guide or a walkthrough | more | a drawn board, the assistant talking it through |
|
|
26
26
|
| A report or a launch moment | the most | an expressive composition, imagery, a sequence of cards that tells one story |
|