@boost33/ui 0.8.0-next.2 → 0.8.0-next.3

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 CHANGED
@@ -219,6 +219,51 @@ Repo-only: the specimen's "Shell redesign — B33-1710" route grows the top bar,
219
219
  the open token popover, board 22's nothing-purchased chip, and the unknown,
220
220
  past-zero and total-only chips.
221
221
 
222
+ ### Fixed — the top-bar token chip warns again past 80% of the grant; the top bar holds its layout (0.8.0-next.3)
223
+
224
+ - **The 80% threshold is back in the top bar.** 0.8.0-next.0 moved the chip to
225
+ the top bar without its threshold state, so a seller who had burned 87% of the
226
+ month's grant saw the same chip as one at 10%, and nothing here said so
227
+ (found by Score). `placement="topbar"` now reads `grantCycle` and
228
+ `burnedFraction` exactly as the sidebar card does (the consumer's
229
+ `burnedFraction` wins, otherwise it is derived from `grantCycle`, and with
230
+ neither nothing is claimed). Past 80%:
231
+ - with `grantCycle`, the bar in the chip and in the popover measures against
232
+ what the cycle started with, so it shortens and the burned share shows as
233
+ the warning-tinted track: the sidebar card's drawing (Jamal, 4 Nov 2026).
234
+ With `burnedFraction` alone there is no honest denominator, so the bar
235
+ stays full;
236
+ - the popover shows a line above the runway note, and the chip's accessible
237
+ name ends with it, so the warning is never colour alone. **New label
238
+ `thresholdNote`**, a template with `%percent%`, formatted for `locale`
239
+ ("87%", "87 %"). Default `You've used %percent% of this month's grant.`
240
+ A catalogue typed as a full `WalletChipLabels` must add it; that is the
241
+ typecheck catching a missing translation;
242
+ - the root carries `data-threshold="true"`. Buy tokens is unchanged: the
243
+ accent primary.
244
+ Keep passing `grantCycle` (or `burnedFraction`) to the top-bar chip.
245
+ - **The top bar keeps its regions apart at any width.** At 1024px the start
246
+ group (mark and organisation pill) was given less than it held and painted
247
+ across "Switch Tools →" (Content, Wallet, Activity, Outbound). The bar is now
248
+ a three-column grid whose sides are never narrower than their contents: where
249
+ everything fits, the centre group sits in the middle as before; where it does
250
+ not, the centre moves off the middle instead of under the pill. Below that,
251
+ on a phone with no `chromeFrom`, the bar runs off the right edge in order
252
+ rather than piling up (Score). **No approved screenshot moves**: every gated
253
+ state measures the same pixel count with and without the change.
254
+ - **The top bar is a `<header>`**, the page's banner landmark, so assistive tech
255
+ can jump to it and a test can scope to it (Score). `getByRole('banner')`
256
+ finds it. The census in `scripts/border-proof.ts` records the bar's hairline on
257
+ a `header` now; the pixels did not move.
258
+ - **The popover's reset note ends on the date.** `grantedNote` defaults to
259
+ `Included each month · resets %date%`, without the `Resets %date%.`
260
+ full stop that printed "30 sept.." for a French date (Score). If you
261
+ translate it, keep punctuation off the end of `%date%`. `grantExpires` is one
262
+ date in both placements, the day this month's grant runs out and the next
263
+ lands. The sidebar says it as an expiry, the popover as a reset.
264
+ - **Below `chromeFrom` the shell still fills its root** (`min-height: 100%`),
265
+ so a short page keeps the white ground to the bottom of the screen (Content).
266
+
222
267
  ### Added — `AppShell` gets out of the way on a phone: `chromeFrom` and `phoneChrome`
223
268
 
224
269
  AppShell has no phone layout, and the 0.8 top bar runs off a 390px screen.
@@ -1,28 +1,28 @@
1
- const o = "_shell_1rvaz_13", n = "_body_1rvaz_24", t = "_appName_1rvaz_39", _ = "_foot_1rvaz_65", a = "_actionSlot_1rvaz_79", c = "_action_1rvaz_79", s = "_srOnly_1rvaz_103", e = "_nav_1rvaz_116", r = "_main_1rvaz_125", l = "_content_1rvaz_146", v = "_phoneChrome_1rvaz_201", z = {
2
- shell: o,
3
- body: n,
4
- appName: t,
1
+ const t = "_shell_kt75f_13", o = "_body_kt75f_24", n = "_appName_kt75f_39", _ = "_foot_kt75f_65", c = "_actionSlot_kt75f_79", s = "_action_kt75f_79", a = "_srOnly_kt75f_103", e = "_nav_kt75f_116", f = "_main_kt75f_125", l = "_content_kt75f_146", k = "_phoneChrome_kt75f_203", p = {
2
+ shell: t,
3
+ body: o,
4
+ appName: n,
5
5
  foot: _,
6
- actionSlot: a,
7
- action: c,
8
- srOnly: s,
6
+ actionSlot: c,
7
+ action: s,
8
+ srOnly: a,
9
9
  nav: e,
10
- main: r,
10
+ main: f,
11
11
  content: l,
12
- phoneChrome: v
12
+ phoneChrome: k
13
13
  };
14
14
  export {
15
- c as action,
16
- a as actionSlot,
17
- t as appName,
18
- n as body,
15
+ s as action,
16
+ c as actionSlot,
17
+ n as appName,
18
+ o as body,
19
19
  l as content,
20
- z as default,
20
+ p as default,
21
21
  _ as foot,
22
- r as main,
22
+ f as main,
23
23
  e as nav,
24
- v as phoneChrome,
25
- o as shell,
26
- s as srOnly
24
+ k as phoneChrome,
25
+ t as shell,
26
+ a as srOnly
27
27
  };
28
28
  //# sourceMappingURL=AppShell.module.css.js.map
@@ -1,26 +1,26 @@
1
- import { jsxs as r, Fragment as c, jsx as n } from "react/jsx-runtime";
2
- import { warnDeprecatedProp as u } from "../../deprecated-prop-warning.js";
3
- import { resolveTopBarLabels as h } from "./labels.js";
4
- import l from "./TopBar.module.css.js";
5
- function T({ sidebarToggle: o, start: i, switcher: e, tokens: a, actions: d, labels: t, breadcrumb: m }) {
6
- m != null && u("TopBar.breadcrumb");
7
- const s = h(t), p = e != null || a != null;
8
- return /* @__PURE__ */ r("div", { className: l.bar, children: [
9
- /* @__PURE__ */ r("div", { className: l.start, children: [
1
+ import { jsxs as l, Fragment as c, jsx as n } from "react/jsx-runtime";
2
+ import { warnDeprecatedProp as h } from "../../deprecated-prop-warning.js";
3
+ import { resolveTopBarLabels as u } from "./labels.js";
4
+ import e from "./TopBar.module.css.js";
5
+ function T({ sidebarToggle: o, start: d, switcher: r, tokens: a, actions: i, labels: t, breadcrumb: m }) {
6
+ m != null && h("TopBar.breadcrumb");
7
+ const s = u(t), p = r != null || a != null;
8
+ return /* @__PURE__ */ l("header", { className: e.bar, children: [
9
+ /* @__PURE__ */ l("div", { className: e.start, children: [
10
10
  o,
11
- i
11
+ d
12
12
  ] }),
13
- p && /* @__PURE__ */ r("div", { className: l.centre, children: [
14
- e != null && /* @__PURE__ */ r(c, { children: [
15
- /* @__PURE__ */ n("span", { className: l.label, children: s.switchTools }),
16
- e
13
+ p && /* @__PURE__ */ l("div", { className: e.centre, children: [
14
+ r != null && /* @__PURE__ */ l(c, { children: [
15
+ /* @__PURE__ */ n("span", { className: e.label, children: s.switchTools }),
16
+ r
17
17
  ] }),
18
- a != null && /* @__PURE__ */ r(c, { children: [
19
- /* @__PURE__ */ n("span", { className: l.label, "data-after-switcher": e != null ? "true" : void 0, children: s.checkTokens }),
18
+ a != null && /* @__PURE__ */ l(c, { children: [
19
+ /* @__PURE__ */ n("span", { className: e.label, "data-after-switcher": r != null ? "true" : void 0, children: s.checkTokens }),
20
20
  a
21
21
  ] })
22
22
  ] }),
23
- /* @__PURE__ */ n("div", { className: l.end, children: d })
23
+ /* @__PURE__ */ n("div", { className: e.end, children: i })
24
24
  ] });
25
25
  }
26
26
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"TopBar.js","sources":["../../../src/components/TopBar/TopBar.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { warnDeprecatedProp } from '../../deprecated-prop-warning'\nimport { resolveTopBarLabels, type TopBarLabels } from './labels'\nimport styles from './TopBar.module.css'\n\nexport interface TopBarProps {\n /**\n * The control that collapses the sidebar to its 56px rail and back, at the\n * far left of the bar, before the mark (B33-1712). A slot: the product's own\n * button, which owns the collapsed state.\n *\n * It has a slot of its own because the bar stopped drawing `breadcrumb` in\n * 0.8.0, and a consumer that kept its toggle inside the breadcrumb -- the\n * Wallet did -- would otherwise lose its only way into and out of the rail on\n * upgrade, silently: the pixel diff passed the bar at 0.19% with the toggle\n * gone. No board draws it; the rail keeps working with no new design.\n */\n sidebarToggle?: ReactNode\n /**\n * The left of the bar: the Boost33 mark and the organisation's pill, as the 3\n * Nov 2026 redesign draws it (B33-1712, board 20). A slot. Inside `AppShell`\n * the shell fills it from its own `mark`, `hubHref` and `org` props, so a\n * consumer of the shell does not set this.\n */\n start?: ReactNode\n /**\n * The app switcher, at the centre of the bar after its \"Switch Tools →\"\n * label. A slot: pass `AppSwitcher`. Omit it and neither it nor its label is\n * drawn. Inside `AppShell`, the shell's `switcher` prop lands here.\n */\n switcher?: ReactNode\n /**\n * The token chip, after the switcher and its \"Check Your Tokens →\" label. A\n * slot: pass `WalletChip` with `placement=\"topbar\"`. Omit it and neither it\n * nor its label is drawn. Inside `AppShell`, the shell's `wallet` prop lands\n * here.\n */\n tokens?: ReactNode\n /**\n * The right of the bar: the notification button and the account avatar\n * (board 20). A slot -- the product's own, or the package's\n * `NotificationButton` beside the consumer's avatar.\n *\n * Search is not here and nothing replaces it: Jamal removed it on 3 Nov 2026\n * until the feature is built (B33-1710), and the CommandPalette that would\n * open from it is left out of 0.8.0 with no trigger and no shortcut.\n */\n actions?: ReactNode\n /** The centre group's two labels. Each field defaults to English. */\n labels?: Partial<TopBarLabels>\n /**\n * Was the breadcrumb on the left of the bar. **Not drawn since 0.8.0**: the\n * redesign puts the mark and the organisation there, and the page's own\n * `PageHeader` names where you are. Optional so an existing call site still\n * compiles.\n *\n * @deprecated Rendered nowhere since 0.8.0 (B33-1712). Stop passing it; in\n * development, passing it logs a console warning once.\n */\n breadcrumb?: ReactNode\n}\n\n// The bar across the top of every screen (B33-1712). Three regions: the mark\n// and organisation on the left, the switcher and token chip in a centred group,\n// and the product's actions on the right. Left and right take equal shares of\n// what the centre leaves, which is what holds the centre group in the middle of\n// the bar whatever either side holds.\n//\n// A Server Component: no state, no handlers. The two controls in the centre are\n// client components passed in as slots.\nexport function TopBar({ sidebarToggle, start, switcher, tokens, actions, labels, breadcrumb }: TopBarProps) {\n if (breadcrumb != null) warnDeprecatedProp('TopBar.breadcrumb')\n const t = resolveTopBarLabels(labels)\n const hasCentre = switcher != null || tokens != null\n\n return (\n <div className={styles.bar}>\n <div className={styles.start}>\n {sidebarToggle}\n {start}\n </div>\n {hasCentre && (\n <div className={styles.centre}>\n {switcher != null && (\n <>\n <span className={styles.label}>{t.switchTools}</span>\n {switcher}\n </>\n )}\n {tokens != null && (\n <>\n {/* The second label keeps 32px clear of the switcher, so each\n label reads as belonging to the control after it, not the one\n before it (board 20). With no switcher there is nothing to\n keep clear of, and the padding goes. */}\n <span className={styles.label} data-after-switcher={switcher != null ? 'true' : undefined}>\n {t.checkTokens}\n </span>\n {tokens}\n </>\n )}\n </div>\n )}\n <div className={styles.end}>{actions}</div>\n </div>\n )\n}\n"],"names":["TopBar","sidebarToggle","start","switcher","tokens","actions","labels","breadcrumb","warnDeprecatedProp","t","resolveTopBarLabels","hasCentre","jsxs","styles","Fragment","jsx"],"mappings":";;;;AAsEO,SAASA,EAAO,EAAE,eAAAC,GAAe,OAAAC,GAAO,UAAAC,GAAU,QAAAC,GAAQ,SAAAC,GAAS,QAAAC,GAAQ,YAAAC,KAA2B;AAC3G,EAAIA,KAAc,QAAMC,EAAmB,mBAAmB;AAC9D,QAAMC,IAAIC,EAAoBJ,CAAM,GAC9BK,IAAYR,KAAY,QAAQC,KAAU;AAEhD,SACE,gBAAAQ,EAAC,OAAA,EAAI,WAAWC,EAAO,KACrB,UAAA;AAAA,IAAA,gBAAAD,EAAC,OAAA,EAAI,WAAWC,EAAO,OACpB,UAAA;AAAA,MAAAZ;AAAA,MACAC;AAAA,IAAA,GACH;AAAA,IACCS,KACC,gBAAAC,EAAC,OAAA,EAAI,WAAWC,EAAO,QACpB,UAAA;AAAA,MAAAV,KAAY,QACX,gBAAAS,EAAAE,GAAA,EACE,UAAA;AAAA,QAAA,gBAAAC,EAAC,QAAA,EAAK,WAAWF,EAAO,OAAQ,YAAE,aAAY;AAAA,QAC7CV;AAAA,MAAA,GACH;AAAA,MAEDC,KAAU,QACT,gBAAAQ,EAAAE,GAAA,EAKE,UAAA;AAAA,QAAA,gBAAAC,EAAC,QAAA,EAAK,WAAWF,EAAO,OAAO,uBAAqBV,KAAY,OAAO,SAAS,QAC7E,UAAAM,EAAE,YAAA,CACL;AAAA,QACCL;AAAA,MAAA,EAAA,CACH;AAAA,IAAA,GAEJ;AAAA,IAEF,gBAAAW,EAAC,OAAA,EAAI,WAAWF,EAAO,KAAM,UAAAR,EAAA,CAAQ;AAAA,EAAA,GACvC;AAEJ;"}
1
+ {"version":3,"file":"TopBar.js","sources":["../../../src/components/TopBar/TopBar.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { warnDeprecatedProp } from '../../deprecated-prop-warning'\nimport { resolveTopBarLabels, type TopBarLabels } from './labels'\nimport styles from './TopBar.module.css'\n\nexport interface TopBarProps {\n /**\n * The control that collapses the sidebar to its 56px rail and back, at the\n * far left of the bar, before the mark (B33-1712). A slot: the product's own\n * button, which owns the collapsed state.\n *\n * It has a slot of its own because the bar stopped drawing `breadcrumb` in\n * 0.8.0, and a consumer that kept its toggle inside the breadcrumb -- the\n * Wallet did -- would otherwise lose its only way into and out of the rail on\n * upgrade, silently: the pixel diff passed the bar at 0.19% with the toggle\n * gone. No board draws it; the rail keeps working with no new design.\n */\n sidebarToggle?: ReactNode\n /**\n * The left of the bar: the Boost33 mark and the organisation's pill, as the 3\n * Nov 2026 redesign draws it (B33-1712, board 20). A slot. Inside `AppShell`\n * the shell fills it from its own `mark`, `hubHref` and `org` props, so a\n * consumer of the shell does not set this.\n */\n start?: ReactNode\n /**\n * The app switcher, at the centre of the bar after its \"Switch Tools →\"\n * label. A slot: pass `AppSwitcher`. Omit it and neither it nor its label is\n * drawn. Inside `AppShell`, the shell's `switcher` prop lands here.\n */\n switcher?: ReactNode\n /**\n * The token chip, after the switcher and its \"Check Your Tokens →\" label. A\n * slot: pass `WalletChip` with `placement=\"topbar\"`. Omit it and neither it\n * nor its label is drawn. Inside `AppShell`, the shell's `wallet` prop lands\n * here.\n */\n tokens?: ReactNode\n /**\n * The right of the bar: the notification button and the account avatar\n * (board 20). A slot -- the product's own, or the package's\n * `NotificationButton` beside the consumer's avatar.\n *\n * Search is not here and nothing replaces it: Jamal removed it on 3 Nov 2026\n * until the feature is built (B33-1710), and the CommandPalette that would\n * open from it is left out of 0.8.0 with no trigger and no shortcut.\n */\n actions?: ReactNode\n /** The centre group's two labels. Each field defaults to English. */\n labels?: Partial<TopBarLabels>\n /**\n * Was the breadcrumb on the left of the bar. **Not drawn since 0.8.0**: the\n * redesign puts the mark and the organisation there, and the page's own\n * `PageHeader` names where you are. Optional so an existing call site still\n * compiles.\n *\n * @deprecated Rendered nowhere since 0.8.0 (B33-1712). Stop passing it; in\n * development, passing it logs a console warning once.\n */\n breadcrumb?: ReactNode\n}\n\n// The bar across the top of every screen (B33-1712). Three regions: the mark\n// and organisation on the left, the switcher and token chip in a centred group,\n// and the product's actions on the right. Left and right take equal shares of\n// what the centre leaves, which is what holds the centre group in the middle of\n// the bar whatever either side holds.\n//\n// A Server Component: no state, no handlers. The two controls in the centre are\n// client components passed in as slots.\nexport function TopBar({ sidebarToggle, start, switcher, tokens, actions, labels, breadcrumb }: TopBarProps) {\n if (breadcrumb != null) warnDeprecatedProp('TopBar.breadcrumb')\n const t = resolveTopBarLabels(labels)\n const hasCentre = switcher != null || tokens != null\n\n // A <header>, so the bar is the page's banner landmark and a screen-reader\n // user can jump to it, and an end-to-end test can scope to it (score-main,\n // 0.8.0-next.2). Inside AppShell it is never within <main> or an <article>,\n // which is what makes a <header> a banner. `display: grid` is set on the\n // class, so the element swap changes no box.\n return (\n <header className={styles.bar}>\n <div className={styles.start}>\n {sidebarToggle}\n {start}\n </div>\n {hasCentre && (\n <div className={styles.centre}>\n {switcher != null && (\n <>\n <span className={styles.label}>{t.switchTools}</span>\n {switcher}\n </>\n )}\n {tokens != null && (\n <>\n {/* The second label keeps 32px clear of the switcher, so each\n label reads as belonging to the control after it, not the one\n before it (board 20). With no switcher there is nothing to\n keep clear of, and the padding goes. */}\n <span className={styles.label} data-after-switcher={switcher != null ? 'true' : undefined}>\n {t.checkTokens}\n </span>\n {tokens}\n </>\n )}\n </div>\n )}\n <div className={styles.end}>{actions}</div>\n </header>\n )\n}\n"],"names":["TopBar","sidebarToggle","start","switcher","tokens","actions","labels","breadcrumb","warnDeprecatedProp","t","resolveTopBarLabels","hasCentre","jsxs","styles","Fragment","jsx"],"mappings":";;;;AAsEO,SAASA,EAAO,EAAE,eAAAC,GAAe,OAAAC,GAAO,UAAAC,GAAU,QAAAC,GAAQ,SAAAC,GAAS,QAAAC,GAAQ,YAAAC,KAA2B;AAC3G,EAAIA,KAAc,QAAMC,EAAmB,mBAAmB;AAC9D,QAAMC,IAAIC,EAAoBJ,CAAM,GAC9BK,IAAYR,KAAY,QAAQC,KAAU;AAOhD,SACE,gBAAAQ,EAAC,UAAA,EAAO,WAAWC,EAAO,KACxB,UAAA;AAAA,IAAA,gBAAAD,EAAC,OAAA,EAAI,WAAWC,EAAO,OACpB,UAAA;AAAA,MAAAZ;AAAA,MACAC;AAAA,IAAA,GACH;AAAA,IACCS,KACC,gBAAAC,EAAC,OAAA,EAAI,WAAWC,EAAO,QACpB,UAAA;AAAA,MAAAV,KAAY,QACX,gBAAAS,EAAAE,GAAA,EACE,UAAA;AAAA,QAAA,gBAAAC,EAAC,QAAA,EAAK,WAAWF,EAAO,OAAQ,YAAE,aAAY;AAAA,QAC7CV;AAAA,MAAA,GACH;AAAA,MAEDC,KAAU,QACT,gBAAAQ,EAAAE,GAAA,EAKE,UAAA;AAAA,QAAA,gBAAAC,EAAC,QAAA,EAAK,WAAWF,EAAO,OAAO,uBAAqBV,KAAY,OAAO,SAAS,QAC7E,UAAAM,EAAE,YAAA,CACL;AAAA,QACCL;AAAA,MAAA,EAAA,CACH;AAAA,IAAA,GAEJ;AAAA,IAEF,gBAAAW,EAAC,OAAA,EAAI,WAAWF,EAAO,KAAM,UAAAR,EAAA,CAAQ;AAAA,EAAA,GACvC;AAEJ;"}
@@ -1,16 +1,16 @@
1
- const t = "_bar_1lxv8_9", e = "_start_1lxv8_25", _ = "_end_1lxv8_26", l = "_centre_1lxv8_45", n = "_label_1lxv8_54", s = {
1
+ const t = "_bar_1t9gi_9", e = "_start_1t9gi_36", _ = "_end_1t9gi_37", n = "_centre_1t9gi_56", s = "_label_1t9gi_65", a = {
2
2
  bar: t,
3
3
  start: e,
4
4
  end: _,
5
- centre: l,
6
- label: n
5
+ centre: n,
6
+ label: s
7
7
  };
8
8
  export {
9
9
  t as bar,
10
- l as centre,
11
- s as default,
10
+ n as centre,
11
+ a as default,
12
12
  _ as end,
13
- n as label,
13
+ s as label,
14
14
  e as start
15
15
  };
16
16
  //# sourceMappingURL=TopBar.module.css.js.map
@@ -155,7 +155,12 @@ export interface WalletChipKnownProps extends WalletChipChromeProps {
155
155
  * wrong figure that looks wrong is the one that gets fixed.
156
156
  */
157
157
  burnedFraction?: number;
158
- /** When the current grant expires, preformatted for display, e.g. "30 Sep". */
158
+ /**
159
+ * When the current grant expires, preformatted for display, e.g. "30 Sep":
160
+ * the day this month's grant runs out and the next one lands. The sidebar
161
+ * card says it as an expiry (`labels.grantExpiry`), the top-bar popover as a
162
+ * reset (`labels.grantedNote`); both are this one date.
163
+ */
159
164
  grantExpires?: string;
160
165
  /**
161
166
  * The threshold state's runway line, preformatted, e.g. "About four days left
@@ -1,163 +1,164 @@
1
1
  "use client";
2
- import { jsx as a, jsxs as n, Fragment as P } from "react/jsx-runtime";
3
- import { useAnchoredOverlay as U } from "../../anchored-overlay.js";
4
- import { Chevron as $ } from "../AppSwitcher/icons.js";
5
- import y from "../../buttons.module.css.js";
2
+ import { jsx as a, jsxs as s, Fragment as I } from "react/jsx-runtime";
3
+ import { useAnchoredOverlay as w } from "../../anchored-overlay.js";
4
+ import { Chevron as W } from "../AppSwitcher/icons.js";
5
+ import F from "../../buttons.module.css.js";
6
6
  import e from "./WalletChip.module.css.js";
7
- import { formatTokens as o, DEFAULT_WALLET_LOCALE as k, thousandsFigure as w } from "./format.js";
8
- import { WalletMark as x, RetryMark as O } from "./icons.js";
9
- import { resolveWalletChipLabels as A } from "./labels.js";
10
- const E = 0.8, G = "var(--spacing-wallet-segment-min)";
11
- function L(i, l) {
12
- const t = l > 0 ? i / l * 100 : 0;
13
- return i <= 0 ? `${t}%` : `max(${t}%, ${G})`;
7
+ import { formatTokens as p, DEFAULT_WALLET_LOCALE as P, formatPercent as Z, thousandsFigure as _ } from "./format.js";
8
+ import { WalletMark as q, RetryMark as S } from "./icons.js";
9
+ import { resolveWalletChipLabels as R } from "./labels.js";
10
+ const E = 0.8, j = "var(--spacing-wallet-segment-min)";
11
+ function A(n, i) {
12
+ const t = i > 0 ? n / i * 100 : 0;
13
+ return n <= 0 ? `${t}%` : `max(${t}%, ${j})`;
14
14
  }
15
- function R({ granted: i, purchased: l, cycleTotal: t, tone: p, label: r }) {
16
- return /* @__PURE__ */ n("div", { className: e.bar, "data-tone": p, role: "img", "aria-label": r, children: [
17
- /* @__PURE__ */ a("span", { className: e.segmentGranted, "data-testid": "segment-granted", style: { width: L(i, t) } }),
18
- /* @__PURE__ */ a("span", { className: e.segmentPurchased, "data-testid": "segment-purchased", style: { width: L(l, t) } })
15
+ function C({ granted: n, purchased: i, cycleTotal: t, tone: v, label: N }) {
16
+ return /* @__PURE__ */ s("div", { className: e.bar, "data-tone": v, role: "img", "aria-label": N, children: [
17
+ /* @__PURE__ */ a("span", { className: e.segmentGranted, "data-testid": "segment-granted", style: { width: A(n, t) } }),
18
+ /* @__PURE__ */ a("span", { className: e.segmentPurchased, "data-testid": "segment-purchased", style: { width: A(i, t) } })
19
19
  ] });
20
20
  }
21
- function J(i) {
22
- return i.totalOnly === !0 ? /* @__PURE__ */ a(W, { ...i }) : i.placement === "topbar" ? /* @__PURE__ */ a(M, { ...i }) : /* @__PURE__ */ a(I, { ...i });
21
+ function se(n) {
22
+ return n.totalOnly === !0 ? /* @__PURE__ */ a(H, { ...n }) : n.placement === "topbar" ? /* @__PURE__ */ a(D, { ...n }) : /* @__PURE__ */ a(z, { ...n });
23
23
  }
24
- function M({ granted: i = 0, purchased: l = 0, grantExpires: t, burnNote: p, unknown: r = !1, onTopUp: v, labels: m, locale: u = k, walletHref: c, linkComponent: g, defaultOpen: h }) {
25
- const s = A(m), d = U({ defaultOpen: h }), B = g ?? "a", b = i + l, F = b, f = r ? "—" : o(b, u), N = () => s.bar(o(i, u), o(l, u), o(b, u));
26
- return /* @__PURE__ */ n("div", { className: e.topRoot, children: [
27
- /* @__PURE__ */ n("button", { type: "button", className: e.topTrigger, "aria-label": r ? s.railBalanceUnknown : s.railBalance(f), onClick: d.toggle, ...d.triggerProps, children: [
28
- /* @__PURE__ */ n("span", { className: e.topFigure, "aria-hidden": "true", children: [
29
- /* @__PURE__ */ a("span", { className: e.topAmount, children: f }),
30
- /* @__PURE__ */ a("span", { className: e.topUnit, children: s.unit })
24
+ function D({ granted: n = 0, purchased: i = 0, grantCycle: t, burnedFraction: v, grantExpires: N, burnNote: m, unknown: o = !1, onTopUp: f, labels: d, locale: c = P, walletHref: h, linkComponent: r, defaultOpen: g }) {
25
+ const l = R(d), b = w({ defaultOpen: g }), T = r ?? "a", B = n + i, u = t !== void 0 && t > 0 ? (t - n) / t : 0, y = v ?? u, $ = !o && y >= E, U = $ && t !== void 0 ? t + i : B, x = $ ? "threshold" : void 0, k = o ? "—" : p(B, c), G = () => l.bar(p(n, c), p(i, c), p(B, c)), L = $ ? l.thresholdNote(Z(y, c)) : void 0, M = o ? l.railBalanceUnknown : L ? `${l.railBalance(k)}. ${L}` : l.railBalance(k);
26
+ return /* @__PURE__ */ s("div", { className: e.topRoot, "data-threshold": $ ? "true" : void 0, children: [
27
+ /* @__PURE__ */ s("button", { type: "button", className: e.topTrigger, "aria-label": M, onClick: b.toggle, ...b.triggerProps, children: [
28
+ /* @__PURE__ */ s("span", { className: e.topFigure, "aria-hidden": "true", children: [
29
+ /* @__PURE__ */ a("span", { className: e.topAmount, children: k }),
30
+ /* @__PURE__ */ a("span", { className: e.topUnit, children: l.unit })
31
31
  ] }),
32
- !r && /* @__PURE__ */ a(T, { granted: i, purchased: l, total: F, className: e.topBar }),
33
- /* @__PURE__ */ a($, { className: e.topChevron })
32
+ !o && /* @__PURE__ */ a(O, { granted: n, purchased: i, total: U, tone: x, className: e.topBar }),
33
+ /* @__PURE__ */ a(W, { className: e.topChevron })
34
34
  ] }),
35
- d.open && /* @__PURE__ */ n("div", { ...d.panelProps, className: e.popover, "aria-label": s.popover, children: [
36
- /* @__PURE__ */ n("div", { className: e.popHead, children: [
37
- /* @__PURE__ */ n("span", { className: e.popFigure, children: [
38
- /* @__PURE__ */ a("span", { className: e.popAmount, children: f }),
39
- /* @__PURE__ */ a("span", { className: e.popUnit, children: s.unit })
35
+ b.open && /* @__PURE__ */ s("div", { ...b.panelProps, className: e.popover, "aria-label": l.popover, children: [
36
+ /* @__PURE__ */ s("div", { className: e.popHead, children: [
37
+ /* @__PURE__ */ s("span", { className: e.popFigure, children: [
38
+ /* @__PURE__ */ a("span", { className: e.popAmount, children: k }),
39
+ /* @__PURE__ */ a("span", { className: e.popUnit, children: l.unit })
40
40
  ] }),
41
- c !== void 0 && /* @__PURE__ */ a(B, { className: y.quiet, href: c, onClick: d.close, children: s.open })
41
+ h !== void 0 && /* @__PURE__ */ a(T, { className: F.quiet, href: h, onClick: b.close, children: l.open })
42
42
  ] }),
43
- r ? /* @__PURE__ */ a("p", { className: e.popNote, children: s.balanceUnknown }) : /* @__PURE__ */ n(P, { children: [
44
- /* @__PURE__ */ a(T, { granted: i, purchased: l, total: F, className: e.popBar, label: N() }),
45
- /* @__PURE__ */ n("ul", { className: e.legend, children: [
46
- /* @__PURE__ */ n("li", { className: e.legendRow, children: [
43
+ o ? /* @__PURE__ */ a("p", { className: e.popNote, children: l.balanceUnknown }) : /* @__PURE__ */ s(I, { children: [
44
+ /* @__PURE__ */ a(O, { granted: n, purchased: i, total: U, tone: x, className: e.popBar, label: G() }),
45
+ /* @__PURE__ */ s("ul", { className: e.legend, children: [
46
+ /* @__PURE__ */ s("li", { className: e.legendRow, children: [
47
47
  /* @__PURE__ */ a("span", { className: e.swatchGranted, "aria-hidden": "true" }),
48
- /* @__PURE__ */ n("span", { className: e.legendText, children: [
49
- /* @__PURE__ */ a("span", { className: e.legendFigure, children: s.grantedFigure(o(i, u)) }),
50
- /* @__PURE__ */ a("span", { className: e.legendNote, children: t ? s.grantedNote(t) : s.grantedNoteUndated })
48
+ /* @__PURE__ */ s("span", { className: e.legendText, children: [
49
+ /* @__PURE__ */ a("span", { className: e.legendFigure, children: l.grantedFigure(p(n, c)) }),
50
+ /* @__PURE__ */ a("span", { className: e.legendNote, children: N ? l.grantedNote(N) : l.grantedNoteUndated })
51
51
  ] })
52
52
  ] }),
53
- /* @__PURE__ */ n("li", { className: e.legendRow, children: [
53
+ /* @__PURE__ */ s("li", { className: e.legendRow, children: [
54
54
  /* @__PURE__ */ a("span", { className: e.swatchPurchased, "aria-hidden": "true" }),
55
- /* @__PURE__ */ n("span", { className: e.legendText, children: [
56
- /* @__PURE__ */ a("span", { className: e.legendFigure, children: s.purchasedFigure(o(l, u)) }),
57
- /* @__PURE__ */ a("span", { className: e.legendNote, children: s.purchasedNote })
55
+ /* @__PURE__ */ s("span", { className: e.legendText, children: [
56
+ /* @__PURE__ */ a("span", { className: e.legendFigure, children: l.purchasedFigure(p(i, c)) }),
57
+ /* @__PURE__ */ a("span", { className: e.legendNote, children: l.purchasedNote })
58
58
  ] })
59
59
  ] })
60
60
  ] }),
61
- (p || v !== void 0) && /* @__PURE__ */ n("div", { className: e.popFoot, children: [
62
- p && /* @__PURE__ */ a("p", { className: e.popNote, children: p }),
63
- v !== void 0 && /* @__PURE__ */ a("button", { type: "button", className: `${y.primary} ${e.buy}`, "data-tone": "accent", onClick: v, children: s.buyTokens })
61
+ (L || m || f !== void 0) && /* @__PURE__ */ s("div", { className: e.popFoot, children: [
62
+ L && /* @__PURE__ */ a("p", { className: e.popWarning, children: L }),
63
+ m && /* @__PURE__ */ a("p", { className: e.popNote, children: m }),
64
+ f !== void 0 && /* @__PURE__ */ a("button", { type: "button", className: `${F.primary} ${e.buy}`, "data-tone": "accent", onClick: f, children: l.buyTokens })
64
65
  ] })
65
66
  ] })
66
67
  ] })
67
68
  ] });
68
69
  }
69
- function W({ balance: i, burnNote: l, onTopUp: t, labels: p, locale: r = k, walletHref: v, linkComponent: m, defaultOpen: u }) {
70
- const c = A(p), g = U({ defaultOpen: u }), h = m ?? "a", s = i < 0, d = o(s ? -i : i, r);
71
- return /* @__PURE__ */ n("div", { className: e.topRoot, "data-past-zero": s ? "true" : void 0, children: [
72
- /* @__PURE__ */ n("button", { type: "button", className: e.topTrigger, "aria-label": s ? c.pastZeroBalance(d) : c.railBalance(d), onClick: g.toggle, ...g.triggerProps, children: [
73
- /* @__PURE__ */ n("span", { className: e.topFigure, "aria-hidden": "true", children: [
74
- /* @__PURE__ */ a("span", { className: e.topAmount, children: d }),
75
- /* @__PURE__ */ a("span", { className: e.topUnit, children: s ? c.pastZero : c.unit })
70
+ function H({ balance: n, burnNote: i, onTopUp: t, labels: v, locale: N = P, walletHref: m, linkComponent: o, defaultOpen: f }) {
71
+ const d = R(v), c = w({ defaultOpen: f }), h = o ?? "a", r = n < 0, g = p(r ? -n : n, N);
72
+ return /* @__PURE__ */ s("div", { className: e.topRoot, "data-past-zero": r ? "true" : void 0, children: [
73
+ /* @__PURE__ */ s("button", { type: "button", className: e.topTrigger, "aria-label": r ? d.pastZeroBalance(g) : d.railBalance(g), onClick: c.toggle, ...c.triggerProps, children: [
74
+ /* @__PURE__ */ s("span", { className: e.topFigure, "aria-hidden": "true", children: [
75
+ /* @__PURE__ */ a("span", { className: e.topAmount, children: g }),
76
+ /* @__PURE__ */ a("span", { className: e.topUnit, children: r ? d.pastZero : d.unit })
76
77
  ] }),
77
- /* @__PURE__ */ a($, { className: e.topChevron })
78
+ /* @__PURE__ */ a(W, { className: e.topChevron })
78
79
  ] }),
79
- g.open && /* @__PURE__ */ n("div", { ...g.panelProps, className: e.popover, "aria-label": c.popover, children: [
80
- /* @__PURE__ */ n("div", { className: e.popHead, children: [
81
- /* @__PURE__ */ n("span", { className: e.popFigure, children: [
82
- /* @__PURE__ */ a("span", { className: e.popAmount, children: d }),
83
- /* @__PURE__ */ a("span", { className: e.popUnit, children: s ? c.pastZeroLong : c.unit })
80
+ c.open && /* @__PURE__ */ s("div", { ...c.panelProps, className: e.popover, "aria-label": d.popover, children: [
81
+ /* @__PURE__ */ s("div", { className: e.popHead, children: [
82
+ /* @__PURE__ */ s("span", { className: e.popFigure, children: [
83
+ /* @__PURE__ */ a("span", { className: e.popAmount, children: g }),
84
+ /* @__PURE__ */ a("span", { className: e.popUnit, children: r ? d.pastZeroLong : d.unit })
84
85
  ] }),
85
- v !== void 0 && /* @__PURE__ */ a(h, { className: y.quiet, href: v, onClick: g.close, children: c.open })
86
+ m !== void 0 && /* @__PURE__ */ a(h, { className: F.quiet, href: m, onClick: c.close, children: d.open })
86
87
  ] }),
87
- (l || t !== void 0) && /* @__PURE__ */ n("div", { className: e.popFoot, children: [
88
- l && /* @__PURE__ */ a("p", { className: e.popNote, children: l }),
89
- t !== void 0 && /* @__PURE__ */ a("button", { type: "button", className: `${y.primary} ${e.buy}`, "data-tone": "accent", onClick: t, children: c.buyTokens })
88
+ (i || t !== void 0) && /* @__PURE__ */ s("div", { className: e.popFoot, children: [
89
+ i && /* @__PURE__ */ a("p", { className: e.popNote, children: i }),
90
+ t !== void 0 && /* @__PURE__ */ a("button", { type: "button", className: `${F.primary} ${e.buy}`, "data-tone": "accent", onClick: t, children: d.buyTokens })
90
91
  ] })
91
92
  ] })
92
93
  ] });
93
94
  }
94
- function T({ granted: i, purchased: l, total: t, className: p, label: r }) {
95
- return /* @__PURE__ */ n("span", { className: p, role: r ? "img" : void 0, "aria-label": r, "aria-hidden": r ? void 0 : "true", children: [
96
- /* @__PURE__ */ a("span", { className: e.segmentGranted, "data-segment": "granted", style: { width: L(i, t) } }),
97
- /* @__PURE__ */ a("span", { className: e.segmentPurchased, "data-segment": "purchased", style: { width: L(l, t) } })
95
+ function O({ granted: n, purchased: i, total: t, tone: v, className: N, label: m }) {
96
+ return /* @__PURE__ */ s("span", { className: N, "data-tone": v, role: m ? "img" : void 0, "aria-label": m, "aria-hidden": m ? void 0 : "true", children: [
97
+ /* @__PURE__ */ a("span", { className: e.segmentGranted, "data-segment": "granted", style: { width: A(n, t) } }),
98
+ /* @__PURE__ */ a("span", { className: e.segmentPurchased, "data-segment": "purchased", style: { width: A(i, t) } })
98
99
  ] });
99
100
  }
100
- function I({ granted: i = 0, purchased: l = 0, grantCycle: t, burnedFraction: p, grantExpires: r, burnNote: v, unknown: m = !1, collapsed: u = !1, onTopUp: c, labels: g, locale: h = k }) {
101
- const s = A(g), d = () => s.bar(o(i, h), o(l, h), o(i + l, h)), B = i + l, b = (t ?? i) + l, F = t !== void 0 && t > 0 ? (t - i) / t : 0, f = p ?? F, N = !m && f >= E;
102
- if (u) {
103
- const C = m ? void 0 : s.railFigure(w(B, h));
104
- return /* @__PURE__ */ n("div", { className: e.rail, role: "group", "aria-label": C === void 0 ? s.railBalanceUnknown : s.railBalance(C), tabIndex: 0, children: [
105
- /* @__PURE__ */ a(x, { className: e.railIcon }),
106
- /* @__PURE__ */ a("span", { className: e.railFigure, children: C ?? "—" }),
107
- m ? /* @__PURE__ */ a("span", { className: e.srOnly, children: s.railUnknown }) : /* @__PURE__ */ a(R, { granted: i, purchased: l, cycleTotal: b, tone: N ? "threshold" : "rest", label: d() })
101
+ function z({ granted: n = 0, purchased: i = 0, grantCycle: t, burnedFraction: v, grantExpires: N, burnNote: m, unknown: o = !1, collapsed: f = !1, onTopUp: d, labels: c, locale: h = P }) {
102
+ const r = R(c), g = () => r.bar(p(n, h), p(i, h), p(n + i, h)), l = n + i, b = (t ?? n) + i, T = t !== void 0 && t > 0 ? (t - n) / t : 0, B = v ?? T, u = !o && B >= E;
103
+ if (f) {
104
+ const y = o ? void 0 : r.railFigure(_(l, h));
105
+ return /* @__PURE__ */ s("div", { className: e.rail, role: "group", "aria-label": y === void 0 ? r.railBalanceUnknown : r.railBalance(y), tabIndex: 0, children: [
106
+ /* @__PURE__ */ a(q, { className: e.railIcon }),
107
+ /* @__PURE__ */ a("span", { className: e.railFigure, children: y ?? "—" }),
108
+ o ? /* @__PURE__ */ a("span", { className: e.srOnly, children: r.railUnknown }) : /* @__PURE__ */ a(C, { granted: n, purchased: i, cycleTotal: b, tone: u ? "threshold" : "rest", label: g() })
108
109
  ] });
109
110
  }
110
- return /* @__PURE__ */ n("div", { className: e.chip, role: "group", "aria-label": s.region, tabIndex: 0, "data-threshold": N ? "true" : void 0, "data-unknown": m ? "true" : void 0, children: [
111
- /* @__PURE__ */ n("div", { className: e.header, children: [
112
- /* @__PURE__ */ a("span", { className: e.name, children: s.name }),
113
- N && /* @__PURE__ */ n("span", { className: e.pill, children: [
114
- Math.round(f * 100),
111
+ return /* @__PURE__ */ s("div", { className: e.chip, role: "group", "aria-label": r.region, tabIndex: 0, "data-threshold": u ? "true" : void 0, "data-unknown": o ? "true" : void 0, children: [
112
+ /* @__PURE__ */ s("div", { className: e.header, children: [
113
+ /* @__PURE__ */ a("span", { className: e.name, children: r.name }),
114
+ u && /* @__PURE__ */ s("span", { className: e.pill, children: [
115
+ Math.round(B * 100),
115
116
  "%"
116
117
  ] })
117
118
  ] }),
118
- m ? /* @__PURE__ */ n("div", { className: e.figure, children: [
119
+ o ? /* @__PURE__ */ s("div", { className: e.figure, children: [
119
120
  /* @__PURE__ */ a("span", { className: e.amount, "aria-hidden": "true", children: "—" }),
120
- /* @__PURE__ */ a(O, { className: e.retry }),
121
- /* @__PURE__ */ a("span", { className: e.srOnly, children: s.balanceUnknown })
122
- ] }) : /* @__PURE__ */ n("div", { className: e.figure, children: [
123
- /* @__PURE__ */ a("span", { className: e.amount, children: o(B, h) }),
124
- /* @__PURE__ */ a("span", { className: e.unit, children: s.unit })
121
+ /* @__PURE__ */ a(S, { className: e.retry }),
122
+ /* @__PURE__ */ a("span", { className: e.srOnly, children: r.balanceUnknown })
123
+ ] }) : /* @__PURE__ */ s("div", { className: e.figure, children: [
124
+ /* @__PURE__ */ a("span", { className: e.amount, children: p(l, h) }),
125
+ /* @__PURE__ */ a("span", { className: e.unit, children: r.unit })
125
126
  ] }),
126
- m ? /* @__PURE__ */ a("div", { className: e.bar, "data-tone": "unknown", "aria-hidden": "true" }) : /* @__PURE__ */ a(R, { granted: i, purchased: l, cycleTotal: b, tone: N ? "threshold" : "rest", label: d() }),
127
- !m && !N && /* @__PURE__ */ n("div", { className: e.details, children: [
128
- /* @__PURE__ */ n("dl", { className: e.split, children: [
129
- /* @__PURE__ */ n("div", { className: e.splitRow, children: [
130
- /* @__PURE__ */ n("dt", { className: e.splitLabel, children: [
127
+ o ? /* @__PURE__ */ a("div", { className: e.bar, "data-tone": "unknown", "aria-hidden": "true" }) : /* @__PURE__ */ a(C, { granted: n, purchased: i, cycleTotal: b, tone: u ? "threshold" : "rest", label: g() }),
128
+ !o && !u && /* @__PURE__ */ s("div", { className: e.details, children: [
129
+ /* @__PURE__ */ s("dl", { className: e.split, children: [
130
+ /* @__PURE__ */ s("div", { className: e.splitRow, children: [
131
+ /* @__PURE__ */ s("dt", { className: e.splitLabel, children: [
131
132
  /* @__PURE__ */ a("span", { className: e.dotGranted, "aria-hidden": "true" }),
132
- s.granted
133
+ r.granted
133
134
  ] }),
134
- /* @__PURE__ */ a("dd", { className: e.splitAmount, children: o(i, h) })
135
+ /* @__PURE__ */ a("dd", { className: e.splitAmount, children: p(n, h) })
135
136
  ] }),
136
- /* @__PURE__ */ n("div", { className: e.splitRow, children: [
137
- /* @__PURE__ */ n("dt", { className: e.splitLabel, children: [
137
+ /* @__PURE__ */ s("div", { className: e.splitRow, children: [
138
+ /* @__PURE__ */ s("dt", { className: e.splitLabel, children: [
138
139
  /* @__PURE__ */ a("span", { className: e.dotPurchased, "aria-hidden": "true" }),
139
- s.purchased
140
+ r.purchased
140
141
  ] }),
141
- /* @__PURE__ */ a("dd", { className: e.splitAmount, children: o(l, h) })
142
+ /* @__PURE__ */ a("dd", { className: e.splitAmount, children: p(i, h) })
142
143
  ] })
143
144
  ] }),
144
- r && /* @__PURE__ */ a("p", { className: e.footer, children: s.grantExpiry(r) })
145
+ N && /* @__PURE__ */ a("p", { className: e.footer, children: r.grantExpiry(N) })
145
146
  ] }),
146
- N && v && /* @__PURE__ */ a("p", { className: e.burnNote, children: v }),
147
- !m && c !== void 0 && /* @__PURE__ */ a(
147
+ u && m && /* @__PURE__ */ a("p", { className: e.burnNote, children: m }),
148
+ !o && d !== void 0 && /* @__PURE__ */ a(
148
149
  "button",
149
150
  {
150
151
  type: "button",
151
- className: `${N ? y.primary : y.quiet} ${e.topUp}`,
152
- "data-tone": N ? "accent" : void 0,
153
- "data-grown": N ? "true" : void 0,
154
- onClick: c,
155
- children: s.topUp
152
+ className: `${u ? F.primary : F.quiet} ${e.topUp}`,
153
+ "data-tone": u ? "accent" : void 0,
154
+ "data-grown": u ? "true" : void 0,
155
+ onClick: d,
156
+ children: r.topUp
156
157
  }
157
158
  )
158
159
  ] });
159
160
  }
160
161
  export {
161
- J as WalletChip
162
+ se as WalletChip
162
163
  };
163
164
  //# sourceMappingURL=WalletChip.js.map