@felloinnovations/brand-kit 0.4.0 → 0.5.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/AGENTS.md +198 -24
- package/CHANGELOG.md +197 -0
- package/README.md +34 -7
- package/design-system/01-how-claude-decides.md +26 -17
- package/design-system/02-principles.md +11 -6
- package/design-system/03-colour.md +134 -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 +357 -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 +52 -16
- package/design-system/components/Skeleton/preview.html +35 -23
- package/design-system/components/Skeleton/style.css +22 -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 +4091 -744
- package/design-system/tokens.json +1314 -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 +110 -11
- 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 +174 -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 +1292 -62
- package/tokens/tokens.md +588 -61
- package/tokens/tokens.root.css +1298 -62
- package/tokens/tokens.ts +1677 -64
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
What a chart mark holds, shown on hover or focus: Seth's North chart tip, with a caret on the mark it belongs to.
|
|
2
|
+
|
|
3
|
+
## Use it when
|
|
4
|
+
|
|
5
|
+
- A bar, a point, a tick or a square holds more than its mark can say (the week, the count, what it is made of).
|
|
6
|
+
- The person reads a chart by moving across it, and each mark answers as they pass.
|
|
7
|
+
- A short summary should sit by a mark without opening anything (a goal met on a day).
|
|
8
|
+
|
|
9
|
+
## Not for
|
|
10
|
+
|
|
11
|
+
- A control's name: use `Tooltip`.
|
|
12
|
+
- Content someone acts on beyond one ask (a field, several acts): use `Popover`.
|
|
13
|
+
- The only place a number lives: what a hover card says must also be reachable without hovering (the chart's own
|
|
14
|
+
table, a list, or the card on focus and tap).
|
|
15
|
+
- A thing's full detail: use `Panel`.
|
|
16
|
+
|
|
17
|
+
## Anatomy
|
|
18
|
+
|
|
19
|
+
- The card (`ws-hover-card`): `--ws-raised` ground, 8 px corners, the 0.5 px hairline and the tip drop
|
|
20
|
+
(`--ws-shadow-hairline`, `--ws-shadow-tip`), 12 above, 14 at the sides, 10 below. At least 168 wide; it grows with
|
|
21
|
+
its words up to 440, then a label wraps. 12 px body words. The rhythm is North's:
|
|
22
|
+
- Eyebrow 16 (`ws-hover-card__eyebrow`): an 8 px swatch with 2 px corners (`ws-hover-card__swatch`) and 11 px muted
|
|
23
|
+
words, 6 apart, 2 above the title.
|
|
24
|
+
- Title 20 (`ws-hover-card__title`): 16 / 20 semibold navy, 8 above the rows.
|
|
25
|
+
- Rows 22 (`ws-hover-card__row`): an 18 px line with 2 above and below; an optional swatch, the label
|
|
26
|
+
(`ws-hover-card__label`) taking the room, 28 clear of its value (the 8 px gap plus 20 of its own, North's row), the
|
|
27
|
+
value (`ws-hover-card__value`) navy semibold and tabular.
|
|
28
|
+
A label that wraps keeps its swatch and value on its first line; a number never wraps.
|
|
29
|
+
- Rule row (`ws-hover-card__row--rule`): a total or the next section, 8 above and 8 below a hairline that runs the
|
|
30
|
+
card's full width; its label navy medium.
|
|
31
|
+
- Ask foot (`ws-hover-card__foot`): a full-width strip under a hairline, 8 / 14 inside, 12 / 16 medium navy words, its
|
|
32
|
+
bottom corners the card's; the card drops its own bottom room. 40 tall on touch.
|
|
33
|
+
- Caret (on `--above` and `--below`): an 8 px square turned 45, its two outer edges drawn and only its outer half
|
|
34
|
+
shown, so the card's edge runs on to the point and nothing inside the card (the foot, its tint, its ring) is covered.
|
|
35
|
+
|
|
36
|
+
## Variants and sizes
|
|
37
|
+
|
|
38
|
+
| Class | Look |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `ws-hover-card` | The full card: eyebrow, title, rows, rules, foot |
|
|
41
|
+
| `ws-hover-card--compact` | North's point card: 8 / 10 inside, 6 px corners, a 12 / 16 semibold title over an 11 / 13 line (`ws-hover-card__line`), 2 apart |
|
|
42
|
+
| `ws-hover-card--above` | Placed on a mark: the card 8 over the point the chart sets (`left`, `top`), its caret reaching down to it |
|
|
43
|
+
| `ws-hover-card--below` | The same 8 under the point, caret up |
|
|
44
|
+
| `ws-hover-card--start`, `--end` | Near a side, the caret moves to 20% or 80% and the card with it, so it never runs off (North P3) |
|
|
45
|
+
|
|
46
|
+
## States
|
|
47
|
+
|
|
48
|
+
- **Hidden**: not drawn; the chart renders it for the mark under the pointer or in focus.
|
|
49
|
+
- **Shown** (North's chart tip, js@484880): it pops out of .9 and 6 px toward its mark (`--ws-rise`), from the
|
|
50
|
+
caret's corner, on the pop spring (`--ws-spring-pop`, .35 / .1); its parts settle in after it, 45 ms apart
|
|
51
|
+
(`--ws-stagger-row`), each over `--ws-duration-settle` on `--ws-ease-soft` out of a 3 px blur (`ws-settle`).
|
|
52
|
+
- **Following**: as the pointer moves along a chart it glides to the next mark on the follow spring (.22 / 0, never a
|
|
53
|
+
bounce), never in jumps. `ws-hover-card--follow` does it in CSS (`--ws-spring-follow` on `left` and `top`) for an app
|
|
54
|
+
that only sets them; an app that springs it itself (`springs.follow`) leaves the class off.
|
|
55
|
+
- **Grace**: it stays 180 ms (`--ws-hover-grace`) after the pointer leaves its mark, so a gap between bars never
|
|
56
|
+
flickers it.
|
|
57
|
+
- **Leaving** (`data-leaving`): it fades to .94 and 4 px over `--ws-duration-exit` (120 ms), faster than it came;
|
|
58
|
+
remove it 120 ms later.
|
|
59
|
+
- **Foot**: hover tints it with the navy wash, and the caret under it with it, so the strip and its point stay one
|
|
60
|
+
surface; focus draws the ring inside it.
|
|
61
|
+
- **Long label**: wraps; the value stays on the first line.
|
|
62
|
+
|
|
63
|
+
## Behaviour
|
|
64
|
+
|
|
65
|
+
- Keyboard: each mark that has a card is focusable (or the chart moves a focus mark with the arrow keys); the card
|
|
66
|
+
shows for the focused mark. Escape hides it.
|
|
67
|
+
- Pointer: shows on the mark, follows along the chart, stays for the grace.
|
|
68
|
+
- Touch: a tap on a mark shows its card; a tap elsewhere hides it. The foot is 40 tall.
|
|
69
|
+
- Placement: the chart sets `left` and `top` to the point inside its own positioned box; `--start` or `--end` near a
|
|
70
|
+
side. Inside a box that clips, portal it to the page.
|
|
71
|
+
- Reduced motion: it appears and goes in place; it moves to the next mark at once.
|
|
72
|
+
- The preview's last stack is live: point along the bars.
|
|
73
|
+
|
|
74
|
+
## Content
|
|
75
|
+
|
|
76
|
+
- The eyebrow names the mark (the week, the person, the series), with its colour.
|
|
77
|
+
- The title is the mark's one figure, in words if it helps ("26 calls").
|
|
78
|
+
- Rows say what the figure is made of, largest first; a rule row ends with the total or the comparison.
|
|
79
|
+
- The foot asks one question about this mark ("Ask about this week").
|
|
80
|
+
|
|
81
|
+
## Rules
|
|
82
|
+
|
|
83
|
+
- Every swatch is the mark's own chart colour; the words stay the word tones (AA on the raised ground).
|
|
84
|
+
- No more than five rows; a longer breakdown belongs in the chart's table.
|
|
85
|
+
- Its words are never the only place the figures live.
|
|
86
|
+
- A card that holds the ask foot (a button) is `role="dialog"` with an `aria-label`, never `role="tooltip"`: a tooltip
|
|
87
|
+
holds nothing to press. A card with only words (`--compact`) is `role="tooltip"`.
|
|
88
|
+
|
|
89
|
+
## Source
|
|
90
|
+
|
|
91
|
+
**Derived from**: Seth's North chart tip (style1.css:208-220: min 168, 12 / 14 / 10, eyebrow 16, title 20 + 8, rows 22,
|
|
92
|
+
full-width rules; :561-562 the ask foot; :386-398 the point card, the caret and the 80% edge anchor; js@484880 the pop,
|
|
93
|
+
follow, grace and the 45 ms row stagger). **Precedent**: new in 0.5.0; the kit's `Tooltip` was a one-line label only.
|
|
94
|
+
|
|
95
|
+
## Markup
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<div style="position: relative;">
|
|
99
|
+
<!-- the chart's marks; the card is placed at the open mark's point -->
|
|
100
|
+
<div class="ws-hover-card ws-hover-card--above" role="dialog" aria-label="Week of 20 October" style="left: 58%; top: 74%;">
|
|
101
|
+
<span class="ws-hover-card__eyebrow"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--color-text-heading);"></span>Week of 20 October</span>
|
|
102
|
+
<span class="ws-hover-card__title">26 calls</span>
|
|
103
|
+
<span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-finished);"></span><span class="ws-hover-card__label">Answered</span><span class="ws-hover-card__value">19</span></span>
|
|
104
|
+
<span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-under-half);"></span><span class="ws-hover-card__label">Missed</span><span class="ws-hover-card__value">7</span></span>
|
|
105
|
+
<span class="ws-hover-card__row ws-hover-card__row--rule"><span class="ws-hover-card__label">Team average</span><span class="ws-hover-card__value">31</span></span>
|
|
106
|
+
<button type="button" class="ws-hover-card__foot">Ask about this week</button>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Styles
|
|
112
|
+
|
|
113
|
+
`HoverCard/style.css`, built into `bundle.css` and `fello.css`. Tokens only, so it turns dark with the page; the
|
|
114
|
+
swatches take the chart colours through `--ws-hover-card-swatch`.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<!-- @dsCard group="Overlays" height=660 -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>HoverCard</title>
|
|
7
|
+
<link rel="stylesheet" href="../../tokens.css">
|
|
8
|
+
<link rel="stylesheet" href="../bundle.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div class="ws-stage">
|
|
12
|
+
|
|
13
|
+
<div class="ws-stack" style="width: 420px;">
|
|
14
|
+
<span class="ws-muted">Over a bar: eyebrow, title, rows, a rule row and the ask foot; the caret on the bar's top</span>
|
|
15
|
+
<div role="group" aria-label="Calls by week, with the week of 20 October open" style="position: relative; height: 320px; border-bottom: var(--ws-line) solid var(--ws-edge-slot);">
|
|
16
|
+
<span style="position: absolute; bottom: 0; left: 8%; width: 12%; height: 30%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
|
|
17
|
+
<span style="position: absolute; bottom: 0; left: 30%; width: 12%; height: 40%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
|
|
18
|
+
<span style="position: absolute; bottom: 0; left: 52%; width: 12%; height: 26%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--color-text-heading);"></span>
|
|
19
|
+
<span style="position: absolute; bottom: 0; left: 74%; width: 12%; height: 34%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
|
|
20
|
+
<div class="ws-hover-card ws-hover-card--above" role="dialog" aria-label="Week of 20 October" style="left: 58%; top: 74%;">
|
|
21
|
+
<span class="ws-hover-card__eyebrow"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--color-text-heading);"></span>Week of 20 October</span>
|
|
22
|
+
<span class="ws-hover-card__title">26 calls</span>
|
|
23
|
+
<span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-finished);"></span><span class="ws-hover-card__label">Answered</span><span class="ws-hover-card__value">19</span></span>
|
|
24
|
+
<span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-under-half);"></span><span class="ws-hover-card__label">Missed</span><span class="ws-hover-card__value">7</span></span>
|
|
25
|
+
<span class="ws-hover-card__row ws-hover-card__row--rule"><span class="ws-hover-card__label">Team average</span><span class="ws-hover-card__value">31</span></span>
|
|
26
|
+
<button type="button" class="ws-hover-card__foot">Ask about this week</button>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="ws-stack" style="width: 420px;">
|
|
32
|
+
<span class="ws-muted">A point card over a dot; near the right edge its caret moves to 80% so it stays inside</span>
|
|
33
|
+
<div role="img" aria-label="Replies by day" style="position: relative; height: 180px; border-bottom: var(--ws-line) solid var(--ws-edge-slot);">
|
|
34
|
+
<span style="position: absolute; left: 30%; top: 70%; width: var(--space-xs); height: var(--space-xs); border-radius: var(--radius-full); background: var(--color-text-heading); translate: -50% -50%;"></span>
|
|
35
|
+
<div class="ws-hover-card ws-hover-card--compact ws-hover-card--above" role="tooltip" style="left: 30%; top: calc(70% - var(--space-xxs));">
|
|
36
|
+
<span class="ws-hover-card__title">Tuesday</span>
|
|
37
|
+
<span class="ws-hover-card__line">4 replies, 2 within the hour</span>
|
|
38
|
+
</div>
|
|
39
|
+
<span style="position: absolute; left: 92%; top: 40%; width: var(--space-xs); height: var(--space-xs); border-radius: var(--radius-full); background: var(--color-text-heading); translate: -50% -50%;"></span>
|
|
40
|
+
<div class="ws-hover-card ws-hover-card--compact ws-hover-card--above ws-hover-card--end" role="tooltip" style="left: 92%; top: calc(40% - var(--space-xxs));">
|
|
41
|
+
<span class="ws-hover-card__title">Sunday</span>
|
|
42
|
+
<span class="ws-hover-card__line">1 reply</span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div class="ws-stack" style="width: 420px;">
|
|
48
|
+
<span class="ws-muted">Below its mark, and at rest beside a chart; a long label wraps, the number never does</span>
|
|
49
|
+
<div style="position: relative; height: 40px;">
|
|
50
|
+
<span style="position: absolute; left: 20%; top: 0; width: var(--space-xs); height: var(--space-xs); border-radius: var(--radius-full); background: var(--ws-chart-finished); translate: -50% 0;"></span>
|
|
51
|
+
<div class="ws-hover-card ws-hover-card--compact ws-hover-card--below ws-hover-card--start" role="tooltip" style="left: 20%; top: var(--space-xs);">
|
|
52
|
+
<span class="ws-hover-card__title">Goal met on 14 October</span>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="ws-hover-card" style="margin-top: var(--space-xl);">
|
|
56
|
+
<span class="ws-hover-card__eyebrow"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-finished);"></span>October</span>
|
|
57
|
+
<span class="ws-hover-card__title">82%</span>
|
|
58
|
+
<span class="ws-hover-card__row"><span class="ws-hover-card__label">Calls answered within five minutes of the lead coming in from Zillow or the website</span><span class="ws-hover-card__value">41 of 50</span></span>
|
|
59
|
+
<span class="ws-hover-card__row"><span class="ws-hover-card__label">Later</span><span class="ws-hover-card__value">9</span></span>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div class="ws-stack" style="width: 420px;" data-live>
|
|
64
|
+
<span class="ws-muted">Live: point along the bars. The card pops out of .9 on the pop spring, its rows settling in 45 ms apart, then glides from bar to bar on the follow spring (--follow); 180 ms after the pointer leaves it goes, over .12 s</span>
|
|
65
|
+
<div id="hc-live" role="group" aria-label="Calls by week" style="position: relative; height: 240px; border-bottom: var(--ws-line) solid var(--ws-edge-slot);">
|
|
66
|
+
<span data-week="Week of 29 September" data-calls="18" data-answered="12" style="position: absolute; bottom: 0; left: 8%; width: 12%; height: 40%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
|
|
67
|
+
<span data-week="Week of 6 October" data-calls="24" data-answered="17" style="position: absolute; bottom: 0; left: 30%; width: 12%; height: 54%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
|
|
68
|
+
<span data-week="Week of 13 October" data-calls="15" data-answered="11" style="position: absolute; bottom: 0; left: 52%; width: 12%; height: 34%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--ws-chart-navy-fade);"></span>
|
|
69
|
+
<span data-week="Week of 20 October" data-calls="26" data-answered="19" style="position: absolute; bottom: 0; left: 74%; width: 12%; height: 60%; border-radius: var(--ws-radius-bar) var(--ws-radius-bar) 0 0; background: var(--color-text-heading);"></span>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
<script>
|
|
73
|
+
(() => {
|
|
74
|
+
const chart = document.getElementById('hc-live');
|
|
75
|
+
let card = null, leave = 0;
|
|
76
|
+
const place = (bar) => {
|
|
77
|
+
const x = parseFloat(bar.style.left) + parseFloat(bar.style.width) / 2;
|
|
78
|
+
card.style.left = `${x}%`;
|
|
79
|
+
card.style.top = `${100 - parseFloat(bar.style.height)}%`;
|
|
80
|
+
card.classList.toggle('ws-hover-card--start', x < 25);
|
|
81
|
+
card.classList.toggle('ws-hover-card--end', x > 75);
|
|
82
|
+
card.querySelector('.ws-hover-card__title').textContent = `${bar.dataset.calls} calls`;
|
|
83
|
+
card.querySelector('[data-words]').textContent = bar.dataset.week;
|
|
84
|
+
card.querySelector('.ws-hover-card__value').textContent = bar.dataset.answered;
|
|
85
|
+
};
|
|
86
|
+
for (const bar of chart.children) bar.addEventListener('pointerenter', () => {
|
|
87
|
+
clearTimeout(leave);
|
|
88
|
+
if (!card || card.hasAttribute('data-leaving')) {
|
|
89
|
+
card?.remove();
|
|
90
|
+
card = document.createElement('div');
|
|
91
|
+
card.className = 'ws-hover-card ws-hover-card--above ws-hover-card--follow';
|
|
92
|
+
card.setAttribute('role', 'tooltip');
|
|
93
|
+
card.innerHTML = '<span class="ws-hover-card__eyebrow"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--color-text-heading);"></span><span data-words></span></span><span class="ws-hover-card__title"></span><span class="ws-hover-card__row"><span class="ws-hover-card__swatch" style="--ws-hover-card-swatch: var(--ws-chart-finished);"></span><span class="ws-hover-card__label">Answered</span><span class="ws-hover-card__value"></span></span>';
|
|
94
|
+
place(bar);
|
|
95
|
+
chart.append(card);
|
|
96
|
+
} else place(bar);
|
|
97
|
+
});
|
|
98
|
+
chart.addEventListener('pointerleave', () => {
|
|
99
|
+
clearTimeout(leave);
|
|
100
|
+
leave = setTimeout(() => { const c = card; c?.setAttribute('data-leaving', ''); setTimeout(() => c?.remove(), 120); }, 180);
|
|
101
|
+
});
|
|
102
|
+
})();
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
</div>
|
|
106
|
+
</body>
|
|
107
|
+
</html>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* ---- HoverCard: what a chart mark holds, on hover or focus, Seth's North chart tip (N:209-220): eyebrow 16, title 20 and 8
|
|
2
|
+
under, rows 22, full-width rules; placed over a mark, a caret points at it ---- */
|
|
3
|
+
/* The card: 12 / 14 / 10 inside, at least 168 wide, 8 px corners, the hairline and the tip drop, 12 px body words. It
|
|
4
|
+
grows with its words up to the panel width; a label wraps, a number never does. --ws-hover-card-anchor is where the
|
|
5
|
+
caret sits along its edge (50%, or 20% / 80% near a side, North P3). */
|
|
6
|
+
.ws-hover-card { --ws-hover-card-x: var(--space-sm-plus); --ws-hover-card-anchor: 50%; position: relative; display: flex; flex-direction: column; width: max-content; min-width: calc(var(--space-8xl) + var(--space-xs)); max-width: min(var(--ws-thing-width), calc(100vw - var(--space-xl))); padding: var(--space-sm) var(--ws-hover-card-x) var(--space-xs-plus); border-radius: var(--ws-radius-card); background: var(--ws-raised); box-shadow: var(--ws-shadow-hairline), var(--ws-shadow-tip); font-size: var(--ws-text-dense); line-height: var(--ws-leading-control); color: var(--color-text-body); }
|
|
7
|
+
/* Eyebrow 16: 11 px muted words after an 8 px swatch, 6 apart, 2 above the title. */
|
|
8
|
+
.ws-hover-card__eyebrow { display: flex; align-items: center; gap: var(--space-xxs-plus); margin-bottom: var(--space-3xs); font-size: var(--ws-text-micro); line-height: var(--space-md); color: var(--color-text-muted); }
|
|
9
|
+
.ws-hover-card__swatch { flex-shrink: 0; width: var(--space-xs); height: var(--space-xs); border-radius: var(--ws-radius-chip); background: var(--ws-hover-card-swatch, currentColor); }
|
|
10
|
+
/* Title 20: 16 / 20 semibold navy, 8 above the rows. */
|
|
11
|
+
.ws-hover-card__title { margin-bottom: var(--space-xs); font-size: var(--font-size-md); line-height: var(--ws-leading-row); font-weight: 600; color: var(--color-text-heading); font-variant-numeric: tabular-nums; }
|
|
12
|
+
/* Rows 22: an 18 px line and 2 above and below; the label takes the room and keeps 20 of its own past the 8 px gap, so
|
|
13
|
+
it ends 28 clear of its value (navy semibold). A label that wraps keeps its swatch and value on its first line. */
|
|
14
|
+
.ws-hover-card__row { display: flex; align-items: flex-start; gap: var(--space-xs); padding-block: var(--space-3xs); }
|
|
15
|
+
.ws-hover-card__row > .ws-hover-card__swatch { margin-block: calc((var(--ws-leading-control) - var(--space-xs)) / 2); }
|
|
16
|
+
.ws-hover-card__label { flex: 1; min-width: 0; padding-right: var(--ws-card-inset); }
|
|
17
|
+
.ws-hover-card__value { flex-shrink: 0; font-weight: 600; color: var(--color-text-heading); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
18
|
+
/* A rule row (a total, the next section): 8 above and 8 below a hairline that runs the card's full width. */
|
|
19
|
+
.ws-hover-card__row--rule { margin: var(--space-xxs-plus) calc(var(--ws-hover-card-x) * -1) 0; padding: var(--space-xs) var(--ws-hover-card-x) var(--space-3xs); border-top: var(--ws-hairline) solid var(--ws-edge-card); }
|
|
20
|
+
.ws-hover-card__row--rule .ws-hover-card__label { font-weight: 500; color: var(--color-text-heading); }
|
|
21
|
+
/* The ask foot: a full-width strip under a hairline that asks about this mark; the card drops its own bottom room. */
|
|
22
|
+
.ws-hover-card:has(> .ws-hover-card__foot) { padding-bottom: 0; }
|
|
23
|
+
.ws-hover-card__foot { display: flex; align-items: center; gap: var(--space-xxs-plus); margin: var(--space-xs) calc(var(--ws-hover-card-x) * -1) 0; padding: var(--space-xs) var(--ws-hover-card-x); border: 0; border-top: var(--ws-hairline) solid var(--ws-edge-card); border-radius: 0 0 var(--ws-radius-card) var(--ws-radius-card); background: none; font-size: var(--ws-text-dense); line-height: var(--space-md); font-weight: 500; color: var(--color-text-heading); text-align: left; cursor: pointer; transition: background-color var(--ws-duration-hover) var(--ws-ease-soft); }
|
|
24
|
+
.ws-hover-card__foot:focus-visible { outline-offset: calc(var(--ws-focus-width) * -1); }
|
|
25
|
+
@media (hover: hover) { .ws-hover-card__foot:hover { background: var(--ws-hover); } }
|
|
26
|
+
@media (pointer: coarse) { .ws-hover-card__foot { min-height: var(--ws-touch); } }
|
|
27
|
+
/* --compact: the point card (N:388): 8 / 10 inside, 6 px corners, a 12 px semibold title over an 11 px line, 2 apart. */
|
|
28
|
+
.ws-hover-card--compact { gap: var(--space-3xs); min-width: 0; padding: var(--space-xs) var(--space-xs-plus); border-radius: var(--ws-radius-row); }
|
|
29
|
+
.ws-hover-card--compact .ws-hover-card__title { margin-bottom: 0; font-size: var(--ws-text-dense); line-height: var(--space-md); }
|
|
30
|
+
.ws-hover-card__line { font-size: var(--ws-text-micro); line-height: var(--ws-leading-micro); color: var(--color-text-body); }
|
|
31
|
+
/* Placed on a mark: the chart sets left and top to the point (style), --above lifts the card 8 over it, --below drops it
|
|
32
|
+
8 under; the caret (an 8 px square turned 45, its two outer edges drawn, clipped to its outer half so it never
|
|
33
|
+
paints over the foot, its tint or its focus ring) continues the card's edge to the point.
|
|
34
|
+
--start and --end move the caret to 20% / 80% near a side, so the card never runs off it. */
|
|
35
|
+
.ws-hover-card--above, .ws-hover-card--below { position: absolute; z-index: var(--z-dropdown); }
|
|
36
|
+
.ws-hover-card--above { translate: calc(var(--ws-hover-card-anchor) * -1) calc(-100% - var(--space-xs)); transform-origin: var(--ws-hover-card-anchor) 100%; }
|
|
37
|
+
.ws-hover-card--below { translate: calc(var(--ws-hover-card-anchor) * -1) var(--space-xs); transform-origin: var(--ws-hover-card-anchor) 0; }
|
|
38
|
+
.ws-hover-card--above::after, .ws-hover-card--below::after { content: ""; position: absolute; left: var(--ws-hover-card-anchor); width: var(--space-xs); height: var(--space-xs); background: var(--ws-raised); }
|
|
39
|
+
.ws-hover-card--above::after { top: 100%; border-right: var(--ws-hairline) solid var(--ws-edge-card); border-bottom: var(--ws-hairline) solid var(--ws-edge-card); clip-path: polygon(100% 0, 100% 100%, 0 100%); transform: translate(-50%, calc(var(--ws-nudge) * -1)) rotate(45deg); box-shadow: inset 0 0 0 var(--space-xs) transparent; transition: box-shadow var(--ws-duration-hover) var(--ws-ease-soft); }
|
|
40
|
+
/* Under the ask foot the caret is the foot's own end, so it takes the foot's hover wash with it. */
|
|
41
|
+
@media (hover: hover) { .ws-hover-card--above:has(> .ws-hover-card__foot:hover)::after { box-shadow: inset 0 0 0 var(--space-xs) var(--ws-hover); } }
|
|
42
|
+
.ws-hover-card--below::after { bottom: 100%; border-top: var(--ws-hairline) solid var(--ws-edge-card); border-left: var(--ws-hairline) solid var(--ws-edge-card); clip-path: polygon(0 0, 100% 0, 0 100%); transform: translate(-50%, var(--ws-nudge)) rotate(45deg); }
|
|
43
|
+
.ws-hover-card--start { --ws-hover-card-anchor: 20%; }
|
|
44
|
+
.ws-hover-card--end { --ws-hover-card-anchor: 80%; }
|
|
45
|
+
/* Motion (D7, North's chart tip, js@484880): it pops on the pop spring (.35 / .1, "Tooltip pop-in") from scale .9 and
|
|
46
|
+
6 px toward its mark, out of the caret's corner, its parts (the foot too) settling in after it 45 ms apart, each over
|
|
47
|
+
.32 s soft (js@483244) where the browser counts siblings (all at once elsewhere); it leaves over .12 s to scale .94
|
|
48
|
+
and 4 px, faster. --follow glides it after the pointer on the follow spring (.22 / 0, "Tooltip follows cursor",
|
|
49
|
+
never a bounce) as the app moves its left and top; leave it off when the app springs it itself. */
|
|
50
|
+
.ws-hover-card { --ws-hover-card-from: var(--ws-rise); --ws-hover-card-to: var(--ws-nudge); }
|
|
51
|
+
.ws-hover-card--below { --ws-hover-card-from: calc(var(--ws-rise) * -1); --ws-hover-card-to: calc(var(--ws-nudge) * -1); }
|
|
52
|
+
@keyframes ws-hover-card-in { from { opacity: 0; transform: translateY(var(--ws-hover-card-from)) scale(0.9); } }
|
|
53
|
+
@keyframes ws-hover-card-out { to { opacity: 0; transform: translateY(var(--ws-hover-card-to)) scale(var(--ws-pop-scale)); } }
|
|
54
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
55
|
+
.ws-hover-card { animation: ws-hover-card-in var(--ws-spring-pop-duration) var(--ws-spring-pop) backwards; }
|
|
56
|
+
.ws-hover-card > * { animation: ws-settle var(--ws-duration-settle) var(--ws-ease-soft) backwards; animation-delay: calc((sibling-index() - 1) * var(--ws-stagger-row)); }
|
|
57
|
+
.ws-hover-card[data-leaving] { animation: ws-hover-card-out var(--ws-duration-exit) var(--ws-ease-exit) forwards; pointer-events: none; }
|
|
58
|
+
.ws-hover-card--follow { transition: left var(--ws-spring-follow-duration) var(--ws-spring-follow), top var(--ws-spring-follow-duration) var(--ws-spring-follow); }
|
|
59
|
+
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
A
|
|
1
|
+
A square button holding one icon and nothing else, for an act that needs no words to be understood.
|
|
2
2
|
|
|
3
3
|
## Use it when
|
|
4
4
|
|
|
5
|
-
- The act is a single, well-known icon beside other controls (close, mute, edit, remove) where words
|
|
6
|
-
|
|
7
|
-
- A card's
|
|
8
|
-
-
|
|
5
|
+
- The act is a single, well-known icon beside other controls (close, mute, edit, remove, previous, next) where words
|
|
6
|
+
would crowd the row.
|
|
7
|
+
- A pane's or a card's close (`solid`, Seth's grey square), or a review's Previous and Next.
|
|
8
|
+
- The composer's round Send or Talk (`round`).
|
|
9
|
+
- A card's corner needs a quiet remove or dismiss (`xs`, 24 px).
|
|
10
|
+
- A toggle needs to show it is on (a mic that is listening, a mark that is set): `selected`.
|
|
9
11
|
|
|
10
12
|
## Not for
|
|
11
13
|
|
|
@@ -15,50 +17,59 @@ A round button holding one icon and nothing else, for an act that needs no words
|
|
|
15
17
|
|
|
16
18
|
## Anatomy
|
|
17
19
|
|
|
18
|
-
- A
|
|
19
|
-
- Size: `xs`
|
|
20
|
-
(`--ws-control-h-md
|
|
21
|
-
|
|
20
|
+
- A square: 6 px corners (`--ws-radius-row`; 4 at `xs`), no edge by default; `round` makes it a disc.
|
|
21
|
+
- Size: `xs` 24, `small` 28 (`--ws-control-h-sm`), `medium` 32 (`--ws-control-h`, the default), `large` 36
|
|
22
|
+
(`--ws-control-h-md`). On a touch screen every size is a 40 px target: medium and large grow to 40, `xs` and `small`
|
|
23
|
+
keep their look and gain a 40 px hit area round them.
|
|
24
|
+
- Icon: 16 px navy (`--ws-icon`), 20 px inside `large`.
|
|
22
25
|
- `label` names the act for a screen reader and is its tooltip (never leave it out).
|
|
23
26
|
|
|
24
27
|
## Variants and sizes
|
|
25
28
|
|
|
26
29
|
| Variant | Fill | Edge | Where |
|
|
27
30
|
| --- | --- | --- | --- |
|
|
28
|
-
| `ghost` |
|
|
29
|
-
| `outline` |
|
|
30
|
-
| `solid` | `--ws-
|
|
31
|
-
| `primary` |
|
|
31
|
+
| `ghost` | none, the navy wash under the pointer | none | the default: a row's or a header's quiet icon act |
|
|
32
|
+
| `outline` | none | 0.5 px `--ws-edge-card`, drawn inside | an icon act that must read as a control at rest |
|
|
33
|
+
| `solid` | the tray grey (`--ws-tray`, #EDEDED) | none | Seth's close, Previous and Next |
|
|
34
|
+
| `primary` | navy | none | the one act of its place as an icon: Send, a shortlist pick |
|
|
35
|
+
| `round` (with any) | as its variant | as its variant | the composer's voice and send discs |
|
|
32
36
|
|
|
33
|
-
Sizes: `xs` (
|
|
37
|
+
Sizes: `xs` (24), `small` (28), `medium` (32, default), `large` (36).
|
|
34
38
|
|
|
35
39
|
## States
|
|
36
40
|
|
|
37
41
|
- **Default:** as the table above.
|
|
38
|
-
- **Hover:** `ghost`
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- **
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
- **
|
|
42
|
+
- **Hover (a mouse only):** `ghost` takes the navy wash (`--ws-hover-strong`, North's icon button); `outline` darkens its
|
|
43
|
+
edge (#AAA49D), no fill; `solid` darkens its grey (`--ws-well-hover`); `primary` goes a shade brighter with the light
|
|
44
|
+
under the pointer.
|
|
45
|
+
- **Focus:** the kit's ring, 2 px navy, 2 px out.
|
|
46
|
+
- **Pressed:** gives to 0.97 (a round one, the voice act, to 0.94, `--ws-press-scale-round`; a send act that wears
|
|
47
|
+
`ws-press--send` to 0.92, `--ws-press-scale-send`) and springs back, on North's press spring (`--ws-spring-press`, the
|
|
48
|
+
house's press rule); still under reduced motion.
|
|
49
|
+
- **Selected:** a toggle that is on wears `primary`'s navy whatever its look, with `aria-pressed="true"`. Not for a
|
|
50
|
+
field's own toggle (a password's eye): that one changes its icon and its label instead.
|
|
51
|
+
- **Pending:** its answer is on the way. The icon breathes on the working beat (`ws-working` on the svg) in full colour;
|
|
52
|
+
the button stays focusable (`aria-disabled`) and refuses a second press (`aria-busy="true"`); under the pointer it
|
|
53
|
+
keeps its resting look, so nothing invites the press it refuses.
|
|
54
|
+
- **Pictured states (a preview or a mockup):** `is-hover`, `is-pressed` and `is-focus` draw them still.
|
|
55
|
+
- **Disabled:** 40%, no pointer. A `primary` one sinks instead: the sunk cream with a muted icon, at full opacity.
|
|
46
56
|
- **Empty / loading:** not a state of its own; the icon is always present.
|
|
47
|
-
- **Long label:** not applicable (no visible words);
|
|
48
|
-
- **Narrow:** unaffected by width; it never
|
|
49
|
-
- **Touch:** every size
|
|
57
|
+
- **Long label:** not applicable (no visible words); `label` may still be a full sentence for the screen reader.
|
|
58
|
+
- **Narrow:** unaffected by width; it never shrinks.
|
|
59
|
+
- **Touch:** every size is a 40 px target.
|
|
60
|
+
- **Dark:** the navy icons become the light ink; the tray grey and the hover grey take their dark values.
|
|
50
61
|
|
|
51
62
|
## Behaviour
|
|
52
63
|
|
|
53
64
|
- Keyboard: a normal `<button>`; Enter or Space activates it.
|
|
54
|
-
- Pointer / touch: hover and press as above
|
|
55
|
-
- Motion:
|
|
56
|
-
(1
|
|
65
|
+
- Pointer / touch: hover and press as above.
|
|
66
|
+
- Motion: colours over `--ws-duration-hover` on `--ws-ease-soft`, the press on the press spring; the pending icon
|
|
67
|
+
breathes on `--ws-loop` (1 s). Everything is still under reduced motion.
|
|
57
68
|
|
|
58
69
|
## Content
|
|
59
70
|
|
|
60
|
-
- No visible words; `label` is a short, concrete verb phrase ("Mute", "
|
|
61
|
-
shown as the title.
|
|
71
|
+
- No visible words; `label` is a short, concrete verb phrase ("Mute", "Close", "Previous review"), read by assistive
|
|
72
|
+
tech and shown as the title.
|
|
62
73
|
- No em dashes in `label`.
|
|
63
74
|
|
|
64
75
|
## Props
|
|
@@ -68,21 +79,41 @@ Sizes: `xs` (24px), `small` (28px), `medium` (32px, default), `large` (36px).
|
|
|
68
79
|
| `icon` | `IconName` | which icon it shows |
|
|
69
80
|
| `label` | `string` | what it is called: `aria-label` and its tooltip |
|
|
70
81
|
| `variant` | `'ghost' \| 'outline' \| 'solid' \| 'primary'` | the look, default `ghost` |
|
|
71
|
-
| `size` | `'xs' \| 'small' \| 'medium' \| 'large'` | the
|
|
82
|
+
| `size` | `'xs' \| 'small' \| 'medium' \| 'large'` | the size, default `medium` |
|
|
83
|
+
| `round` | `boolean` | a disc instead of a square (voice, send) |
|
|
72
84
|
| `selected` | `boolean` | a toggle that is on: navy fill, `aria-pressed` |
|
|
73
|
-
| `pending` | `boolean` | its answer is on the way: the icon
|
|
74
|
-
| `weight` | `'regular' \| 'bold' \| 'fill'` | the icon's own weight (bold on a navy fill) |
|
|
85
|
+
| `pending` | `boolean` | its answer is on the way: the icon breathes, `aria-busy`, refuses a press |
|
|
75
86
|
| ...rest | native `<button>` props | passed through (`onClick`, `type`, `disabled`, `aria-*`) |
|
|
76
87
|
|
|
77
88
|
## Rules
|
|
78
89
|
|
|
79
|
-
- `pending` keeps the icon in full colour and
|
|
80
|
-
(
|
|
90
|
+
- `pending` keeps the icon in full colour and breathes it (`ws-working`), never greys it, so waiting never looks broken
|
|
91
|
+
(16 Oct 2026).
|
|
81
92
|
- `label` is required: an icon alone is never the only name for an act.
|
|
82
93
|
- The one act of its place as an icon (Send, a shortlist pick) is `primary`, navy, matching `Button`'s one-navy rule.
|
|
94
|
+
- A pane closes with a `solid` square holding an x (Seth's drawer, 301:2021).
|
|
95
|
+
- Square by default (Seth's Fia frames and North both draw squares); `round` only for the voice and send discs.
|
|
83
96
|
|
|
84
97
|
## Source
|
|
85
98
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
99
|
+
**Derived from**: Seth's Fia frames: the drawer's close (301:2021) and the review's Previous and Next (313:2941, 313:2944),
|
|
100
|
+
32 px squares with 6 px corners on #EDEDED with 16 px navy icons. Seth's North (style1.css:28-30): square icon buttons
|
|
101
|
+
and their .06 navy hover wash; the round voice button's 0.94 press (app.js). The field's fix (Ignite controls.tsx): the
|
|
102
|
+
disabled navy one sinks. **Precedent**: the first product built on the system.
|
|
103
|
+
|
|
104
|
+
## Markup
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<button type="button" class="ws-icon-btn ws-icon-btn--solid" aria-label="Close" title="Close">
|
|
108
|
+
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg>
|
|
109
|
+
</button>
|
|
110
|
+
<button type="button" class="ws-icon-btn ws-icon-btn--lg ws-icon-btn--round ws-icon-btn--primary" aria-label="Talk" title="Talk">
|
|
111
|
+
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="6" y="2" width="4" height="7" rx="2"/><path d="M4 7.5a4 4 0 0 0 8 0M8 13.5V15"/></svg>
|
|
112
|
+
</button>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Styles
|
|
116
|
+
|
|
117
|
+
`design-system/components/IconButton/style.css`: `ws-icon-btn` with `--xs`, `--sm`, `--lg`, `--round`, `--outline`,
|
|
118
|
+
`--solid`, `--primary`, and the pictured states `is-hover`, `is-pressed`, `is-focus`. The hover values (`--ws-edge-hover`, `--ws-act-hover`, `--ws-act-light`) are scoped in
|
|
119
|
+
`Button/style.css`; the touch targets come from the house's touch block.
|