@boost33/ui 0.7.0 → 0.8.0-next.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/CHANGELOG.md +248 -3
- package/dist/buttons.module.css.js +10 -0
- package/dist/buttons.module.css.js.map +1 -0
- package/dist/components/AppShell/AppShell.d.ts +99 -21
- package/dist/components/AppShell/AppShell.js +76 -50
- package/dist/components/AppShell/AppShell.js.map +1 -1
- package/dist/components/AppShell/AppShell.module.css.js +22 -16
- package/dist/components/AppShell/AppShell.module.css.js.map +1 -1
- package/dist/components/AppSwitcher/AppSwitcher.d.ts +90 -45
- package/dist/components/AppSwitcher/AppSwitcher.js +71 -66
- package/dist/components/AppSwitcher/AppSwitcher.js.map +1 -1
- package/dist/components/AppSwitcher/AppSwitcher.module.css.js +42 -36
- package/dist/components/AppSwitcher/AppSwitcher.module.css.js.map +1 -1
- package/dist/components/AppSwitcher/icons.js +10 -10
- package/dist/components/AppSwitcher/icons.js.map +1 -1
- package/dist/components/AppSwitcher/labels.d.ts +11 -22
- package/dist/components/AppSwitcher/labels.js.map +1 -1
- package/dist/components/Boost33Mark/Boost33Mark.d.ts +37 -4
- package/dist/components/Boost33Mark/Boost33Mark.js +15 -15
- package/dist/components/Boost33Mark/Boost33Mark.js.map +1 -1
- package/dist/components/Boost33Mark/Boost33Mark.module.css.js +10 -8
- package/dist/components/Boost33Mark/Boost33Mark.module.css.js.map +1 -1
- package/dist/components/CommandPalette/CommandPalette.d.ts +8 -2
- package/dist/components/CommandPalette/CommandPalette.js.map +1 -1
- package/dist/components/NavItem/NavItem.d.ts +15 -2
- package/dist/components/NavItem/NavItem.js +14 -11
- package/dist/components/NavItem/NavItem.js.map +1 -1
- package/dist/components/NavItem/NavItem.module.css.js +6 -2
- package/dist/components/NavItem/NavItem.module.css.js.map +1 -1
- package/dist/components/NavSection/NavSection.module.css.js +5 -5
- package/dist/components/NotificationButton/NotificationButton.d.ts +29 -0
- package/dist/components/NotificationButton/NotificationButton.js +23 -0
- package/dist/components/NotificationButton/NotificationButton.js.map +1 -0
- package/dist/components/NotificationButton/NotificationButton.module.css.js +14 -0
- package/dist/components/NotificationButton/NotificationButton.module.css.js.map +1 -0
- package/dist/components/NotificationButton/labels.d.ts +12 -0
- package/dist/components/NotificationButton/labels.js +15 -0
- package/dist/components/NotificationButton/labels.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationCenter.js +37 -36
- package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.module.css.js +43 -43
- package/dist/components/Sidebar/NavHeightBudgetWarning.js +2 -2
- package/dist/components/Sidebar/NavHeightBudgetWarning.js.map +1 -1
- package/dist/components/Sidebar/Sidebar.module.css.js +1 -1
- package/dist/components/TopBar/TopBar.d.ts +54 -4
- package/dist/components/TopBar/TopBar.js +22 -7
- package/dist/components/TopBar/TopBar.js.map +1 -1
- package/dist/components/TopBar/TopBar.module.css.js +12 -8
- package/dist/components/TopBar/TopBar.module.css.js.map +1 -1
- package/dist/components/TopBar/labels.d.ts +20 -0
- package/dist/components/TopBar/labels.js +15 -0
- package/dist/components/TopBar/labels.js.map +1 -0
- package/dist/components/WalletChip/WalletChip.d.ts +77 -2
- package/dist/components/WalletChip/WalletChip.js +142 -50
- package/dist/components/WalletChip/WalletChip.js.map +1 -1
- package/dist/components/WalletChip/WalletChip.module.css.js +93 -47
- package/dist/components/WalletChip/WalletChip.module.css.js.map +1 -1
- package/dist/components/WalletChip/labels.d.ts +63 -1
- package/dist/components/WalletChip/labels.js +21 -6
- package/dist/components/WalletChip/labels.js.map +1 -1
- package/dist/components/Wordmark/Wordmark.d.ts +29 -2
- package/dist/components/Wordmark/Wordmark.js +9 -8
- package/dist/components/Wordmark/Wordmark.js.map +1 -1
- package/dist/components/Wordmark/Wordmark.module.css.js +7 -7
- package/dist/index.d.ts +9 -3
- package/dist/index.js +55 -49
- package/dist/index.js.map +1 -1
- package/dist/nav-height-budget.d.ts +12 -9
- package/dist/nav-height-budget.js +3 -3
- package/dist/nav-height-budget.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/theme.css +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -31,6 +31,189 @@ Three components are built to Stage A on main and are not releasable until
|
|
|
31
31
|
each passes its fidelity gate. Their entries wait here for the release that
|
|
32
32
|
ships them.
|
|
33
33
|
|
|
34
|
+
### Changed — the shell redesign, part 1 of 3: the sidebar and the app switcher (B33-1711)
|
|
35
|
+
|
|
36
|
+
The 3 Nov 2026 navigation redesign (B33-1710; Paper file Boost Products, page
|
|
37
|
+
101 Hub, row V0.7, boards 20 and 21). **This changes how every consumer's
|
|
38
|
+
sidebar and switcher look, and every gated screenshot of them.** No new
|
|
39
|
+
baseline has been captured: the person approving the redesign captures them
|
|
40
|
+
(CLAUDE.md). Parts 2 and 3 (B33-1712, B33-1713) land in the same release.
|
|
41
|
+
|
|
42
|
+
What a consumer sees, and what it has to do:
|
|
43
|
+
|
|
44
|
+
- **`AppShell` takes `appName`.** The product's name, drawn as plain text at
|
|
45
|
+
the top of the sidebar with no icon. Optional: omit it and nothing draws
|
|
46
|
+
there. Pass your product's display name, in your language. It names no
|
|
47
|
+
landmark (`label` still does that).
|
|
48
|
+
- **`AppSwitcher` no longer draws products that do not exist yet.** A row with
|
|
49
|
+
`live: false` is left out, unless it is the current product. Keep passing the
|
|
50
|
+
registry whole -- do not filter it yourself. A product the account does not
|
|
51
|
+
hold (`entitled: false`) is still drawn, with its "Not on plan" tag: hiding it
|
|
52
|
+
would tell a client their product does not exist. This overrules the
|
|
53
|
+
Vocabulary document's "the switcher shows every product regardless of state",
|
|
54
|
+
which is amended to match.
|
|
55
|
+
- **The "Soon" tag is gone with them.** `labels.soon` stays in the type and is
|
|
56
|
+
ignored, so a labels object that sets it still compiles. Drop it when
|
|
57
|
+
convenient.
|
|
58
|
+
- **The switcher's account row is gone.** `account` is now optional and
|
|
59
|
+
ignored, and `AppSwitcherAccount` is deprecated. The organisation moves to the
|
|
60
|
+
top bar in part 2. Nothing breaks if you keep passing it; stop when
|
|
61
|
+
convenient. Its `onSelect` is never called.
|
|
62
|
+
- **New, optional, per product row:** `group` (a section header, e.g. "Your
|
|
63
|
+
tools" -- rows are grouped in the order served; no groups means one plain
|
|
64
|
+
list) and `trailing` (`{ kind: 'value', value: '8,940' }` or
|
|
65
|
+
`{ kind: 'dot', label: '2 new' }` -- the dot's `label` is what a screen reader
|
|
66
|
+
hears). Both are data you are served; the switcher fetches nothing.
|
|
67
|
+
- **The switcher is redrawn to board 21.** A 32px tinted trigger with no border
|
|
68
|
+
and the product name in the display face; a 360px borderless panel; a dark
|
|
69
|
+
Hub row with a chevron; 28px product tiles; the current row semibold on a
|
|
70
|
+
muted ground. The product marks are unchanged (the set approved 29 Oct 2026).
|
|
71
|
+
- **Nav rows:** the active label is regular weight now, not semibold (the white
|
|
72
|
+
row and full-ink colour carry "you are here"). Counts are 12px medium and
|
|
73
|
+
right-aligned. `countUrgent` draws a filled pill instead of orange text --
|
|
74
|
+
white on `--color-orange-600`, 5.18:1, because the old orange text was 3.45:1
|
|
75
|
+
on the sidebar and failed AA. New `dot` on `NavItem` and `AppShellNavItem`: a
|
|
76
|
+
7px attention dot, its string read by a screen reader.
|
|
77
|
+
- **Section labels** track at 0.09em (`--tracking-wider`), up from 0.05em.
|
|
78
|
+
- **Three new component-private tokens** (in `style.css`, no Tailwind
|
|
79
|
+
utility): `--container-app-switcher` (360px), `--spacing-2_75` (11px),
|
|
80
|
+
`--spacing-1_75` (7px).
|
|
81
|
+
|
|
82
|
+
The 56px rail keeps working, icon-only. The redesign draws no rail, so it gets
|
|
83
|
+
no new design.
|
|
84
|
+
|
|
85
|
+
Repo-only: the specimen's unarmed-switcher route is removed (the row it showed
|
|
86
|
+
is gone), and a new "Shell redesign — B33-1710" route at the bottom of the
|
|
87
|
+
specimen assembles boards 20 and 21 for review.
|
|
88
|
+
|
|
89
|
+
### Changed — the shell redesign, part 3 of 3: the sidebar action, and every button on three tiers (B33-1713)
|
|
90
|
+
|
|
91
|
+
Board 20 of the same redesign, and the consolidation its review asked for.
|
|
92
|
+
**Every button the package draws changes look**; no new baseline has been
|
|
93
|
+
captured (the person approving the redesign captures them).
|
|
94
|
+
|
|
95
|
+
What a consumer sees, and what it has to do:
|
|
96
|
+
|
|
97
|
+
- **New `AppShell.action`** (`AppShellAction`: `label`, optional `icon`, and
|
|
98
|
+
`href` or `onClick`): your product's main action, drawn at the foot of the
|
|
99
|
+
sidebar directly above the footer's divider -- board 20's "New scan". Near-black,
|
|
100
|
+
full width, 40px. Not drawn with neither `href` nor `onClick`. On the rail it
|
|
101
|
+
shows its icon alone, its label kept as its accessible name, and is not drawn
|
|
102
|
+
if it has no icon. If you drew your own action button elsewhere in the shell,
|
|
103
|
+
pass it here instead.
|
|
104
|
+
- **The footer sits under a hairline when there is an action**, 10px above its
|
|
105
|
+
rows, and its rows are 2px apart (the nav's own pitch), down from 16px.
|
|
106
|
+
- **Three button tiers, written down in ADR-0016:** primary (filled, 40px, ink or
|
|
107
|
+
accent), outlined (32px, white, 1px edge) and quiet (a word, no box). Every
|
|
108
|
+
package button now takes one.
|
|
109
|
+
- **`WalletChip`'s "Top up" is no longer orange text.** At rest it is the quiet
|
|
110
|
+
tier in full ink; past the threshold it is the primary tier in the accent tone.
|
|
111
|
+
The orange text was 3.69:1 on white and failed AA at 12px.
|
|
112
|
+
- **The accent tone is `--color-orange-600`**, not the brand orange: white on the
|
|
113
|
+
brand orange is 3.69:1. "Buy tokens" and the grown "Top up" both use it.
|
|
114
|
+
Decided by Jamal on 4 Nov 2026.
|
|
115
|
+
- **`NotificationCenter`'s "Mark all as read" and "View all"** are the quiet tier.
|
|
116
|
+
The component is still Stage A and not releasable.
|
|
117
|
+
- **If you pass `action`, add 67px to `consumerSlotsPx`** when you call
|
|
118
|
+
`navBudgetForViewport` yourself: the 40px button, 16px clear above it, and the
|
|
119
|
+
hairline and 10px the footer then takes. The development warning measures the
|
|
120
|
+
real column and needs nothing.
|
|
121
|
+
|
|
122
|
+
Not done here, and why: board 20's Settings row carries an external-link arrow,
|
|
123
|
+
which no ticket in Wave 4 asks for and `NavItem` has no slot for. It wants its
|
|
124
|
+
own ticket.
|
|
125
|
+
|
|
126
|
+
Repo-only: `src/buttons.module.css` holds the tiers. The "Shell redesign —
|
|
127
|
+
B33-1710" specimen route's shell gains "New scan" and a Settings / Help footer.
|
|
128
|
+
|
|
129
|
+
### Changed — the shell redesign, part 2 of 3: the top bar, the token chip, the bell (B33-1712)
|
|
130
|
+
|
|
131
|
+
Boards 20, 21 and 22 of the same redesign. **This is a breaking layout change
|
|
132
|
+
for every consumer of `AppShell`: the switcher and the wallet chip move out of
|
|
133
|
+
the sidebar into the top bar, and the breadcrumb is no longer drawn.** Every
|
|
134
|
+
gated screenshot of the shell, the top bar and the sidebar changes; no new
|
|
135
|
+
baseline has been captured (the person approving the redesign captures them).
|
|
136
|
+
|
|
137
|
+
What a consumer sees, and what it has to do:
|
|
138
|
+
|
|
139
|
+
- **The top bar has three regions.** Left: the Boost33 mark (linked home
|
|
140
|
+
through `hubHref`, as the sidebar wordmark was) and the new `org` slot.
|
|
141
|
+
Centre: "Switch Tools →" then the switcher, "Check Your Tokens →" then the
|
|
142
|
+
token chip. Right: `topBar.actions` -- pass `NotificationButton` and your
|
|
143
|
+
avatar there.
|
|
144
|
+
- **`AppShell.switcher` and `AppShell.wallet` keep their names and move.**
|
|
145
|
+
Both now render in the top bar's centre group, not the sidebar. Each label is
|
|
146
|
+
drawn only when its control is passed. Pass `WalletChip` with
|
|
147
|
+
`placement="topbar"` in `wallet`; the sidebar card is not designed for the
|
|
148
|
+
bar.
|
|
149
|
+
- **The sidebar no longer draws the wordmark, the switcher or the wallet
|
|
150
|
+
chip.** It holds `appName`, the nav and `footer`, with 16px top and bottom
|
|
151
|
+
padding of its own.
|
|
152
|
+
- **New `AppShell.org`**: a slot for your organisation pill, beside the mark.
|
|
153
|
+
The package draws no organisation menu (that is AccountMenu, B33-493, which
|
|
154
|
+
has not passed its gate).
|
|
155
|
+
- **`topBar` is optional, and `topBar.breadcrumb` is deprecated and not
|
|
156
|
+
drawn.** It still compiles; stop passing it. `PageHeader` names the page.
|
|
157
|
+
**If you put `SidebarToggle` in `topBar.breadcrumb` (the Wallet does), move it
|
|
158
|
+
to the new `topBar.sidebarToggle` slot, or your rail loses its toggle.** The
|
|
159
|
+
screenshot gate does not catch this: the bar passed its baseline at 0.19%
|
|
160
|
+
with the toggle gone.
|
|
161
|
+
- **New `topBar.sidebarToggle`** (and `TopBar.sidebarToggle`): your rail
|
|
162
|
+
toggle, drawn at the far left of the bar before the mark. No board draws it;
|
|
163
|
+
judged at the gate.
|
|
164
|
+
`topBar.labels` (`TopBarLabels`, `defaultTopBarLabels`) translates the two
|
|
165
|
+
centre labels.
|
|
166
|
+
- **No search, and no `⌘K`.** Search was removed from the top bar on 3 Nov
|
|
167
|
+
2026 until it is built, and nothing replaces it. `CommandPalette` stays in the
|
|
168
|
+
package, Stage A and unreleasable, with no trigger in the shell.
|
|
169
|
+
- **New `WalletChip placement="topbar"`**: a 32px pill drawn like the
|
|
170
|
+
switcher -- the balance in the mono face, a 44 x 6 two-segment bar, a
|
|
171
|
+
chevron -- that opens a 340px popover with the balance, the bar at width,
|
|
172
|
+
granted and purchased with what each means, your `burnNote`, an "Open" link
|
|
173
|
+
(`walletHref`, `linkComponent`) and a "Buy tokens" button (`onTopUp`). A zero
|
|
174
|
+
segment is drawn at 0px with the 2px gap kept, never as a sliver (B33-590).
|
|
175
|
+
`unknown` shows an em dash, no bar and no split. The default
|
|
176
|
+
`placement="sidebar"` card is unchanged.
|
|
177
|
+
- **New `WalletChip totalOnly` with a signed `balance`** (top bar only, enforced
|
|
178
|
+
by the type), for a balance the Ledger reports with a bucket below zero, which
|
|
179
|
+
no two-segment bar can draw honestly. Below zero: the distance past zero in
|
|
180
|
+
`--color-danger` with the words "past zero", as the Wallet's past-zero screen
|
|
181
|
+
says it. At zero or above (a bucket below zero, a positive total -- decided by
|
|
182
|
+
Jamal on 3 Nov 2026): the plain figure. Neither draws a bar or a
|
|
183
|
+
granted / purchased legend. New labels: `pastZero`, `pastZeroLong`,
|
|
184
|
+
`pastZeroBalance`. **No board draws this state; it is judged at the gate.**
|
|
185
|
+
- **New labels for the popover:** `popover`, `grantedFigure`,
|
|
186
|
+
`purchasedFigure`, `grantedNote`, `grantedNoteUndated`, `purchasedNote`,
|
|
187
|
+
`open`, `buyTokens`. Each defaults to English.
|
|
188
|
+
- **New `NotificationButton`**: the 32px bell for `topBar.actions`, with an
|
|
189
|
+
`unread` dot. It fetches nothing and renders nothing without `onClick` or
|
|
190
|
+
`href`. The NotificationCenter panel stays Stage A and is not wired.
|
|
191
|
+
- **"Buy tokens" is white on `--color-orange-600`** (5.18:1), not the brand
|
|
192
|
+
orange board 21 draws (3.69:1, fails AA at 13px). Decided by Jamal on 4 Nov
|
|
193
|
+
2026: orange that carries text is `--color-orange-600`.
|
|
194
|
+
- **The top bar spans the full width,** above the sidebar and the product's
|
|
195
|
+
column alike (board 20). Until now it sat over the content column only and
|
|
196
|
+
the sidebar ran the full height.
|
|
197
|
+
- **Two new component-private tokens:** `--container-token-popover` (340px),
|
|
198
|
+
`--spacing-0_75` (3px).
|
|
199
|
+
- **The nav height budget moves, because the sidebar's furniture moved.**
|
|
200
|
+
`navBudgetForViewport(900)` and `checkNavHeightBudget`'s default budget rise
|
|
201
|
+
from 629 to 730px: the top bar (48) is now counted above the sidebar, and the
|
|
202
|
+
wordmark, switcher and wallet chip no longer take sidebar height. The default
|
|
203
|
+
`consumerSlotsPx` is now 44 (the footer alone), down from 86 (switcher plus
|
|
204
|
+
footer). If you pass your own `consumerSlotsPx`, drop your switcher's height
|
|
205
|
+
from it. A 13-item nav that scrolled at 900px now fits; the dev warning in
|
|
206
|
+
`Sidebar` follows the same numbers.
|
|
207
|
+
- **The app name no longer shrinks** when the nav is long enough to scroll
|
|
208
|
+
(it lost 2px of its 38).
|
|
209
|
+
|
|
210
|
+
The 56px rail keeps working, icon-only, and gets no new design. The top bar
|
|
211
|
+
does not collapse.
|
|
212
|
+
|
|
213
|
+
Repo-only: the specimen's "Shell redesign — B33-1710" route grows the top bar,
|
|
214
|
+
the open token popover, board 22's nothing-purchased chip, and the unknown,
|
|
215
|
+
past-zero and total-only chips.
|
|
216
|
+
|
|
34
217
|
### Changed — `CHANGELOG.md` now ships inside the package
|
|
35
218
|
|
|
36
219
|
`package.json` `files` adds `CHANGELOG.md` next to `dist`, so this file is in
|
|
@@ -309,11 +492,73 @@ most consumers meet first.
|
|
|
309
492
|
still gains no `aria-haspopup`, and it still opens nothing. Connecting the two is
|
|
310
493
|
Stage B.
|
|
311
494
|
|
|
312
|
-
## 0.7.
|
|
495
|
+
## 0.7.1 — 2026-11-02
|
|
496
|
+
|
|
497
|
+
**Not breaking. Nothing to do on upgrade unless you want the link home**, which
|
|
498
|
+
is one prop on `AppShell`. New optional props only; with none of them passed,
|
|
499
|
+
every component renders exactly what 0.7.0 rendered. A patch rather than a minor
|
|
500
|
+
by decision (Jamal, 2 November 2026): under `0.x` either is allowed, and the
|
|
501
|
+
entry below is what tells you what changed.
|
|
502
|
+
|
|
503
|
+
**Held back, as in 0.6.0 and 0.7.0:** the Stage A entries under Unreleased
|
|
504
|
+
(`CommandPalette`, `AccountMenu`, `NotificationCenter`) have still not passed
|
|
505
|
+
their fidelity gate and are not part of this release, even though their exports
|
|
506
|
+
are present in `dist/`.
|
|
507
|
+
|
|
508
|
+
### Added — the Boost33 wordmark can be the link home: `hubHref` on `AppShell`, `Wordmark` and `Boost33Mark` (B33-1699)
|
|
509
|
+
|
|
510
|
+
**Not breaking. Nothing changes until you pass `hubHref`.** Every new prop is
|
|
511
|
+
optional, and with none of them set the wordmark renders the same `div` it did
|
|
512
|
+
before.
|
|
513
|
+
|
|
514
|
+
**Why you want it.** Until now the only way back to the hub from Score, Voice or
|
|
515
|
+
the Wallet was the "Hub" row inside the switcher's panel, and a founder testing
|
|
516
|
+
as a new user could not find it: *"How do I come back to the different
|
|
517
|
+
features... I don't see the button."* The lockup in the top-left corner is where
|
|
518
|
+
people look for that link.
|
|
519
|
+
|
|
520
|
+
**What to do on upgrade.** Pass the hub URL to the shell. The package does not
|
|
521
|
+
know it and never will: Identity owns where the hub lives, and it differs per
|
|
522
|
+
environment.
|
|
523
|
+
|
|
524
|
+
```tsx
|
|
525
|
+
<AppShell hubHref={hubUrl} linkComponent={Link} /* …everything you pass today */ />
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
| Prop | On | What it does |
|
|
529
|
+
| --- | --- | --- |
|
|
530
|
+
| `hubHref?: string` | `AppShell` | Links the sidebar's wordmark to the hub, through the `linkComponent` you already pass the shell. On the rail the mark alone is the link. |
|
|
531
|
+
| `hubHref?: string`, `linkComponent?: ElementType` | `Wordmark` | The same, for a consumer rendering the lockup itself. Same contract as `NavItem` (ADR-0011). |
|
|
532
|
+
| `hubHref?: string`, `linkComponent?: ElementType` | `Boost33Mark` | The mark standing alone as a link. **`title` becomes required** when `hubHref` is set, and the compiler enforces it: a link whose only content is artwork has no accessible name otherwise. |
|
|
533
|
+
|
|
534
|
+
**What you will see.** Nothing, until someone tabs to it. The linked wordmark
|
|
535
|
+
draws the same pixels as the plain one: the `wordmark`, `wordmark-rail` and
|
|
536
|
+
`mark-boost33` baselines pass unchanged with the specimen rendering the linked
|
|
537
|
+
form. Keyboard focus draws the nav rows' ring, a 2px `--color-primary` outline,
|
|
538
|
+
around the lockup. That focus ring is new and is not captured by any baseline.
|
|
539
|
+
|
|
540
|
+
**Three things to check in your app:**
|
|
541
|
+
|
|
542
|
+
- **The link's accessible name is "Boost33"**, the lockup's own text, in every
|
|
543
|
+
locale. That is a brand name, not a phrase, so it is not translated.
|
|
544
|
+
- **Do not also link the mark you pass in.** `mark={<Boost33Mark />}` stays
|
|
545
|
+
unlinked; a linked mark inside a linked lockup nests one anchor in another.
|
|
546
|
+
- **The hub URL is usually on another origin.** `linkComponent` still receives
|
|
547
|
+
it, as the switcher's hub row already does. Next's `Link` and next-intl's
|
|
548
|
+
localised `Link` both pass an absolute URL through as an ordinary navigation.
|
|
549
|
+
|
|
550
|
+
#### Not in `dist/`
|
|
551
|
+
|
|
552
|
+
The Wordmark and AppShell specimen routes render the linked form, new behaviour
|
|
553
|
+
tests in `tests/wordmark.test.tsx`, `tests/boost33-mark.test.tsx` and
|
|
554
|
+
`tests/app-shell.test.tsx`, and a compile-time guard,
|
|
555
|
+
`tests/boost33-mark-link.type-test.tsx`. No baseline changed.
|
|
556
|
+
|
|
557
|
+
## 0.7.0 — 2026-10-29
|
|
313
558
|
|
|
314
559
|
**The redrawn marks' baselines were approved by Jamal on 29 October 2026**
|
|
315
|
-
(`tests/baselines/README.md`, "The 29 October redraw"),
|
|
316
|
-
|
|
560
|
+
(`tests/baselines/README.md`, "The 29 October redraw"), and the release was
|
|
561
|
+
published the same day.
|
|
317
562
|
|
|
318
563
|
**Not breaking. Nothing to do on upgrade, and every product mark looks
|
|
319
564
|
different.** A minor: no export, prop or type changes. `ProductMark` draws new
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buttons.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -10,12 +10,29 @@ export interface AppShellNavItem {
|
|
|
10
10
|
active?: boolean;
|
|
11
11
|
/** Trailing-slot count. Omit to leave the slot empty; it still reserves its width so counts line up. */
|
|
12
12
|
count?: number;
|
|
13
|
-
/**
|
|
13
|
+
/** Draws `count` as the filled "needs you" pill instead of muted text. */
|
|
14
14
|
countUrgent?: boolean;
|
|
15
|
+
/** A trailing attention dot; the string is what a screen reader hears. Ignored when `count` is set. */
|
|
16
|
+
dot?: string;
|
|
15
17
|
/** Where the row goes. A nav row's destination is data; the shell renders it as a link. */
|
|
16
18
|
href?: string;
|
|
17
19
|
}
|
|
18
20
|
/** One nav section: an optional header over a run of rows. */
|
|
21
|
+
/**
|
|
22
|
+
* The product's main action, drawn as a button at the foot of the sidebar,
|
|
23
|
+
* above the footer's divider (B33-1713, board 20's "New scan"). Data, like a
|
|
24
|
+
* nav row: the shell renders it, in the primary tier's ink tone (ADR-0016).
|
|
25
|
+
*/
|
|
26
|
+
export interface AppShellAction {
|
|
27
|
+
/** The button's words, in the consumer's language -- "New scan". */
|
|
28
|
+
label: string;
|
|
29
|
+
/** A leading icon, decorative. On the 56px rail it is all that shows. */
|
|
30
|
+
icon?: ReactNode;
|
|
31
|
+
/** Where it goes. Renders a link through `linkComponent`. Wins over `onClick`. */
|
|
32
|
+
href?: string;
|
|
33
|
+
/** What pressing it does. Renders a `<button>`. */
|
|
34
|
+
onClick?: () => void;
|
|
35
|
+
}
|
|
19
36
|
export interface AppShellNavSection {
|
|
20
37
|
/** The section header. Omit for a headerless section (the nav's first section has none). On the rail every header drops. */
|
|
21
38
|
label?: string;
|
|
@@ -65,43 +82,104 @@ export interface AppShellProps {
|
|
|
65
82
|
* resolved by a consumer passing this.
|
|
66
83
|
*/
|
|
67
84
|
navLabel?: string;
|
|
85
|
+
/**
|
|
86
|
+
* The product's name, drawn as plain text at the top of the sidebar (B33-1711).
|
|
87
|
+
* The product name only -- "Boost Score", in the consumer's language -- with
|
|
88
|
+
* no icon beside it: the product mark belongs in the app switcher, not next to
|
|
89
|
+
* the name. Omit it and nothing is drawn there.
|
|
90
|
+
*
|
|
91
|
+
* It is visible text and nothing else. It names no landmark (that is `label`)
|
|
92
|
+
* and nothing branches on it. Often the same string as `label`; it is a
|
|
93
|
+
* separate prop because one is read aloud as a landmark's name and the other
|
|
94
|
+
* is read on screen, and a consumer may want them to differ.
|
|
95
|
+
*
|
|
96
|
+
* Hidden on the 56px rail, where there is no room for a word.
|
|
97
|
+
*/
|
|
98
|
+
appName?: string;
|
|
68
99
|
/** The navigation, as data. No product hardcodes rows; the shell composes them. */
|
|
69
100
|
nav: AppShellNavSection[];
|
|
70
|
-
/**
|
|
71
|
-
|
|
72
|
-
|
|
101
|
+
/**
|
|
102
|
+
* The top bar's own content: its `actions` on the right (the notification
|
|
103
|
+
* button and the avatar) and its `labels`. The shell fills the rest of the bar
|
|
104
|
+
* itself -- the mark and `org` on the left, `switcher` and `wallet` in the
|
|
105
|
+
* centre -- so those are props of the shell, not of this object.
|
|
106
|
+
*
|
|
107
|
+
* `breadcrumb` is still accepted and no longer drawn (B33-1712): the redesign
|
|
108
|
+
* puts the mark and the organisation where it was. A sidebar toggle kept
|
|
109
|
+
* inside it goes in `topBar.sidebarToggle` instead, at the far left of the
|
|
110
|
+
* bar, or the rail loses its toggle.
|
|
111
|
+
*/
|
|
112
|
+
topBar?: Omit<TopBarProps, 'start' | 'switcher' | 'tokens'>;
|
|
113
|
+
/**
|
|
114
|
+
* The Boost33 mark, at the left of the top bar (B33-1712; it was the
|
|
115
|
+
* sidebar's wordmark lockup until 0.8.0). Passed in, the way Wordmark takes
|
|
116
|
+
* it. Pass it unlinked -- `hubHref` links it. The word "Boost33" is not drawn
|
|
117
|
+
* beside it; it stays as the link's accessible name.
|
|
118
|
+
*/
|
|
73
119
|
mark?: ReactNode;
|
|
74
120
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
121
|
+
* Where the hub lives. Set it and the mark at the left of the top bar becomes
|
|
122
|
+
* a link home, rendered through `linkComponent` (B33-1699). The consumer
|
|
123
|
+
* supplies the URL -- Identity owns where the hub is and it differs per
|
|
124
|
+
* environment, so the package never hardcodes it. See `Wordmark.hubHref`.
|
|
125
|
+
*/
|
|
126
|
+
hubHref?: string;
|
|
127
|
+
/**
|
|
128
|
+
* The organisation, beside the mark at the left of the top bar (B33-1712,
|
|
129
|
+
* board 20: "AC Acme Coaching ⌄"). A slot -- the product's own pill. The
|
|
130
|
+
* package draws no organisation menu: that is AccountMenu (B33-493), which has
|
|
131
|
+
* not passed its gate.
|
|
132
|
+
*/
|
|
133
|
+
org?: ReactNode;
|
|
134
|
+
/**
|
|
135
|
+
* The app switcher, at the centre of the top bar after its "Switch Tools →"
|
|
136
|
+
* label (B33-1712; it sat under the wordmark in the sidebar until 0.8.0). A
|
|
137
|
+
* slot: pass `AppSwitcher`. The registry it draws is served by Identity
|
|
138
|
+
* (ADR-0003), not owned here. It no longer has a rail form to render -- the
|
|
139
|
+
* top bar does not collapse.
|
|
78
140
|
*/
|
|
79
141
|
switcher?: ReactNode;
|
|
80
142
|
/**
|
|
81
|
-
* The
|
|
82
|
-
*
|
|
83
|
-
*
|
|
143
|
+
* The token chip, at the centre of the top bar after the switcher and its
|
|
144
|
+
* "Check Your Tokens →" label (B33-1712; it was pinned above the sidebar's
|
|
145
|
+
* footer until 0.8.0). A slot: pass `WalletChip` with `placement="topbar"`.
|
|
146
|
+
* The balance comes from `@boost33/ledger-client`, never read here.
|
|
84
147
|
*/
|
|
85
148
|
wallet?: ReactNode;
|
|
86
|
-
/**
|
|
149
|
+
/**
|
|
150
|
+
* The product's main action, at the foot of the sidebar directly above the
|
|
151
|
+
* footer's divider (B33-1713). Omit it and nothing is drawn. Given neither
|
|
152
|
+
* `href` nor `onClick`, it is not drawn either: a button that does nothing is
|
|
153
|
+
* a control that lies (B33-1270). On the rail it shows its icon alone, or
|
|
154
|
+
* nothing if it has none.
|
|
155
|
+
*/
|
|
156
|
+
action?: AppShellAction;
|
|
157
|
+
/**
|
|
158
|
+
* The sidebar footer, at the foot of the sidebar, under a divider -- Settings
|
|
159
|
+
* and Help on board 20. A slot -- the product's own.
|
|
160
|
+
*/
|
|
87
161
|
footer?: ReactNode;
|
|
88
162
|
/**
|
|
89
163
|
* The sidebar collapsed to the 56px rail. A state of the shell: the sidebar
|
|
90
|
-
* narrows and every piece it owns collapses off this one
|
|
91
|
-
*
|
|
164
|
+
* narrows to icon-only nav and every piece it owns collapses off this one
|
|
165
|
+
* flag. The footer slot renders its own collapsed form. The switcher and the
|
|
166
|
+
* token chip live in the top bar since 0.8.0 (B33-1712) and do not collapse;
|
|
167
|
+
* the rail has no redesign of its own and keeps working as it did.
|
|
92
168
|
*/
|
|
93
169
|
collapsed?: boolean;
|
|
94
170
|
/**
|
|
95
171
|
* The element every linked nav row renders through. Defaults to a plain `a`;
|
|
96
172
|
* a consumer whose router owns navigation passes its own here and the shell
|
|
97
|
-
* threads it to every row of `nav`,
|
|
98
|
-
*
|
|
99
|
-
* shell's one nod to how a
|
|
100
|
-
* knowing what it is. See
|
|
173
|
+
* threads it to every row of `nav`, and to the wordmark when `hubHref` links
|
|
174
|
+
* it, so the whole nav goes client-side with the locale prefix intact rather
|
|
175
|
+
* than full-page-reloading (B33-847). This is the shell's one nod to how a
|
|
176
|
+
* consumer routes -- it renders the element, never knowing what it is. See
|
|
177
|
+
* docs/adr/0011.
|
|
101
178
|
*
|
|
102
|
-
* **It reaches the rows of `nav` and nothing else.** The
|
|
103
|
-
* `wallet`, `footer`, `topBar.actions`) are `ReactNode`s
|
|
104
|
-
* already created, so the shell cannot put a prop on what is
|
|
179
|
+
* **It reaches the rows of `nav` and the wordmark, and nothing else.** The
|
|
180
|
+
* slots (`switcher`, `wallet`, `footer`, `topBar.actions`) are `ReactNode`s
|
|
181
|
+
* the consumer has already created, so the shell cannot put a prop on what is
|
|
182
|
+
* inside one. A
|
|
105
183
|
* consumer composing a link-bearing component into a slot -- `AppSwitcher`,
|
|
106
184
|
* `AccountMenu`, `NotificationCenter` -- passes `linkComponent` to that
|
|
107
185
|
* component as well, or its rows stay bare anchors and reload the page. The
|
|
@@ -130,4 +208,4 @@ export interface AppShellProps {
|
|
|
130
208
|
*/
|
|
131
209
|
children: ReactNode;
|
|
132
210
|
}
|
|
133
|
-
export declare function AppShell({ label, navLabel, nav, topBar, mark, switcher, wallet, footer, collapsed, linkComponent, children, }: AppShellProps): import("react").JSX.Element;
|
|
211
|
+
export declare function AppShell({ label, appName, navLabel, nav, topBar, mark, hubHref, org, switcher, wallet, action, footer, collapsed, linkComponent, children, }: AppShellProps): import("react").JSX.Element;
|
|
@@ -1,57 +1,83 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { Sidebar as
|
|
3
|
-
import { NavSection as
|
|
4
|
-
import { NavItem as
|
|
5
|
-
import { TopBar as
|
|
6
|
-
import { Wordmark as
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
import { jsxs as o, jsx as r, Fragment as v } from "react/jsx-runtime";
|
|
2
|
+
import { Sidebar as x } from "../Sidebar/Sidebar.js";
|
|
3
|
+
import { NavSection as j } from "../NavSection/NavSection.js";
|
|
4
|
+
import { NavItem as A } from "../NavItem/NavItem.js";
|
|
5
|
+
import { TopBar as C } from "../TopBar/TopBar.js";
|
|
6
|
+
import { Wordmark as L } from "../Wordmark/Wordmark.js";
|
|
7
|
+
import U from "../../buttons.module.css.js";
|
|
8
|
+
import l from "./AppShell.module.css.js";
|
|
9
|
+
function z({
|
|
10
|
+
label: n,
|
|
11
|
+
appName: a,
|
|
12
|
+
navLabel: s,
|
|
13
|
+
nav: t,
|
|
14
|
+
topBar: c,
|
|
15
|
+
mark: d,
|
|
16
|
+
hubHref: m,
|
|
17
|
+
org: p,
|
|
18
|
+
switcher: N,
|
|
19
|
+
wallet: b,
|
|
20
|
+
action: S,
|
|
21
|
+
footer: u,
|
|
22
|
+
collapsed: i = !1,
|
|
23
|
+
linkComponent: h,
|
|
24
|
+
children: k
|
|
20
25
|
}) {
|
|
21
|
-
return /* @__PURE__ */
|
|
22
|
-
/* @__PURE__ */
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
26
|
+
return /* @__PURE__ */ o("div", { className: l.shell, children: [
|
|
27
|
+
/* @__PURE__ */ r(
|
|
28
|
+
C,
|
|
29
|
+
{
|
|
30
|
+
...c,
|
|
31
|
+
start: /* @__PURE__ */ o(v, { children: [
|
|
32
|
+
/* @__PURE__ */ r(L, { mark: d, collapsed: !0, hubHref: m, linkComponent: h }),
|
|
33
|
+
p
|
|
34
|
+
] }),
|
|
35
|
+
switcher: N,
|
|
36
|
+
tokens: b
|
|
37
|
+
}
|
|
38
|
+
),
|
|
39
|
+
/* @__PURE__ */ o("div", { className: l.body, children: [
|
|
40
|
+
/* @__PURE__ */ o(x, { landmarkLabel: n, collapsed: i, children: [
|
|
41
|
+
a != null && !i && /* @__PURE__ */ r("p", { className: l.appName, children: a }),
|
|
42
|
+
/* @__PURE__ */ r("nav", { "aria-label": s ?? n, className: l.nav, children: t.map((f, y) => (
|
|
43
|
+
// No room for a header at 56px, so on the rail every section renders
|
|
44
|
+
// headerless -- its rows collapse to their icons and line up.
|
|
45
|
+
/* @__PURE__ */ r(j, { label: i ? void 0 : f.label, children: f.items.map((e, g) => /* @__PURE__ */ r(
|
|
46
|
+
A,
|
|
47
|
+
{
|
|
48
|
+
icon: e.icon,
|
|
49
|
+
active: e.active,
|
|
50
|
+
collapsed: i,
|
|
51
|
+
count: e.count,
|
|
52
|
+
countUrgent: e.countUrgent,
|
|
53
|
+
dot: e.dot,
|
|
54
|
+
href: e.href,
|
|
55
|
+
linkComponent: h,
|
|
56
|
+
children: e.label
|
|
57
|
+
},
|
|
58
|
+
g
|
|
59
|
+
)) }, y)
|
|
60
|
+
)) }),
|
|
61
|
+
/* @__PURE__ */ r($, { action: S, collapsed: i, linkComponent: h }),
|
|
62
|
+
u != null && /* @__PURE__ */ r("div", { className: l.foot, children: u })
|
|
63
|
+
] }),
|
|
64
|
+
/* @__PURE__ */ r("div", { className: l.main, children: /* @__PURE__ */ r("main", { className: l.content, children: k }) })
|
|
51
65
|
] })
|
|
52
66
|
] });
|
|
53
67
|
}
|
|
68
|
+
function $({ action: n, collapsed: a, linkComponent: s }) {
|
|
69
|
+
if (n === void 0 || n.href === void 0 && n.onClick === void 0 || a && n.icon == null) return null;
|
|
70
|
+
const t = /* @__PURE__ */ o(v, { children: [
|
|
71
|
+
n.icon != null && /* @__PURE__ */ r("span", { "aria-hidden": "true", children: n.icon }),
|
|
72
|
+
/* @__PURE__ */ r("span", { className: a ? l.srOnly : void 0, children: n.label })
|
|
73
|
+
] }), c = `${U.primary} ${l.action}`, d = a ? "true" : void 0;
|
|
74
|
+
if (n.href !== void 0) {
|
|
75
|
+
const m = s ?? "a";
|
|
76
|
+
return /* @__PURE__ */ r("div", { className: l.actionSlot, children: /* @__PURE__ */ r(m, { className: c, href: n.href, "data-collapsed": d, children: t }) });
|
|
77
|
+
}
|
|
78
|
+
return /* @__PURE__ */ r("div", { className: l.actionSlot, children: /* @__PURE__ */ r("button", { type: "button", className: c, onClick: n.onClick, "data-collapsed": d, children: t }) });
|
|
79
|
+
}
|
|
54
80
|
export {
|
|
55
|
-
|
|
81
|
+
z as AppShell
|
|
56
82
|
};
|
|
57
83
|
//# sourceMappingURL=AppShell.js.map
|