@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
|
@@ -1,69 +1,127 @@
|
|
|
1
|
-
A name on hover or keyboard focus, for a control that shows less than it is
|
|
1
|
+
A name on hover or keyboard focus, for a control that shows less than it is; and Seth's navy note, the full words behind a short one.
|
|
2
2
|
|
|
3
3
|
## Use it when
|
|
4
4
|
|
|
5
|
-
- An icon-only button's
|
|
6
|
-
- A
|
|
5
|
+
- An icon-only button's name should also show to a sighted pointer or keyboard user ("Refresh the audit").
|
|
6
|
+
- A short word stands for longer words that some people want to read (a question cut to "A buyer"): the note.
|
|
7
7
|
|
|
8
8
|
## Not for
|
|
9
9
|
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
10
|
+
- The only way to know what a control does on touch: a touch screen never shows a plain tip, so the icon must read on
|
|
11
|
+
its own.
|
|
12
|
+
- What a chart mark holds (a title, figures, rows): use `HoverCard`.
|
|
13
|
+
- Content someone acts on (a field, a link): use `Popover`.
|
|
14
|
+
- A receipt for something that happened: use `Toast`.
|
|
15
|
+
- A native `title` beside it: this replaces that.
|
|
14
16
|
|
|
15
17
|
## Anatomy
|
|
16
18
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
19
|
+
- The wrapper (`ws-tooltip`): an inline box around the control, which the tip is placed against.
|
|
20
|
+
- The tip (`ws-tooltip__tip`): North's compact tip. `--ws-raised` ground, 6 / 10 inside, 6 px corners
|
|
21
|
+
(`--ws-radius-row`), the 0.5 px hairline and the tip drop (`--ws-shadow-hairline`, `--ws-shadow-tip`), 12 / 16
|
|
22
|
+
semibold navy words on one line; a longer name wraps at 440 (or the window less 32) and is never cut. 8 above its control (`--ws-tooltip-gap`), centred on it.
|
|
23
|
+
- The note (`ws-tooltip--note`, Seth 305:2272): the act's navy (`--ws-inverse`, words `--ws-on-inverse`), the brand navy in dark, 4 px corners, 10 / 12
|
|
24
|
+
inside, 14 / 20 regular white words that wrap at 300 (12.71:1), no shadow (in dark, a faint light rim). Its words start where the word
|
|
25
|
+
it explains starts (its 12 px padding hangs to the left). A 12 x 6 caret points down at that word's middle, 4 above
|
|
26
|
+
it; the note sits 10 above.
|
|
27
|
+
- The term (`ws-tooltip__term`): the word the note explains, a button with a 1 px dotted underline 4 under the words,
|
|
28
|
+
the cue that more shows. On touch its hit area is 24 tall while its words keep the line, so a term inside a sentence
|
|
29
|
+
stays on the sentence's baseline.
|
|
21
30
|
|
|
22
31
|
## Variants and sizes
|
|
23
32
|
|
|
24
|
-
|
|
|
33
|
+
| Class | Where |
|
|
25
34
|
| --- | --- |
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
35
|
+
| `ws-tooltip` | Centred, above |
|
|
36
|
+
| `ws-tooltip--below` | Under the control |
|
|
37
|
+
| `ws-tooltip--start` | Flush to the control's left edge, for a control near the left of its container |
|
|
38
|
+
| `ws-tooltip--end` | Flush to its right edge (with the note, its words end where the word ends) |
|
|
39
|
+
| `ws-tooltip--note` | Seth's navy note with its caret, left-anchored |
|
|
40
|
+
| `ws-tooltip--note ws-tooltip--below` | The note under its term, the caret turned up, for a term near the top of its card |
|
|
41
|
+
| `ws-tooltip--open` | Shown, whatever the pointer does (a tap toggle, or a preview) |
|
|
42
|
+
| `ws-tooltip--dismissed` | Hidden after Escape, even while hovered or focused |
|
|
29
43
|
|
|
30
44
|
## States
|
|
31
45
|
|
|
32
|
-
- **Hidden** (default):
|
|
33
|
-
|
|
34
|
-
- **
|
|
35
|
-
|
|
46
|
+
- **Hidden** (default): not shown, takes no presses; still read: a plain tip names its control (`aria-labelledby`), a
|
|
47
|
+
note describes its term (`aria-describedby`).
|
|
48
|
+
- **Hover**: shown once the pointer has rested 40 ms (`--ws-hover-intent`); only for pointers that hover. A bridge
|
|
49
|
+
over the 8 px gap keeps it while the pointer moves onto it.
|
|
50
|
+
- **Keyboard focus**: shown at once when the control has `:focus-visible`, never on a click's own focus.
|
|
51
|
+
- **Tap**: the note toggles on a tap (`ws-tooltip--open`); a plain tip never shows on touch.
|
|
52
|
+
- **Opening** (North's "Tooltip pop-in", js@484880): it pops out of .9 and 4 px toward its control, growing from the
|
|
53
|
+
edge it hangs from, on the pop spring (`--ws-spring-pop`, .35 / .1, 500 ms to rest); the note's caret pops with it.
|
|
54
|
+
- **Leaving**: it fades off over 180 ms (North's tip fade, css:388; `--ws-tooltip-out`) on `--ws-ease-exit`, faster
|
|
55
|
+
than it came.
|
|
36
56
|
|
|
37
57
|
## Behaviour
|
|
38
58
|
|
|
39
|
-
- Keyboard: shows
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
59
|
+
- Keyboard: shows on visible focus, goes when focus moves on. Escape hides it where it is (WCAG 1.4.13): a few lines
|
|
60
|
+
of script add `ws-tooltip--dismissed` on Escape and take it off when the pointer or focus leaves.
|
|
61
|
+
- Pointer: shows after the hover intent, stays while the pointer is on the control, the gap or the tip.
|
|
62
|
+
- Touch: the plain tip never shows; the note opens on a tap of its term and closes on a second tap or a tap outside.
|
|
63
|
+
- The note hangs from its term's start (or its end, `--end`) and never moves itself onto the screen: a term away from
|
|
64
|
+
both edges of a phone gets its place from the app (Floating UI `shift`), or the note runs past the edge.
|
|
65
|
+
- Where the browser places by anchor (CSS anchor positioning), the tip is fixed to its wrapper as its anchor, so no
|
|
66
|
+
scroller, card or stage that clips can cut it (K9): a tip on AppShell's bar or its body's first row shows whole. A
|
|
67
|
+
plain tip with no room on its side turns to the other one (above to below) or slides along its control to stay on the
|
|
68
|
+
screen; the note keeps its side. Without anchor placement, inside a scroller or a card that clips, render the tip in a
|
|
69
|
+
portal (Radix `Tooltip` with its container on a `class="fello"` root in a scoped app), or it is cut.
|
|
70
|
+
- Reduced motion: it simply appears and goes; so does a browser without `linear()`.
|
|
71
|
+
- The preview's last stack is live: point at or tab to each.
|
|
44
72
|
|
|
45
73
|
## Content
|
|
46
74
|
|
|
47
|
-
-
|
|
48
|
-
|
|
75
|
+
- A plain tip is the control's name: the control points at it with `aria-labelledby` and has no `aria-label` of its
|
|
76
|
+
own, so the words live in one place and are read once.
|
|
77
|
+
- One line, sentence case ("Ask about this").
|
|
78
|
+
- A note holds the full words the term stands for, as they were written, up to three lines.
|
|
49
79
|
|
|
50
80
|
## Props
|
|
51
81
|
|
|
52
82
|
| Name | Type | Meaning |
|
|
53
83
|
| --- | --- | --- |
|
|
54
|
-
| `label` | `ReactNode` | The
|
|
55
|
-
| `align` | `"center"` \| `"start"` \| `"end"` | Where it sits
|
|
84
|
+
| `label` | `ReactNode` | The words shown in the tip. |
|
|
85
|
+
| `align` | `"center"` \| `"start"` \| `"end"` | Where it sits along the control. Default `center`. |
|
|
86
|
+
| `side` | `"above"` \| `"below"` | Which side it opens on. Default `above`. |
|
|
87
|
+
| `note` | boolean | Seth's navy note with a caret. |
|
|
56
88
|
| `className` | string | Layout only. |
|
|
57
|
-
| `children` | `ReactNode` | The control the tip names. |
|
|
89
|
+
| `children` | `ReactNode` | The control (or the term) the tip names. |
|
|
58
90
|
|
|
59
91
|
## Rules
|
|
60
92
|
|
|
61
|
-
- The tip
|
|
62
|
-
|
|
63
|
-
- Shows at once on keyboard focus
|
|
64
|
-
-
|
|
93
|
+
- The plain tip names its control (`aria-labelledby`); never an `aria-label` and an `aria-describedby` to the same
|
|
94
|
+
words, which a screen reader reads twice.
|
|
95
|
+
- Shows at once on keyboard focus: a keyboard user never waits to learn what a button is.
|
|
96
|
+
- No hover-only content: the note also opens on focus and on a tap (14-accessibility.md).
|
|
97
|
+
- The note is navy (Seth, 305:2272). It resolves the old open question about a navy tip: the label tip stays the light
|
|
98
|
+
card, the note is navy.
|
|
65
99
|
|
|
66
100
|
## Source
|
|
67
101
|
|
|
68
|
-
**Derived from**:
|
|
69
|
-
|
|
102
|
+
**Derived from**: North's compact tip and its placement (style1.css:386-398, :484-486: 6 px corners, 8 to 10 from its
|
|
103
|
+
mark, edge-flush near a side, the tip drop; js@484880: pop from .94 and 4 px, 120 ms exit), Seth's note (Figma
|
|
104
|
+
305:2272: navy, 4 px corners, 10 / 12, 14 / 20, 300 wide, 12 x 6 caret over the word, left-anchored) and the field
|
|
105
|
+
fix (hidden until hover or focus, start and end placement; Ignite Tip.tsx). **Precedent**: the first product built on
|
|
106
|
+
the system.
|
|
107
|
+
|
|
108
|
+
## Markup
|
|
109
|
+
|
|
110
|
+
```html
|
|
111
|
+
<span class="ws-tooltip">
|
|
112
|
+
<span class="ws-tooltip__tip" role="tooltip" id="tip-refresh">Refresh the audit</span>
|
|
113
|
+
<button type="button" class="ws-icon-btn" aria-labelledby="tip-refresh">
|
|
114
|
+
<svg viewBox="0 0 16 16" fill="none"><path d="M13 8a5 5 0 1 1-1.5-3.5M13 3v2.5h-2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
115
|
+
</button>
|
|
116
|
+
</span>
|
|
117
|
+
|
|
118
|
+
<span class="ws-tooltip ws-tooltip--note">
|
|
119
|
+
<span class="ws-tooltip__tip" role="tooltip" id="note-buyer">I'm thinking of buying a home in Chagrin Falls, OH. Which real estate agent or team should I talk to?</span>
|
|
120
|
+
<button type="button" class="ws-tooltip__term" aria-describedby="note-buyer" onclick="this.parentElement.classList.toggle('ws-tooltip--open')">A buyer</button>
|
|
121
|
+
</span>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Styles
|
|
125
|
+
|
|
126
|
+
`Tooltip/style.css`, built into `bundle.css` and `fello.css`. Tokens only, so it turns dark with the page (the note
|
|
127
|
+
keeps the brand navy and white words, with a faint light rim, D12).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- @dsCard group="Overlays" height=
|
|
1
|
+
<!-- @dsCard group="Overlays" height=340 -->
|
|
2
2
|
<!doctype html>
|
|
3
3
|
<html>
|
|
4
4
|
<head>
|
|
@@ -8,24 +8,78 @@
|
|
|
8
8
|
<link rel="stylesheet" href="../bundle.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
|
-
<div class="ws-stage ws-stage--grey"
|
|
11
|
+
<div class="ws-stage ws-stage--grey">
|
|
12
12
|
|
|
13
|
-
<div class="ws-
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
<span class="ws-tooltip">
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
</div>
|
|
13
|
+
<div class="ws-stack" style="width: 160px; gap: var(--space-3xl); align-items: center;">
|
|
14
|
+
<span class="ws-muted">Centred, 8 above its control</span>
|
|
15
|
+
<span class="ws-tooltip ws-tooltip--open">
|
|
16
|
+
<span class="ws-tooltip__tip" role="tooltip" id="tip-centre">Ask about this</span>
|
|
17
|
+
<button type="button" class="ws-icon-btn ws-icon-btn--outline" aria-labelledby="tip-centre">
|
|
18
|
+
<svg viewBox="0 0 16 16" fill="none"><path d="M6 6a2 2 0 1 1 3 1.7c-.6.4-1 .9-1 1.6v.4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="8" cy="12" r="0.75" fill="currentColor"/></svg>
|
|
19
|
+
</button>
|
|
20
|
+
</span>
|
|
21
|
+
</div>
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
<div class="ws-stack" style="width: 160px; gap: var(--space-3xl); align-items: center;">
|
|
24
|
+
<span class="ws-muted">At rest, nothing shows</span>
|
|
25
|
+
<span class="ws-tooltip">
|
|
26
|
+
<span class="ws-tooltip__tip" role="tooltip" id="tip-rest">Search</span>
|
|
27
|
+
<button type="button" class="ws-icon-btn ws-icon-btn--outline" aria-labelledby="tip-rest">
|
|
27
28
|
<svg viewBox="0 0 16 16" fill="none"><circle cx="7" cy="7" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M13 13l-2.5-2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
28
29
|
</button>
|
|
30
|
+
</span>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="ws-stack" style="width: 160px; gap: var(--space-3xl); align-items: flex-start;">
|
|
34
|
+
<span class="ws-muted">Near the left edge: flush to the start</span>
|
|
35
|
+
<span class="ws-tooltip ws-tooltip--start ws-tooltip--open">
|
|
36
|
+
<span class="ws-tooltip__tip" role="tooltip" id="tip-start">Refresh the audit</span>
|
|
37
|
+
<button type="button" class="ws-icon-btn ws-icon-btn--outline" aria-labelledby="tip-start">
|
|
38
|
+
<svg viewBox="0 0 16 16" fill="none"><path d="M13 8a5 5 0 1 1-1.5-3.5M13 3v2.5h-2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
39
|
+
</button>
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="ws-stack" style="width: 160px; padding-bottom: var(--space-2xl); align-items: flex-end;">
|
|
44
|
+
<span class="ws-muted">Near the right edge: below, flush to the end</span>
|
|
45
|
+
<span class="ws-tooltip ws-tooltip--end ws-tooltip--below ws-tooltip--open">
|
|
46
|
+
<span class="ws-tooltip__tip" role="tooltip" id="tip-end">Settings</span>
|
|
47
|
+
<button type="button" class="ws-icon-btn ws-icon-btn--outline" aria-labelledby="tip-end">
|
|
48
|
+
<svg viewBox="0 0 16 16" fill="none"><path d="M8 2v2M8 12v2M3 8H1M15 8h-2M4 4l1.4 1.4M10.6 10.6L12 12M4 12l1.4-1.4M10.6 5.4L12 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="8" cy="8" r="2.5" stroke="currentColor" stroke-width="1.5"/></svg>
|
|
49
|
+
</button>
|
|
50
|
+
</span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="ws-stack" style="width: 360px; gap: var(--space-6xl);">
|
|
54
|
+
<span class="ws-muted">The note: the full words behind a short one, a caret on its middle</span>
|
|
55
|
+
<div class="ws-row__title" style="padding: 0 0 var(--space-md) var(--space-md);">
|
|
56
|
+
<span class="ws-tooltip ws-tooltip--note ws-tooltip--open">
|
|
57
|
+
<span class="ws-tooltip__tip" role="tooltip" id="note-buyer">I'm thinking of buying a home in Chagrin Falls, OH. Which real estate agent or team should I talk to?</span>
|
|
58
|
+
<button type="button" class="ws-tooltip__term" aria-describedby="note-buyer">A buyer</button>
|
|
59
|
+
</span>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div class="ws-stack" style="width: 360px; padding-bottom: var(--space-5xl);">
|
|
64
|
+
<span class="ws-muted">Near the top of its card the note opens below, its caret turned up; in a sentence the term keeps the line</span>
|
|
65
|
+
<p class="ws-body" style="padding-left: var(--space-md);"><span class="ws-tooltip ws-tooltip--note ws-tooltip--below ws-tooltip--open"><span class="ws-tooltip__tip" role="tooltip" id="note-seller">I'm thinking of selling my home in Chagrin Falls, OH. Who should I list it with?</span><button type="button" class="ws-tooltip__term" aria-describedby="note-seller">A seller</button></span> asked it on Nov 2, and twice more after.</p>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div class="ws-stack" style="width: 360px; gap: var(--space-3xl);" data-live>
|
|
69
|
+
<span class="ws-muted">Live: point at or tab to each. The tip pops out of .9 on the pop spring after the 40 ms hover intent and fades off over 180 ms; the note pops with its caret</span>
|
|
70
|
+
<div class="ws-cluster" style="gap: var(--space-xl);">
|
|
71
|
+
<span class="ws-tooltip">
|
|
72
|
+
<span class="ws-tooltip__tip" role="tooltip" id="tip-live-1">Search</span>
|
|
73
|
+
<button type="button" class="ws-icon-btn ws-icon-btn--outline" aria-labelledby="tip-live-1"><svg viewBox="0 0 16 16" fill="none"><circle cx="7" cy="7" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M13 13l-2.5-2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>
|
|
74
|
+
</span>
|
|
75
|
+
<span class="ws-tooltip">
|
|
76
|
+
<span class="ws-tooltip__tip" role="tooltip" id="tip-live-2">Refresh the audit</span>
|
|
77
|
+
<button type="button" class="ws-icon-btn ws-icon-btn--outline" aria-labelledby="tip-live-2"><svg viewBox="0 0 16 16" fill="none"><path d="M13 8a5 5 0 1 1-1.5-3.5M13 3v2.5h-2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
|
78
|
+
</span>
|
|
79
|
+
<span class="ws-tooltip ws-tooltip--note">
|
|
80
|
+
<span class="ws-tooltip__tip" role="tooltip" id="note-live">Asked by people who want to buy a home here.</span>
|
|
81
|
+
<button type="button" class="ws-tooltip__term" aria-describedby="note-live">A buyer</button>
|
|
82
|
+
</span>
|
|
29
83
|
</div>
|
|
30
84
|
</div>
|
|
31
85
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* ---- Tooltip: a control's name on hover or keyboard focus, North's compact tip; --note is Seth's navy note with a caret
|
|
2
|
+
over the word it explains (305:2272) ---- */
|
|
3
|
+
/* The tip: 6 / 10 inside, 6 px corners, the hairline and the tip drop, 12 px semibold navy on one line (a longer name
|
|
4
|
+
wraps at 440, or the window less 32, and is never cut), 8 above its control and centred on it. Hidden until the control is hovered (after the 40 ms hover intent) or takes keyboard
|
|
5
|
+
focus (at once); never on a tap, so the control's own name must carry the meaning. --open shows it (a tap toggle,
|
|
6
|
+
or a preview). The bridge (::before) keeps it while the pointer crosses the gap, so it can be hovered. */
|
|
7
|
+
.ws-tooltip { --ws-tooltip-gap: var(--space-xs); --ws-tooltip-from: var(--ws-nudge); position: relative; display: inline-flex; vertical-align: top; }
|
|
8
|
+
.ws-tooltip::before { content: ""; position: absolute; right: 0; bottom: 100%; left: 0; height: var(--ws-tooltip-gap); pointer-events: none; }
|
|
9
|
+
.ws-tooltip__tip { position: absolute; bottom: calc(100% + var(--ws-tooltip-gap)); left: 50%; z-index: var(--z-dropdown); width: max-content; max-width: min(var(--ws-thing-width), calc(100vw - var(--space-xl))); padding: var(--space-xxs-plus) var(--space-xs-plus); border-radius: var(--ws-radius-row); background: var(--ws-raised); box-shadow: var(--ws-shadow-hairline), var(--ws-shadow-tip); font-size: var(--ws-text-dense); line-height: var(--space-md); font-weight: 600; color: var(--color-text-heading); white-space: normal; text-wrap: balance; translate: -50% 0; transform-origin: bottom center; opacity: 0; visibility: hidden; pointer-events: none; }
|
|
10
|
+
@media (hover: hover) {
|
|
11
|
+
.ws-tooltip:hover::before { pointer-events: auto; }
|
|
12
|
+
.ws-tooltip:hover > .ws-tooltip__tip { opacity: 1; visibility: visible; pointer-events: auto; }
|
|
13
|
+
}
|
|
14
|
+
.ws-tooltip--open > .ws-tooltip__tip, .ws-tooltip:has(:focus-visible) > .ws-tooltip__tip { opacity: 1; visibility: visible; pointer-events: auto; }
|
|
15
|
+
/* Placement: --below under the control; --start and --end flush to its left or right edge, for a control near the
|
|
16
|
+
side of its container. */
|
|
17
|
+
.ws-tooltip--below { --ws-tooltip-from: calc(var(--ws-nudge) * -1); }
|
|
18
|
+
.ws-tooltip--below::before { top: 100%; bottom: auto; }
|
|
19
|
+
.ws-tooltip--below > .ws-tooltip__tip { top: calc(100% + var(--ws-tooltip-gap)); bottom: auto; transform-origin: top center; }
|
|
20
|
+
.ws-tooltip--start > .ws-tooltip__tip { left: 0; translate: none; transform-origin: bottom left; }
|
|
21
|
+
.ws-tooltip--end > .ws-tooltip__tip { right: 0; left: auto; translate: none; transform-origin: bottom right; }
|
|
22
|
+
/* The note (Seth, 305:2272): the brand navy with white words in both themes (D12; in dark the float rim, a faint light
|
|
23
|
+
line, is its only shadow), 4 px corners, 10 / 12 inside, 14 / 20 words that wrap at 300.
|
|
24
|
+
Its words start where the word it explains starts (the 12 px padding hangs left of it); a 12 x 6 caret points at
|
|
25
|
+
that word's middle, 4 above it. It shows on hover, focus and tap (--open). __term is that word: dotted underline,
|
|
26
|
+
the cue that more shows. */
|
|
27
|
+
.ws-tooltip--note { --ws-tooltip-gap: calc(var(--space-xxs-plus) + var(--ws-nudge)); }
|
|
28
|
+
.ws-tooltip--note > .ws-tooltip__tip { left: calc(var(--space-sm) * -1); max-width: min(calc(var(--ws-float-width) + var(--space-sm) * 2), calc(100vw - var(--space-xl))); padding: var(--space-xs-plus) var(--space-sm); border-radius: var(--ws-radius-control); background: var(--ws-inverse); box-shadow: var(--ws-float-rim); font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 400; color: var(--ws-on-inverse); text-wrap: wrap; translate: none; transform-origin: bottom left; }
|
|
29
|
+
.ws-tooltip--note.ws-tooltip--end > .ws-tooltip__tip { right: calc(var(--space-sm) * -1); left: auto; transform-origin: bottom right; }
|
|
30
|
+
.ws-tooltip--note::after { content: ""; position: absolute; bottom: calc(100% + var(--ws-nudge)); left: 50%; width: var(--space-sm); height: var(--space-xxs-plus); background: var(--ws-inverse); clip-path: polygon(0 0, 100% 0, 50% 100%); translate: -50% 0; opacity: 0; visibility: hidden; pointer-events: none; }
|
|
31
|
+
@media (hover: hover) { .ws-tooltip--note:hover::after { opacity: 1; visibility: visible; } }
|
|
32
|
+
.ws-tooltip--note.ws-tooltip--open::after, .ws-tooltip--note:has(:focus-visible)::after { opacity: 1; visibility: visible; }
|
|
33
|
+
/* --dismissed: Escape hides it while the pointer or focus stays (WCAG 1.4.13); the app removes it when they leave. */
|
|
34
|
+
.ws-tooltip.ws-tooltip--dismissed > .ws-tooltip__tip, .ws-tooltip.ws-tooltip--dismissed::after { opacity: 0; visibility: hidden; pointer-events: none; }
|
|
35
|
+
/* --note --below: the note under its term, the caret turned up to it. */
|
|
36
|
+
.ws-tooltip--note.ws-tooltip--below > .ws-tooltip__tip { transform-origin: top left; }
|
|
37
|
+
.ws-tooltip--note.ws-tooltip--below::after { top: calc(100% + var(--ws-nudge)); bottom: auto; clip-path: polygon(50% 0, 100% 100%, 0 100%); }
|
|
38
|
+
/* Where the browser places by anchor, the tip and the note's caret are fixed to the wrapper as their anchor, so no
|
|
39
|
+
scroller, card or stage that clips can cut them (K9: AppShell's body scrolls and its stage clips, so a tip on the bar
|
|
40
|
+
or on the body's first row was cut). They take the same places from the anchor's edges; a plain tip with no room
|
|
41
|
+
turns to the other side or slides along its control to stay on the screen (the note keeps its side, so its caret
|
|
42
|
+
stays on it). Without anchor placement they hang in the wrapper, and inside a box that clips the app portals them. */
|
|
43
|
+
@supports (anchor-scope: all) {
|
|
44
|
+
.ws-tooltip { --ws-tooltip-block: top; --ws-tooltip-inline: span-all; --ws-tooltip-justify: anchor-center; anchor-name: --ws-tooltip; anchor-scope: --ws-tooltip; }
|
|
45
|
+
.ws-tooltip--below { --ws-tooltip-block: bottom; }
|
|
46
|
+
.ws-tooltip--start, .ws-tooltip--note { --ws-tooltip-inline: span-right; --ws-tooltip-justify: normal; }
|
|
47
|
+
.ws-tooltip--end { --ws-tooltip-inline: span-left; --ws-tooltip-justify: normal; }
|
|
48
|
+
.ws-tooltip__tip, .ws-tooltip--note::after { position: fixed; position-anchor: --ws-tooltip; inset: auto; translate: none; }
|
|
49
|
+
.ws-tooltip__tip { position-area: var(--ws-tooltip-block) var(--ws-tooltip-inline); justify-self: var(--ws-tooltip-justify); margin: var(--ws-tooltip-gap) 0; }
|
|
50
|
+
.ws-tooltip:not(.ws-tooltip--note) > .ws-tooltip__tip { position-try-fallbacks: flip-block, --ws-tooltip-right, --ws-tooltip-left, --ws-tooltip-right flip-block, --ws-tooltip-left flip-block; }
|
|
51
|
+
.ws-tooltip--note > .ws-tooltip__tip { margin-inline: calc(var(--space-sm) * -1) 0; }
|
|
52
|
+
.ws-tooltip--note.ws-tooltip--end > .ws-tooltip__tip { margin-inline: 0 calc(var(--space-sm) * -1); }
|
|
53
|
+
.ws-tooltip--note::after { position-area: var(--ws-tooltip-block) span-all; justify-self: anchor-center; margin: var(--ws-nudge) 0; }
|
|
54
|
+
}
|
|
55
|
+
@position-try --ws-tooltip-right { position-area: top span-right; justify-self: normal; }
|
|
56
|
+
@position-try --ws-tooltip-left { position-area: top span-left; justify-self: normal; }
|
|
57
|
+
.ws-tooltip__term { padding: 0; border: 0; background: none; font-weight: inherit; text-decoration: underline dotted var(--ws-line); text-underline-offset: var(--space-xxs); cursor: help; }
|
|
58
|
+
/* On touch the term is 24 tall to a finger, but only its hit area grows, so a term inside a sentence keeps the
|
|
59
|
+
sentence's baseline (a taller box pushed its words 2 px down). */
|
|
60
|
+
@media (pointer: coarse) {
|
|
61
|
+
.ws-tooltip__term { position: relative; }
|
|
62
|
+
.ws-tooltip__term::after { content: ""; position: absolute; inset: calc((100% - var(--space-lg)) / 2) 0; }
|
|
63
|
+
}
|
|
64
|
+
/* Motion (D7, North's "Tooltip pop-in", the pop spring .35 / .1, js@484880): it pops from scale .9 and 4 px toward its
|
|
65
|
+
control (--ws-tooltip-from), growing out of the edge it hangs from; it fades off over 180 ms (North's tip fade,
|
|
66
|
+
css:388), faster than it came. A pointer waits the 40 ms hover intent; keyboard focus shows it at once. With reduced
|
|
67
|
+
motion it simply appears and goes. */
|
|
68
|
+
.ws-tooltip { --ws-tooltip-scale: 0.9; --ws-tooltip-out: 180ms; /* raw: North's .18 s tip fade; a global --ws-duration-fade wanted */ }
|
|
69
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
70
|
+
.ws-tooltip__tip { transform: translateY(var(--ws-tooltip-from)) scale(var(--ws-tooltip-scale)); transition: opacity var(--ws-tooltip-out) var(--ws-ease-exit), transform var(--ws-tooltip-out) var(--ws-ease-exit), visibility 0s linear var(--ws-tooltip-out); }
|
|
71
|
+
.ws-tooltip--note::after { transition: opacity var(--ws-tooltip-out) var(--ws-ease-exit), visibility 0s linear var(--ws-tooltip-out); }
|
|
72
|
+
@media (hover: hover) {
|
|
73
|
+
.ws-tooltip:hover > .ws-tooltip__tip { transform: none; transition: opacity var(--ws-spring-pop-duration) var(--ws-spring-pop) var(--ws-hover-intent), transform var(--ws-spring-pop-duration) var(--ws-spring-pop) var(--ws-hover-intent), visibility 0s linear var(--ws-hover-intent); }
|
|
74
|
+
.ws-tooltip--note:hover::after { transition: opacity var(--ws-spring-pop-duration) var(--ws-spring-pop) var(--ws-hover-intent), visibility 0s linear var(--ws-hover-intent); }
|
|
75
|
+
}
|
|
76
|
+
.ws-tooltip--open > .ws-tooltip__tip, .ws-tooltip:has(:focus-visible) > .ws-tooltip__tip { transform: none; transition: opacity var(--ws-spring-pop-duration) var(--ws-spring-pop), transform var(--ws-spring-pop-duration) var(--ws-spring-pop), visibility 0s; }
|
|
77
|
+
.ws-tooltip--note.ws-tooltip--open::after, .ws-tooltip--note:has(:focus-visible)::after { transition: opacity var(--ws-spring-pop-duration) var(--ws-spring-pop), visibility 0s; }
|
|
78
|
+
}
|
|
@@ -1,65 +1,57 @@
|
|
|
1
|
-
The 56 px bar alone: a wordmark, up to five page links, a search box,
|
|
2
|
-
puts its navigation across the top rather than down the side.
|
|
1
|
+
The 56 px bar alone: a wordmark, up to five page links, a search box, one quiet act and the person, for a product
|
|
2
|
+
that puts its navigation across the top rather than down the side.
|
|
3
3
|
|
|
4
4
|
## Use it when
|
|
5
5
|
|
|
6
|
-
- A product reads better as a row of top-level sections than as a side nav: a handful of destinations, no groups
|
|
7
|
-
|
|
8
|
-
- A page needs its navigation and its identity in one fixed strip, with the content free to use the full width below it.
|
|
9
|
-
- A phone needs the same bar collapsed to the wordmark and a menu.
|
|
6
|
+
- A product reads better as a row of top-level sections than as a side nav: a handful of destinations, no groups.
|
|
7
|
+
- A page needs its navigation and identity in one strip, with the content free to use the width below it.
|
|
10
8
|
|
|
11
9
|
## Not for
|
|
12
10
|
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
second row under this bar (no inner tabs on a page, per the desk's own rule).
|
|
17
|
-
- The chat-first desk: the system's own `Sidebar` is the nav there; this bar is for a conventional product shape instead.
|
|
11
|
+
- More than five sections, or sections that fall into groups: `AppShell`.
|
|
12
|
+
- Moving between views of the same thing (list and board, this month and last): `Segmented` or `Tabs`.
|
|
13
|
+
- The chat-first workspace: the chat's own frame.
|
|
18
14
|
|
|
19
15
|
## Anatomy
|
|
20
16
|
|
|
21
|
-
- Bar: `--ws-header-h`
|
|
22
|
-
|
|
23
|
-
- Wordmark: 16
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
17
|
+
- Bar (`.ws-top-bar`): 56 tall (`--ws-header-h`), 24 at the sides, its parts 24 apart. Flat; in the preview it sits on
|
|
18
|
+
a card so its edge reads.
|
|
19
|
+
- Wordmark (`__wordmark`): 16 / 24 semibold navy.
|
|
20
|
+
- Links (`__links`, `__link`): up to five, 14 px medium in the body grey, 24 apart, each the bar's full height, its
|
|
21
|
+
box bleeding 8 past its words (so the focus ring clears them); the current one (`aria-current="page"`, or `--current`) navy with a 2 px navy underline (`--ws-ring`) on the bar's foot.
|
|
22
|
+
- Search (`__search`): a `<label>` round an `<input type="search">`, 200 wide (it gives way first, down to 96, so
|
|
23
|
+
five links of two words still fit at 60rem), 32 tall (40 on touch), 4 px corners, the field's inset hairline, a 12 px
|
|
24
|
+
icon, the focus ring on the box. The links never shrink under their words.
|
|
25
|
+
- End (`__end`): one 32 px `IconButton` and the person's 32 px avatar, 8 apart.
|
|
26
|
+
- Menu button (`__menu`): an `IconButton`, shown only in the phone form.
|
|
31
27
|
|
|
32
28
|
## Variants and sizes
|
|
33
29
|
|
|
34
30
|
| Variant | Shows |
|
|
35
31
|
| --- | --- |
|
|
36
|
-
| Default
|
|
37
|
-
| Phone (
|
|
32
|
+
| Default | Wordmark, links, search, an icon button, the avatar |
|
|
33
|
+
| Phone form (under 60rem of window, or `--phone` at any width) | The wordmark at the left, the menu button at the right, 16 px sides; the links, search and quiet act move into the menu it opens |
|
|
38
34
|
|
|
39
35
|
## States
|
|
40
36
|
|
|
41
|
-
- **
|
|
42
|
-
- **
|
|
43
|
-
- **
|
|
44
|
-
|
|
45
|
-
- **Long link label**: the bar
|
|
46
|
-
|
|
47
|
-
- **Empty search**: shows the placeholder "Search" only; it is never the only way to reach a page.
|
|
48
|
-
- **Narrow desktop**: below the five links' combined width, drop the least-used link into an overflow `Menu` rather than
|
|
49
|
-
shrinking words or wrapping the bar.
|
|
37
|
+
- **Current link**: navy words and the underline, set by `aria-current="page"`, never colour alone.
|
|
38
|
+
- **Hover** (pointers that hover): a link's words darken to navy over 200 ms; the underline stays the current link's.
|
|
39
|
+
- **Focus**: the house's 2 px navy ring on each link (drawn inside it on 4 px corners, since a link is the bar's full
|
|
40
|
+
height), on the search's box and on the icon button.
|
|
41
|
+
- **Long link label**: the bar never wraps; a label this long belongs in `AppShell`'s nav.
|
|
42
|
+
- **Empty search**: "Search" only; it is never the only way to reach a page.
|
|
50
43
|
|
|
51
44
|
## Behaviour
|
|
52
45
|
|
|
53
|
-
- Keyboard: links are real `<a
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
- Motion:
|
|
58
|
-
or simply present under the current link.
|
|
46
|
+
- Keyboard: links are real `<a>`s in document order, then the search and the icon button.
|
|
47
|
+
- Touch: the bar's controls grow to the 40 px floor.
|
|
48
|
+
- The phone form is set by the window (60rem, where five links and the search stop fitting), since the bar is the
|
|
49
|
+
window's own strip.
|
|
50
|
+
- Motion: only the link colour. The underline can slide between links in React; in plain HTML it is simply present.
|
|
59
51
|
|
|
60
52
|
## Content
|
|
61
53
|
|
|
62
|
-
- The wordmark is the product's name only
|
|
54
|
+
- The wordmark is the product's name only.
|
|
63
55
|
- Link words are the page's own name, sentence case, one or two words.
|
|
64
56
|
- No em dashes.
|
|
65
57
|
|
|
@@ -71,23 +63,45 @@ puts its navigation across the top rather than down the side.
|
|
|
71
63
|
| `search` | `{ placeholder, onSearch }` | The inline search box |
|
|
72
64
|
| `actions` | `IconButtonProps[]` | Quiet global acts, icon only |
|
|
73
65
|
| `person` | `{ name, initials }` | The avatar at the right |
|
|
74
|
-
| `phone` | `boolean` |
|
|
66
|
+
| `phone` | `boolean` | The phone form at any width |
|
|
75
67
|
|
|
76
68
|
## Rules
|
|
77
69
|
|
|
78
|
-
- **Five links, not more**: past five,
|
|
79
|
-
- **One underline, the current page's**: never two
|
|
80
|
-
|
|
81
|
-
- **No inner tabs on a page** carries over here too: a page below this bar still never draws its own second tab row for
|
|
82
|
-
the same navigation job.
|
|
83
|
-
- **Source**: Intentional addition, decided from the system (26 Oct 2026): a flat-hierarchy product reads better with its
|
|
84
|
-
navigation across the top than down a 232 px side nav it would barely fill. Derived from `--ws-header-h` (the desk's
|
|
85
|
-
and a page's own header line), the link colour and underline rule already used for the current item elsewhere (the
|
|
86
|
-
navy thumb pattern in `Segmented`'s tabs), and the avatar and icon-button sizes used everywhere else in the system.
|
|
70
|
+
- **Five links, not more**: past five, move to `AppShell`.
|
|
71
|
+
- **One underline, the current page's**: never two, never a filled pill.
|
|
72
|
+
- **No inner tabs on a page** for the same navigation job.
|
|
87
73
|
|
|
88
74
|
## Source
|
|
89
75
|
|
|
90
|
-
**Derived from**: `--ws-header-h
|
|
91
|
-
|
|
92
|
-
**Precedent**: an intentional addition decided from the system,
|
|
93
|
-
|
|
76
|
+
**Derived from**: `--ws-header-h`, the current-link underline, the avatar and icon-button sizes used across the
|
|
77
|
+
system, and the geometry check (4 Nov 2026: at 390 the end ran to 428 and the fifth link to 445, the page scrolled
|
|
78
|
+
55 px sideways, because only `--phone` collapsed it). **Precedent**: an intentional addition decided from the system,
|
|
79
|
+
26 Oct 2026.
|
|
80
|
+
|
|
81
|
+
## Markup
|
|
82
|
+
|
|
83
|
+
```html
|
|
84
|
+
<nav class="ws-top-bar" aria-label="Main">
|
|
85
|
+
<span class="ws-top-bar__wordmark">Fello</span>
|
|
86
|
+
<div class="ws-top-bar__links">
|
|
87
|
+
<a href="/pipeline" class="ws-top-bar__link" aria-current="page">Pipeline</a>
|
|
88
|
+
<a href="/leads" class="ws-top-bar__link">Leads</a>
|
|
89
|
+
</div>
|
|
90
|
+
<label class="ws-top-bar__search">
|
|
91
|
+
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><circle cx="6.8" cy="6.8" r="3.8"/><path d="M9.7 9.7l3.6 3.6"/></svg>
|
|
92
|
+
<input type="search" placeholder="Search" aria-label="Search">
|
|
93
|
+
</label>
|
|
94
|
+
<div class="ws-top-bar__end">
|
|
95
|
+
<button type="button" class="ws-icon-btn" aria-label="Notifications"><!-- 16 px icon --></button>
|
|
96
|
+
<span class="ws-avatar">PN</span>
|
|
97
|
+
</div>
|
|
98
|
+
<button type="button" class="ws-icon-btn ws-top-bar__menu" aria-label="Open the menu"><!-- 16 px icon --></button>
|
|
99
|
+
</nav>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Styles
|
|
103
|
+
|
|
104
|
+
`TopBar/style.css`, with `IconButton` and `Avatar` for the menu button, the quiet act and the person. Tokens: `--ws-header-h`, `--ws-text-value`,
|
|
105
|
+
`--ws-text-body`, `--ws-text-meta`, `--ws-control-h`, `--ws-ring`, `--ws-radius-control`, `--ws-radius-bar`,
|
|
106
|
+
`--ws-field`, `--ws-field-ink`, `--ws-edge-card`, `--ws-hairline`, `--ws-touch`, `--ws-focus-width`, `--ws-focus-color`,
|
|
107
|
+
`--ws-focus-offset`, `--space-6xl`, `--color-text-heading`, `--color-text-body`, `--color-text-muted`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- @dsCard group="Navigation" height=
|
|
1
|
+
<!-- @dsCard group="Navigation" height=232 -->
|
|
2
2
|
<!doctype html>
|
|
3
3
|
<html>
|
|
4
4
|
<head>
|
|
@@ -8,53 +8,40 @@
|
|
|
8
8
|
<link rel="stylesheet" href="../bundle.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
|
-
<div class="ws-stage ws-stage--grey ws-stage--column"
|
|
11
|
+
<div class="ws-stage ws-stage--grey ws-stage--column">
|
|
12
12
|
|
|
13
13
|
<div class="ws-stack">
|
|
14
|
-
<span class="ws-muted">Default: wordmark, up to five links, the current one navy and underlined, search, an icon button, the avatar</span>
|
|
14
|
+
<span class="ws-muted">Default: wordmark, up to five links, the current one navy and underlined, search, an icon button, the avatar; under 60rem of window it is the phone form</span>
|
|
15
15
|
<nav class="ws-card ws-top-bar" aria-label="Main">
|
|
16
16
|
<span class="ws-top-bar__wordmark">Fello</span>
|
|
17
17
|
<div class="ws-top-bar__links">
|
|
18
|
-
<a href="#" class="ws-top-bar__link
|
|
18
|
+
<a href="#" class="ws-top-bar__link" aria-current="page" onclick="return false;">Pipeline</a>
|
|
19
19
|
<a href="#" class="ws-top-bar__link" onclick="return false;">Leads</a>
|
|
20
20
|
<a href="#" class="ws-top-bar__link" onclick="return false;">Listings</a>
|
|
21
21
|
<a href="#" class="ws-top-bar__link" onclick="return false;">Reports</a>
|
|
22
|
+
<a href="#" class="ws-top-bar__link" onclick="return false;">Settings</a>
|
|
22
23
|
</div>
|
|
23
|
-
<
|
|
24
|
-
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="6.8" cy="6.8" r="3.8"/><path d="M9.7 9.7l3.6 3.6"/></svg>
|
|
25
|
-
Search
|
|
26
|
-
</
|
|
24
|
+
<label class="ws-top-bar__search">
|
|
25
|
+
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="6.8" cy="6.8" r="3.8"/><path d="M9.7 9.7l3.6 3.6"/></svg>
|
|
26
|
+
<input type="search" placeholder="Search" aria-label="Search">
|
|
27
|
+
</label>
|
|
27
28
|
<div class="ws-top-bar__end">
|
|
28
29
|
<button type="button" class="ws-icon-btn" aria-label="Notifications">
|
|
29
30
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11.5V7a4 4 0 0 1 8 0v4.5l1 1.5H3l1-1.5Z"/><path d="M6.5 14.5h3"/></svg>
|
|
30
31
|
</button>
|
|
31
32
|
<span class="ws-avatar">PN</span>
|
|
32
33
|
</div>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<div class="ws-stack" style="max-width: 760px;">
|
|
37
|
-
<span class="ws-muted">Five links, a long one truncating never: it wraps the bar before it clips</span>
|
|
38
|
-
<nav class="ws-card ws-top-bar" aria-label="Main">
|
|
39
|
-
<span class="ws-top-bar__wordmark">Fello</span>
|
|
40
|
-
<div class="ws-top-bar__links">
|
|
41
|
-
<a href="#" class="ws-top-bar__link" onclick="return false;">Pipeline</a>
|
|
42
|
-
<a href="#" class="ws-top-bar__link ws-top-bar__link--current" aria-current="page" onclick="return false;">Leads</a>
|
|
43
|
-
<a href="#" class="ws-top-bar__link" onclick="return false;">Listings</a>
|
|
44
|
-
<a href="#" class="ws-top-bar__link" onclick="return false;">Reports</a>
|
|
45
|
-
<a href="#" class="ws-top-bar__link" onclick="return false;">Settings</a>
|
|
46
|
-
</div>
|
|
47
|
-
<div class="ws-top-bar__end">
|
|
48
|
-
<span class="ws-avatar">PN</span>
|
|
49
|
-
</div>
|
|
34
|
+
<button type="button" class="ws-icon-btn ws-top-bar__menu" aria-label="Open the menu">
|
|
35
|
+
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 4.5h11M2.5 8h11M2.5 11.5h11"/></svg>
|
|
36
|
+
</button>
|
|
50
37
|
</nav>
|
|
51
38
|
</div>
|
|
52
39
|
|
|
53
40
|
<div class="ws-stack" style="width: 375px; max-width: 100%;">
|
|
54
|
-
<span class="ws-muted"
|
|
41
|
+
<span class="ws-muted">--phone at any width: the wordmark and the menu button only; the links, search and quiet act are in the menu it opens</span>
|
|
55
42
|
<nav class="ws-card ws-top-bar ws-top-bar--phone" aria-label="Main">
|
|
56
43
|
<span class="ws-top-bar__wordmark">Fello</span>
|
|
57
|
-
<button type="button" class="ws-icon-btn" aria-label="Open the menu">
|
|
44
|
+
<button type="button" class="ws-icon-btn ws-top-bar__menu" aria-label="Open the menu">
|
|
58
45
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 4.5h11M2.5 8h11M2.5 11.5h11"/></svg>
|
|
59
46
|
</button>
|
|
60
47
|
</nav>
|