@boost33/ui 0.5.0 → 0.6.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 +2894 -0
- package/README.md +11 -12
- package/dist/components/AccountMenu/AccountMenu.js +66 -0
- package/dist/components/AccountMenu/AccountMenu.js.map +1 -0
- package/dist/components/AccountMenu/AccountMenu.module.css.js +42 -0
- package/dist/components/AccountMenu/AccountMenu.module.css.js.map +1 -0
- package/dist/components/AccountMenu/icons.js +32 -0
- package/dist/components/AccountMenu/icons.js.map +1 -0
- package/dist/components/AccountMenu/labels.js +14 -0
- package/dist/components/AccountMenu/labels.js.map +1 -0
- package/dist/components/CommandPalette/CommandPalette.js +65 -0
- package/dist/components/CommandPalette/CommandPalette.js.map +1 -0
- package/dist/components/CommandPalette/CommandPalette.module.css.js +34 -0
- package/dist/components/CommandPalette/CommandPalette.module.css.js.map +1 -0
- package/dist/components/CommandPalette/icons.js +23 -0
- package/dist/components/CommandPalette/icons.js.map +1 -0
- package/dist/components/CommandPalette/labels.js +19 -0
- package/dist/components/CommandPalette/labels.js.map +1 -0
- package/dist/components/LaunchLoader/LaunchLoader.d.ts +8 -4
- package/dist/components/LaunchLoader/LaunchLoader.js +22 -35
- package/dist/components/LaunchLoader/LaunchLoader.js.map +1 -1
- package/dist/components/LaunchLoader/LaunchLoader.module.css.js +16 -18
- package/dist/components/LaunchLoader/LaunchLoader.module.css.js.map +1 -1
- package/dist/components/NotificationCenter/NotificationCenter.js +67 -0
- package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationCenter.module.css.js +54 -0
- package/dist/components/NotificationCenter/NotificationCenter.module.css.js.map +1 -0
- package/dist/components/NotificationCenter/icons.js +45 -0
- package/dist/components/NotificationCenter/icons.js.map +1 -0
- package/dist/components/NotificationCenter/labels.js +26 -0
- package/dist/components/NotificationCenter/labels.js.map +1 -0
- package/dist/components/SettingsFrame/SettingsFrame.d.ts +91 -0
- package/dist/components/SettingsFrame/SettingsFrame.js +109 -0
- package/dist/components/SettingsFrame/SettingsFrame.js.map +1 -0
- package/dist/components/SettingsFrame/SettingsFrame.module.css.js +74 -0
- package/dist/components/SettingsFrame/SettingsFrame.module.css.js.map +1 -0
- package/dist/components/SettingsFrame/icons.d.ts +10 -0
- package/dist/components/SettingsFrame/icons.js +37 -0
- package/dist/components/SettingsFrame/icons.js.map +1 -0
- package/dist/components/SettingsFrame/labels.d.ts +36 -0
- package/dist/components/SettingsFrame/labels.js +18 -0
- package/dist/components/SettingsFrame/labels.js.map +1 -0
- package/dist/index.d.ts +18 -1
- package/dist/index.js +46 -32
- package/dist/index.js.map +1 -1
- package/dist/launch-gradient.d.ts +27 -103
- package/dist/launch-gradient.js +4 -56
- package/dist/launch-gradient.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -49,23 +49,22 @@ package** — until then it has one consumer, which is a fork with a version num
|
|
|
49
49
|
|
|
50
50
|
`LaunchLoader` is presentational. The page that renders it owns the timing and
|
|
51
51
|
passes in a `caption` and a `progress` (0–100, or `null` while there is no
|
|
52
|
-
honest number). The
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
0.
|
|
56
|
-
|
|
57
|
-
measures it.
|
|
52
|
+
honest number). The background is built in and the same for every product:
|
|
53
|
+
black, with one blurred brand-orange glow rising from below the middle of the
|
|
54
|
+
screen. There are no product colours to pass; `stops` is deprecated and ignored
|
|
55
|
+
since 0.5.1. The caption sits straight on the glow, and
|
|
56
|
+
`npm run launch-contrast-check` measures it.
|
|
58
57
|
|
|
59
|
-
The
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
The glow is drawn by the package stylesheet and takes no prop, so both sides of
|
|
59
|
+
a hop paint the identical screen. Inline the ground colour too, so the instant
|
|
60
|
+
before the stylesheet and the markup arrive is already black rather than white:
|
|
62
61
|
|
|
63
62
|
```tsx
|
|
64
63
|
import { LaunchLoader, launchBackdropCss } from '@boost33/ui'
|
|
65
64
|
|
|
66
|
-
<style dangerouslySetInnerHTML={{ __html: launchBackdropCss(
|
|
67
|
-
<LaunchLoader
|
|
65
|
+
<style dangerouslySetInnerHTML={{ __html: launchBackdropCss() }} />
|
|
66
|
+
<LaunchLoader caption={caption} progress={progress} />
|
|
68
67
|
```
|
|
69
68
|
|
|
70
69
|
An animated backdrop, when one exists, goes in the `backdrop` slot. The screen
|
|
71
|
-
must stay complete without it. See `CHANGELOG.md` (B33-1389) for the full contract.
|
|
70
|
+
must stay complete without it. See `CHANGELOG.md` (B33-1389, B33-1401) for the full contract.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsxs as s, jsx as e, Fragment as v } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment as u } from "react";
|
|
3
|
+
import { ACCOUNT_MENU_ICONS as f } from "./icons.js";
|
|
4
|
+
import { resolveAccountMenuLabels as g } from "./labels.js";
|
|
5
|
+
import a from "./AccountMenu.module.css.js";
|
|
6
|
+
function L({ person: i, org: l, groups: o, labels: d, linkComponent: t }) {
|
|
7
|
+
const m = g(d), p = t ?? "a";
|
|
8
|
+
function h(n) {
|
|
9
|
+
const r = n.description === void 0, N = n.icon === void 0 ? null : f[n.icon](a.icon), c = /* @__PURE__ */ s(v, { children: [
|
|
10
|
+
/* @__PURE__ */ e("span", { className: a.lane, "aria-hidden": "true", children: N }),
|
|
11
|
+
/* @__PURE__ */ s("span", { className: a.rowText, children: [
|
|
12
|
+
/* @__PURE__ */ e("span", { className: a.rowLabel, children: n.label }),
|
|
13
|
+
n.description !== void 0 && /* @__PURE__ */ e("span", { className: a.rowDescription, children: n.description })
|
|
14
|
+
] })
|
|
15
|
+
] });
|
|
16
|
+
return n.href === void 0 ? /* @__PURE__ */ e(
|
|
17
|
+
"button",
|
|
18
|
+
{
|
|
19
|
+
type: "button",
|
|
20
|
+
className: a.row,
|
|
21
|
+
"data-item": n.id,
|
|
22
|
+
"data-single-line": r ? "true" : void 0,
|
|
23
|
+
children: c
|
|
24
|
+
}
|
|
25
|
+
) : /* @__PURE__ */ e(
|
|
26
|
+
p,
|
|
27
|
+
{
|
|
28
|
+
className: a.row,
|
|
29
|
+
href: n.href,
|
|
30
|
+
"data-item": n.id,
|
|
31
|
+
"data-single-line": r ? "true" : void 0,
|
|
32
|
+
children: c
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return /* @__PURE__ */ s("div", { className: a.panel, "aria-label": m.panel, children: [
|
|
37
|
+
/* @__PURE__ */ s("div", { className: a.person, children: [
|
|
38
|
+
i.avatarUrl === void 0 ? /* @__PURE__ */ e("span", { className: a.personAvatar, "aria-hidden": "true" }) : (
|
|
39
|
+
// Empty alt, not a name: the person's name is on the next line in. The
|
|
40
|
+
// guard in tests/no-hardcoded-strings.test.ts reads `alt`, which is
|
|
41
|
+
// the right thing to read -- an empty one is an absence of copy, not
|
|
42
|
+
// untranslated copy.
|
|
43
|
+
/* @__PURE__ */ e("img", { className: a.personAvatar, src: i.avatarUrl, alt: "" })
|
|
44
|
+
),
|
|
45
|
+
/* @__PURE__ */ s("span", { className: a.personText, children: [
|
|
46
|
+
/* @__PURE__ */ e("span", { className: a.personName, children: i.name }),
|
|
47
|
+
/* @__PURE__ */ e("span", { className: a.personEmail, children: i.email })
|
|
48
|
+
] })
|
|
49
|
+
] }),
|
|
50
|
+
/* @__PURE__ */ s("div", { className: a.org, children: [
|
|
51
|
+
/* @__PURE__ */ s("span", { className: a.orgIdentity, children: [
|
|
52
|
+
/* @__PURE__ */ e("span", { className: a.orgTile, "aria-hidden": "true", children: l.initials }),
|
|
53
|
+
/* @__PURE__ */ e("span", { className: a.orgName, children: l.name })
|
|
54
|
+
] }),
|
|
55
|
+
l.role !== void 0 && /* @__PURE__ */ e("span", { className: a.orgRole, children: l.role })
|
|
56
|
+
] }),
|
|
57
|
+
o.map((n) => /* @__PURE__ */ s(u, { children: [
|
|
58
|
+
/* @__PURE__ */ e("hr", { className: a.divider }),
|
|
59
|
+
/* @__PURE__ */ e("ul", { className: a.rows, children: n.items.map((r) => /* @__PURE__ */ e("li", { children: h(r) }, r.id)) })
|
|
60
|
+
] }, n.id))
|
|
61
|
+
] });
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
L as AccountMenu
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=AccountMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccountMenu.js","sources":["../../../src/components/AccountMenu/AccountMenu.tsx"],"sourcesContent":["// No \"use client\", and that is Stage A's whole shape rather than an oversight.\n// This renders the panel and nothing else: no open/closed state, no handlers, no\n// useAnchoredOverlay, no keyboard handling. So it stays a Server Component, a\n// consumer pays no client bundle for it, and tests/guards.test.ts -- which pins\n// the built package's \"use client\" modules to exactly three -- stays green\n// without being edited. Stage B is where that changes, deliberately and with the\n// guard's expectation updated in the same change.\n\nimport { Fragment } from 'react'\nimport type { ElementType, ReactElement } from 'react'\nimport { ACCOUNT_MENU_ICONS, type AccountMenuIcon } from './icons'\nimport { resolveAccountMenuLabels, type AccountMenuLabels } from './labels'\nimport styles from './AccountMenu.module.css'\n\n/**\n * The signed-in person, at the top of the panel. Supplied by the consumer -- the\n * menu reads no session and fetches nothing (CLAUDE.md).\n */\nexport interface AccountMenuPerson {\n /** Their name, e.g. \"Sofia Marques\". */\n name: string\n /** Their email, on the line beneath. */\n email: string\n /**\n * An avatar image. Omit it -- the drawing does -- and the circle draws bare, in\n * `--color-border-strong`.\n *\n * The image is decorative when it renders: it takes an empty `alt`, because the\n * person's name is on the line beside it and a name here would make a screen\n * reader say who you are twice. Same reasoning as `ProductMark`'s default.\n */\n avatarUrl?: string\n}\n\n/**\n * The organisation strip under the person: which account you are acting in.\n * Identity's data, supplied per render, never looked up here (ADR-0003).\n */\nexport interface AccountMenuOrg {\n /** The organisation's name, e.g. \"Acme Coaching\". */\n name: string\n /** The initials on the tile beside it, e.g. \"AC\". Decorative -- the name is next to it. */\n initials: string\n /**\n * The role pill at the right of the strip, e.g. \"Admin\". Omit it and no pill is\n * drawn -- it is Identity's word for what this person is in this organisation,\n * so a consumer with nothing to say there says nothing rather than guessing.\n */\n role?: string\n}\n\n/**\n * One row in the panel.\n *\n * Whether it navigates is decided by `href` and nothing else, which is ADR-0011's\n * rule applied rather than re-decided: a row with an `href` is a link and renders\n * through `linkComponent`; a row without one is an action and stays a `<button>`.\n * That keeps the component out of the business of knowing which of Profile,\n * Settings, Switch account and Sign out are navigations in a given product --\n * four apps may answer differently, and the consumer already knows.\n */\nexport interface AccountMenuItem {\n /** Stable identity: the React key, and what a test addresses the row by. */\n id: string\n /** The row's name, e.g. \"Profile\". */\n label: string\n /**\n * The line beneath the name. Omit it and the row is a single line, set in the\n * quieter register the drawing gives its Sign out row -- see `.rowLabel` in the\n * stylesheet for why the two travel together.\n */\n description?: string\n /** Where the row goes. Omit it and the row is an action, rendered as a button. */\n href?: string\n /** Which glyph the row carries. Omit it and the glyph lane stays, empty. */\n icon?: AccountMenuIcon\n}\n\n/**\n * A run of rows drawn together. The panel's hairline is drawn above every group,\n * which is what separates the first group from the identity blocks above it as\n * well as each group from the last.\n *\n * Grouped rather than flat because the drawing puts a rule between its three\n * navigations and its one way out, and grouped rather than named (`items` plus a\n * `footer`) because \"footer\" would be this package inventing a meaning for the\n * second group. A consumer that wants one group passes one.\n */\nexport interface AccountMenuGroup {\n /** Stable identity: the React key. */\n id: string\n /** The rows, in the order they are drawn. */\n items: AccountMenuItem[]\n}\n\nexport interface AccountMenuProps {\n /** The signed-in person. */\n person: AccountMenuPerson\n /** The organisation this person is acting in. */\n org: AccountMenuOrg\n /** The row groups, in order. A hairline is drawn above each one. */\n groups: AccountMenuGroup[]\n /**\n * Every user-facing string that is not row data -- which is the panel's\n * accessible name, and today nothing else. Each field defaults to English, and\n * a field left out, or supplied as `undefined` (what a missed next-intl key\n * looks like), keeps its default.\n */\n labels?: Partial<AccountMenuLabels>\n /**\n * The element a row with an `href` renders through. Defaults to a plain `a`; a\n * router-owning consumer passes its own so the rows route client-side with the\n * locale prefix intact (ADR-0011, B33-847). Rows without an `href` are buttons\n * and ignore it.\n */\n linkComponent?: ElementType\n}\n\n/**\n * The account menu: who you are, which organisation you are in, and the way into\n * Settings and out of the session (B33-493).\n *\n * **This is Stage A, and this component is the panel alone.** It takes no\n * trigger, holds no open state and wires nothing. That is not a half-built\n * version of trigger-plus-panel -- it is the part of this component that the two\n * reference drawings agree about. Paper's 004 \"AccountMenu — popover\" and\n * Identity's 103 · 11 Account menu are identical in every property of the panel,\n * and they disagree about the anchor (004 draws a bell on a tile, an unread dot\n * and a halo behind the avatar; 103 draws none of the three) and about where the\n * panel sits relative to it (004: 8px below, 16px right inset, overhanging the\n * avatar by 4px; 103: 10px below, 20px inset, flush). CLAUDE.md puts that choice\n * with the person at the fidelity gate, and says plainly that an agent picking\n * one has invented a referent. So the anchor is not here, `TopBar` is untouched,\n * and the specimen positions the panel in its own stylesheet.\n *\n * A disclosure, like the switcher (ADR-0010): no widget role on the panel, no\n * role on the rows, every row the real `<a>` or `<button>` it already is, and Tab\n * the document's own order. Dismissal, focus restoration and the trigger's\n * `aria-expanded` are the shared anchored-overlay contract's (ADR-0009) and\n * arrive with the trigger in Stage B.\n *\n * Nothing here is authoritative. Every measurement in the stylesheet is read off\n * a drawing that no human has approved, and the gate is where it becomes a\n * referent -- at which point the approved baseline and the measurements written\n * into the spec are what binds, not Paper.\n */\nexport function AccountMenu({ person, org, groups, labels, linkComponent }: AccountMenuProps) {\n const t = resolveAccountMenuLabels(labels)\n const Link: ElementType = linkComponent ?? 'a'\n\n function renderRow(item: AccountMenuItem): ReactElement {\n const singleLine = item.description === undefined\n const glyph = item.icon === undefined ? null : ACCOUNT_MENU_ICONS[item.icon](styles.icon)\n\n // The lane is drawn whether or not the row has a glyph. A row that drops its\n // icon and lets the text slide left would break the column the four names\n // stand in, which is the one alignment a panel of stacked rows has to hold.\n // Same reasoning as NavItem's trailing slot (CONTEXT.md, \"Trailing slot\").\n const content = (\n <>\n <span className={styles.lane} aria-hidden=\"true\">\n {glyph}\n </span>\n <span className={styles.rowText}>\n <span className={styles.rowLabel}>{item.label}</span>\n {item.description !== undefined && (\n <span className={styles.rowDescription}>{item.description}</span>\n )}\n </span>\n </>\n )\n\n // No onClick on either branch: Stage A renders the element and wires nothing.\n // The action row is a real <button type=\"button\"> so that the shape Stage B\n // attaches a handler to is the shape a human approved here.\n return item.href === undefined ? (\n <button\n type=\"button\"\n className={styles.row}\n data-item={item.id}\n data-single-line={singleLine ? 'true' : undefined}\n >\n {content}\n </button>\n ) : (\n <Link\n className={styles.row}\n href={item.href}\n data-item={item.id}\n data-single-line={singleLine ? 'true' : undefined}\n >\n {content}\n </Link>\n )\n }\n\n return (\n <div className={styles.panel} aria-label={t.panel}>\n <div className={styles.person}>\n {person.avatarUrl === undefined ? (\n <span className={styles.personAvatar} aria-hidden=\"true\" />\n ) : (\n // Empty alt, not a name: the person's name is on the next line in. The\n // guard in tests/no-hardcoded-strings.test.ts reads `alt`, which is\n // the right thing to read -- an empty one is an absence of copy, not\n // untranslated copy.\n <img className={styles.personAvatar} src={person.avatarUrl} alt=\"\" />\n )}\n <span className={styles.personText}>\n <span className={styles.personName}>{person.name}</span>\n <span className={styles.personEmail}>{person.email}</span>\n </span>\n </div>\n\n <div className={styles.org}>\n <span className={styles.orgIdentity}>\n <span className={styles.orgTile} aria-hidden=\"true\">\n {org.initials}\n </span>\n <span className={styles.orgName}>{org.name}</span>\n </span>\n {org.role !== undefined && <span className={styles.orgRole}>{org.role}</span>}\n </div>\n\n {/* A Fragment rather than a wrapper element, so the hairline and the rows\n are direct children of the panel's flex column exactly as the drawing\n has them. A wrapper would be a block in between, and the hairline's\n block margins -- which are measured, see `.divider` -- would collapse\n through its edges and move the rule. */}\n {groups.map((group) => (\n <Fragment key={group.id}>\n <hr className={styles.divider} />\n <ul className={styles.rows}>\n {group.items.map((item) => (\n <li key={item.id}>{renderRow(item)}</li>\n ))}\n </ul>\n </Fragment>\n ))}\n </div>\n )\n}\n"],"names":["AccountMenu","person","org","groups","labels","linkComponent","t","resolveAccountMenuLabels","Link","renderRow","item","singleLine","glyph","ACCOUNT_MENU_ICONS","styles","content","jsxs","Fragment","jsx","group"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const o = "_panel_4usug_54", s = "_person_4usug_72", r = "_personAvatar_4usug_85", e = "_personText_4usug_98", _ = "_personName_4usug_106", n = "_personEmail_4usug_122", t = "_org_4usug_147", u = "_orgIdentity_4usug_161", g = "_orgTile_4usug_178", a = "_orgName_4usug_194", c = "_orgRole_4usug_209", p = "_divider_4usug_143", i = "_rows_4usug_242", l = "_row_4usug_48", w = "_rowDescription_4usug_299", d = "_lane_4usug_303", m = "_rowText_4usug_347", T = "_rowLabel_4usug_365", x = {
|
|
2
|
+
panel: o,
|
|
3
|
+
person: s,
|
|
4
|
+
personAvatar: r,
|
|
5
|
+
personText: e,
|
|
6
|
+
personName: _,
|
|
7
|
+
personEmail: n,
|
|
8
|
+
org: t,
|
|
9
|
+
orgIdentity: u,
|
|
10
|
+
orgTile: g,
|
|
11
|
+
orgName: a,
|
|
12
|
+
orgRole: c,
|
|
13
|
+
divider: p,
|
|
14
|
+
rows: i,
|
|
15
|
+
row: l,
|
|
16
|
+
rowDescription: w,
|
|
17
|
+
lane: d,
|
|
18
|
+
rowText: m,
|
|
19
|
+
rowLabel: T
|
|
20
|
+
};
|
|
21
|
+
export {
|
|
22
|
+
x as default,
|
|
23
|
+
p as divider,
|
|
24
|
+
d as lane,
|
|
25
|
+
t as org,
|
|
26
|
+
u as orgIdentity,
|
|
27
|
+
a as orgName,
|
|
28
|
+
c as orgRole,
|
|
29
|
+
g as orgTile,
|
|
30
|
+
o as panel,
|
|
31
|
+
s as person,
|
|
32
|
+
r as personAvatar,
|
|
33
|
+
n as personEmail,
|
|
34
|
+
_ as personName,
|
|
35
|
+
e as personText,
|
|
36
|
+
l as row,
|
|
37
|
+
w as rowDescription,
|
|
38
|
+
T as rowLabel,
|
|
39
|
+
m as rowText,
|
|
40
|
+
i as rows
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=AccountMenu.module.css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccountMenu.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsxs as h, jsx as a } from "react/jsx-runtime";
|
|
2
|
+
const r = {
|
|
3
|
+
viewBox: "0 0 24 24",
|
|
4
|
+
fill: "none",
|
|
5
|
+
stroke: "currentColor",
|
|
6
|
+
strokeWidth: "2",
|
|
7
|
+
strokeLinecap: "round",
|
|
8
|
+
strokeLinejoin: "round",
|
|
9
|
+
"aria-hidden": !0
|
|
10
|
+
}, d = {
|
|
11
|
+
person: (t) => /* @__PURE__ */ h("svg", { className: t, ...r, children: [
|
|
12
|
+
/* @__PURE__ */ a("path", { d: "M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" }),
|
|
13
|
+
/* @__PURE__ */ a("path", { d: "M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2" })
|
|
14
|
+
] }),
|
|
15
|
+
settings: (t) => /* @__PURE__ */ h("svg", { className: t, ...r, children: [
|
|
16
|
+
/* @__PURE__ */ a("path", { d: "M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065" }),
|
|
17
|
+
/* @__PURE__ */ a("path", { d: "M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" })
|
|
18
|
+
] }),
|
|
19
|
+
switch: (t) => /* @__PURE__ */ h("svg", { className: t, ...r, children: [
|
|
20
|
+
/* @__PURE__ */ a("path", { d: "M4 6a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z" }),
|
|
21
|
+
/* @__PURE__ */ a("path", { d: "M9 8l6 4l-6 4z" })
|
|
22
|
+
] }),
|
|
23
|
+
signOut: (t) => /* @__PURE__ */ h("svg", { className: t, ...r, children: [
|
|
24
|
+
/* @__PURE__ */ a("path", { d: "M14 8v-2a2 2 0 0 0 -2 -2h-7a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2 -2v-2" }),
|
|
25
|
+
/* @__PURE__ */ a("path", { d: "M9 12h12l-3 -3" }),
|
|
26
|
+
/* @__PURE__ */ a("path", { d: "M18 15l3 -3" })
|
|
27
|
+
] })
|
|
28
|
+
};
|
|
29
|
+
export {
|
|
30
|
+
d as ACCOUNT_MENU_ICONS
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.js","sources":["../../../src/components/AccountMenu/icons.tsx"],"sourcesContent":["// The account menu's four row glyphs. Drawn in `currentColor` so the row's own\n// ink carries them -- which is also what keeps the no-hardcoded-hex guard\n// satisfied, and what lets the picked-out row darken its glyph with its text in\n// one rule rather than two. Same arrangement as AppSwitcher/icons.tsx.\n//\n// All four are decorative: every row has a visible name beside its glyph, so a\n// name here would only make a screen reader say the row twice. Hence\n// `aria-hidden` on each, with no `title` prop to pass -- the opposite of\n// ProductMark, which can stand alone.\n//\n// The path data is reproduced verbatim from the AccountMenu drawings on Paper's\n// 004 Components page, where all four are Tabler outline glyphs on a 24-unit\n// grid at stroke 2. The drawing on 103 Identity carries byte-identical data, so\n// there is nothing to reconcile between the two here. They are NOT settled\n// artwork: the Wallet has never rendered this menu, so no approved baseline\n// fixes them, and the person at the component's fidelity gate may replace any of\n// them (CLAUDE.md, \"The three components the Wallet never rendered\").\n//\n// One of them is worth flagging rather than quietly shipping: `switch` is a\n// rounded square with a play triangle in it, which is what the drawing uses for\n// \"Switch account\" and is not an obvious reading of that row. Reproduced as\n// drawn, raised at the gate, not silently swapped for a better guess.\n\nimport type { ReactElement } from 'react'\n\n/**\n * Which glyph a row carries. A closed union, unlike `ProductMark`'s `slug`:\n * these four are the package's own chrome rather than a registry Identity owns\n * and can run ahead of, so there is no served value to degrade from. A row that\n * wants no glyph omits the field and keeps the empty lane -- see `.lane` in\n * AccountMenu.module.css for why the lane stays.\n */\nexport type AccountMenuIcon = 'person' | 'settings' | 'switch' | 'signOut'\n\nconst COMMON = {\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: '2',\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n 'aria-hidden': true,\n} as const\n\n/** The glyph for each name, keyed so the row renders one lookup and no switch. */\nexport const ACCOUNT_MENU_ICONS: Record<AccountMenuIcon, (className?: string) => ReactElement> = {\n person: (className) => (\n <svg className={className} {...COMMON}>\n <path d=\"M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0\" />\n <path d=\"M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2\" />\n </svg>\n ),\n settings: (className) => (\n <svg className={className} {...COMMON}>\n <path d=\"M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065\" />\n <path d=\"M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0\" />\n </svg>\n ),\n switch: (className) => (\n <svg className={className} {...COMMON}>\n <path d=\"M4 6a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z\" />\n <path d=\"M9 8l6 4l-6 4z\" />\n </svg>\n ),\n signOut: (className) => (\n <svg className={className} {...COMMON}>\n <path d=\"M14 8v-2a2 2 0 0 0 -2 -2h-7a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2 -2v-2\" />\n <path d=\"M9 12h12l-3 -3\" />\n <path d=\"M18 15l3 -3\" />\n </svg>\n ),\n}\n"],"names":["COMMON","ACCOUNT_MENU_ICONS","className","jsx"],"mappings":";AAkCA,MAAMA,IAAS;AAAA,EACb,SAAS;AAAA,EACT,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,eAAe;AACjB,GAGaC,IAAoF;AAAA,EAC/F,QAAQ,CAACC,wBACN,OAAA,EAAI,WAAAA,GAAuB,GAAGF,GAC7B,UAAA;AAAA,IAAA,gBAAAG,EAAC,QAAA,EAAK,GAAE,oCAAA,CAAoC;AAAA,IAC5C,gBAAAA,EAAC,QAAA,EAAK,GAAE,4CAAA,CAA4C;AAAA,EAAA,GACtD;AAAA,EAEF,UAAU,CAACD,wBACR,OAAA,EAAI,WAAAA,GAAuB,GAAGF,GAC7B,UAAA;AAAA,IAAA,gBAAAG,EAAC,QAAA,EAAK,GAAE,6gBAAA,CAA6gB;AAAA,IACrhB,gBAAAA,EAAC,QAAA,EAAK,GAAE,qCAAA,CAAqC;AAAA,EAAA,GAC/C;AAAA,EAEF,QAAQ,CAACD,wBACN,OAAA,EAAI,WAAAA,GAAuB,GAAGF,GAC7B,UAAA;AAAA,IAAA,gBAAAG,EAAC,QAAA,EAAK,GAAE,8EAAA,CAA8E;AAAA,IACtF,gBAAAA,EAAC,QAAA,EAAK,GAAE,iBAAA,CAAiB;AAAA,EAAA,GAC3B;AAAA,EAEF,SAAS,CAACD,wBACP,OAAA,EAAI,WAAAA,GAAuB,GAAGF,GAC7B,UAAA;AAAA,IAAA,gBAAAG,EAAC,QAAA,EAAK,GAAE,kFAAA,CAAkF;AAAA,IAC1F,gBAAAA,EAAC,QAAA,EAAK,GAAE,iBAAA,CAAiB;AAAA,IACzB,gBAAAA,EAAC,QAAA,EAAK,GAAE,cAAA,CAAc;AAAA,EAAA,EAAA,CACxB;AAEJ;"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const c = Object.freeze({
|
|
2
|
+
panel: "Account"
|
|
3
|
+
});
|
|
4
|
+
function o(e) {
|
|
5
|
+
const t = Object.fromEntries(
|
|
6
|
+
Object.entries(e ?? {}).filter(([, n]) => n !== void 0)
|
|
7
|
+
);
|
|
8
|
+
return { ...c, ...t };
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
c as defaultAccountMenuLabels,
|
|
12
|
+
o as resolveAccountMenuLabels
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","sources":["../../../src/components/AccountMenu/labels.ts"],"sourcesContent":["// The account menu's own user-facing words -- which is one word, and the\n// shortness is the point of the file rather than an argument against it.\n//\n// Everything else a person reads in this panel is row data the consumer supplies\n// and therefore translates by construction: the person's name and email, the\n// organisation's name, initials and role, and each row's label and description.\n// That is the same split AppSwitcherLabels draws (\"the product names ... are\n// Identity's data, supplied per row, not copy this package owns\"). What is left\n// is the panel's accessible name, which no row carries and which a disclosure\n// panel has no other way to get (ADR-0010).\n//\n// It takes the WalletChip's label contract rather than inventing a third\n// dialect, and it takes it in full on day one even for one field. B33-1007 is\n// the ticket for what happens otherwise: the switcher's module opens by claiming\n// parity with the chip's and had none, and two of the three divergences it\n// records were only expensive because they were retrofitted. The first --\n// `labels` being the whole interface rather than a `Partial` -- is a breaking\n// change to fix once a consumer has written the object out, which is exactly the\n// position a one-field interface invites. So:\n//\n// * `labels` is `Partial<AccountMenuLabels>`, so the second field costs no\n// consumer a typecheck (CLAUDE.md, \"Versioning\");\n// * `resolveAccountMenuLabels` filters explicitly-`undefined` fields before\n// merging, so a missed next-intl key falls back to English instead of\n// unnaming the panel (B33-873);\n// * `defaultAccountMenuLabels` is `Object.freeze({ ... } satisfies ...)` with\n// no type annotation, so the freeze survives into the emitted `.d.ts`\n// instead of being widened back to mutable (B33-877, B33-916).\n//\n// There are no value-carrying labels here, so none of the chip's\n// `%placeholder%` machinery is reproduced. If one ever arrives, it arrives in the\n// chip's shape -- a template delimited `%name%`, never `{name}`, because a brace\n// is ICU argument syntax and a consumer keeps these strings in an ICU catalogue\n// (B33-1277; the reasoning is in `src/fill-template.ts`).\n\n/** Every user-facing string the account menu renders that is not row data. */\nexport interface AccountMenuLabels {\n /**\n * The panel's accessible name. A disclosure panel carries no widget role, so\n * an `aria-label` is the only thing that names it (ADR-0010). Default\n * \"Account\".\n *\n * It names the control rather than the person in it: the person's name and\n * email are inside the panel and a screen reader reaches them on the way\n * through, so putting them in the name as well says them twice.\n */\n panel: string\n}\n\n/**\n * The English defaults. A consumer that passes nothing renders English.\n *\n * Frozen because it is a public export reaching four products on a version bump:\n * `const` protects the binding and not the contents, so without the freeze a\n * consumer aliasing it -- `const mine = defaultAccountMenuLabels; mine.panel =\n * 'Compte'` -- renames every account menu in the process (B33-877). The freeze\n * carries no `: AccountMenuLabels` annotation on purpose; the annotation widens\n * `Readonly<...>` back to mutable in the emitted declaration file and makes the\n * freeze runtime-only (B33-916). `satisfies` checks the shape without widening.\n */\nexport const defaultAccountMenuLabels = Object.freeze({\n panel: 'Account',\n} satisfies AccountMenuLabels)\n\n/**\n * Merge a consumer's partial `labels` onto the English defaults, treating an\n * explicitly-`undefined` field as unsupplied -- the same resolution\n * `resolveWalletChipLabels` and `resolveAppSwitcherLabels` perform.\n *\n * A next-intl `t('...')` returns `undefined` on a missed key, so\n * `{ panel: undefined }` is what one missing translation looks like at the call\n * site. A plain object spread copies that `undefined` across and leaves the\n * panel with an empty `aria-label`, which is the one thing naming it; a per-field\n * skip does not (B33-873).\n */\nexport function resolveAccountMenuLabels(labels?: Partial<AccountMenuLabels>): AccountMenuLabels {\n const supplied = Object.fromEntries(\n Object.entries(labels ?? {}).filter(([, value]) => value !== undefined),\n ) as Partial<AccountMenuLabels>\n return { ...defaultAccountMenuLabels, ...supplied }\n}\n"],"names":["defaultAccountMenuLabels","resolveAccountMenuLabels","labels","supplied","value"],"mappings":"AA4DO,MAAMA,IAA2B,OAAO,OAAO;AAAA,EACpD,OAAO;AACT,CAA6B;AAatB,SAASC,EAAyBC,GAAwD;AAC/F,QAAMC,IAAW,OAAO;AAAA,IACtB,OAAO,QAAQD,KAAU,EAAE,EAAE,OAAO,CAAC,CAAA,EAAGE,CAAK,MAAMA,MAAU,MAAS;AAAA,EAAA;AAExE,SAAO,EAAE,GAAGJ,GAA0B,GAAGG,EAAA;AAC3C;"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsxs as d, jsx as i, Fragment as u } from "react/jsx-runtime";
|
|
2
|
+
import { useId as $ } from "react";
|
|
3
|
+
import { SearchGlyph as w } from "./icons.js";
|
|
4
|
+
import { resolveCommandPaletteLabels as I } from "./labels.js";
|
|
5
|
+
import a from "./CommandPalette.module.css.js";
|
|
6
|
+
function K({
|
|
7
|
+
groups: v,
|
|
8
|
+
query: N,
|
|
9
|
+
activeResultId: n,
|
|
10
|
+
labels: f,
|
|
11
|
+
linkComponent: y
|
|
12
|
+
}) {
|
|
13
|
+
const l = I(f), g = y ?? "a", t = $(), c = `${t}-results`, m = (e) => `${t}-result-${e}`, h = (e) => `${t}-heading-${e}`, o = v.filter((e) => e.results.length > 0), r = n !== void 0 && o.some((e) => e.results.some((s) => s.id === n)) ? n : void 0;
|
|
14
|
+
return /* @__PURE__ */ d("div", { className: a.panel, children: [
|
|
15
|
+
/* @__PURE__ */ d("div", { className: a.searchRow, children: [
|
|
16
|
+
/* @__PURE__ */ i(w, { className: a.searchGlyph }),
|
|
17
|
+
/* @__PURE__ */ i(
|
|
18
|
+
"input",
|
|
19
|
+
{
|
|
20
|
+
type: "text",
|
|
21
|
+
className: a.input,
|
|
22
|
+
role: "combobox",
|
|
23
|
+
"aria-label": l.search,
|
|
24
|
+
"aria-expanded": o.length > 0,
|
|
25
|
+
"aria-controls": o.length > 0 ? c : void 0,
|
|
26
|
+
"aria-activedescendant": r === void 0 ? void 0 : m(r),
|
|
27
|
+
"aria-autocomplete": "list",
|
|
28
|
+
placeholder: l.placeholder,
|
|
29
|
+
defaultValue: N
|
|
30
|
+
}
|
|
31
|
+
),
|
|
32
|
+
/* @__PURE__ */ i("span", { className: a.dismissKey, children: l.dismissKey })
|
|
33
|
+
] }),
|
|
34
|
+
o.length > 0 ? /* @__PURE__ */ i("div", { id: c, className: a.results, role: "listbox", "aria-label": l.results, children: o.map((e) => /* @__PURE__ */ d(
|
|
35
|
+
"div",
|
|
36
|
+
{
|
|
37
|
+
className: a.group,
|
|
38
|
+
role: "group",
|
|
39
|
+
"aria-labelledby": e.heading === void 0 ? void 0 : h(e.id),
|
|
40
|
+
children: [
|
|
41
|
+
e.heading !== void 0 && /* @__PURE__ */ i("p", { id: h(e.id), className: a.groupHeading, children: e.heading }),
|
|
42
|
+
e.results.map((s) => {
|
|
43
|
+
const x = s.id === r, p = {
|
|
44
|
+
id: m(s.id),
|
|
45
|
+
className: a.row,
|
|
46
|
+
role: "option",
|
|
47
|
+
"aria-selected": x,
|
|
48
|
+
tabIndex: -1
|
|
49
|
+
}, b = /* @__PURE__ */ d(u, { children: [
|
|
50
|
+
/* @__PURE__ */ i("span", { className: a.icon, children: s.icon }),
|
|
51
|
+
/* @__PURE__ */ i("span", { className: a.label, children: s.label })
|
|
52
|
+
] });
|
|
53
|
+
return s.href === void 0 ? /* @__PURE__ */ i("button", { type: "button", ...p, children: b }, s.id) : /* @__PURE__ */ i(g, { href: s.href, ...p, children: b }, s.id);
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
e.id
|
|
58
|
+
)) }) : /* @__PURE__ */ i("p", { className: a.empty, children: l.empty }),
|
|
59
|
+
/* @__PURE__ */ i("div", { className: a.footer, children: /* @__PURE__ */ i("span", { className: a.hints, children: l.footerHints }) })
|
|
60
|
+
] });
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
K as CommandPalette
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=CommandPalette.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommandPalette.js","sources":["../../../src/components/CommandPalette/CommandPalette.tsx"],"sourcesContent":["// No \"use client\" directive, and that is a decision rather than an omission.\n//\n// Stage A holds no state, wires no handler and attaches no listener, so there is\n// nothing here a Server Component cannot render -- and tests/guards.test.ts\n// asserts the built package carries the directive on exactly the three modules\n// that need it (B33-846). Adding a fourth now would make that guard say\n// something untrue about this file. `useId` is one of the four hooks React 19's\n// react-server build exports, so the id generation below is server-safe.\n//\n// Stage B changes that: the modal variant of useAnchoredOverlay holds open\n// state, traps focus and marks the background inert, none of which survives on\n// the server. The directive and the guard's expectation move together then.\n\nimport { useId, type ElementType, type ReactNode } from 'react'\nimport { SearchGlyph } from './icons'\nimport { resolveCommandPaletteLabels, type CommandPaletteLabels } from './labels'\nimport styles from './CommandPalette.module.css'\n\n/**\n * One row in the palette. The host owns everything about it: its words, where it\n * goes, and the glyph in its leading slot.\n *\n * There is no `kind` field and there will not be one. The artboard draws three\n * kinds of row -- a page, a product, an action -- but the groups they sit in are\n * the host's and arbitrary, so a `kind` would be this package deciding what a\n * host's group *means*, which is the product meaning CLAUDE.md keeps out. A row\n * that draws a product tile draws it because the host passed\n * `icon={<ProductMark slug=\"boostscore\" />}`, not because the palette recognised\n * anything.\n */\nexport interface CommandPaletteResult {\n /**\n * Stable within one palette. It is the row's React key and, composed with the\n * palette's own `useId` base, the DOM id `aria-activedescendant` points at --\n * so two results sharing an id would leave the highlight ambiguous.\n */\n id: string\n /** The row's visible text, e.g. \"Buy tokens\". The host's, never defaulted. */\n label: string\n /**\n * Where choosing this row goes. A result with an `href` navigates and renders\n * through `linkComponent`; one without is an action and renders as a button.\n *\n * The button has no handler in Stage A. Activation -- Enter in the input, or a\n * click -- is interaction, and interaction is Stage B.\n */\n href?: string\n /**\n * The glyph in the row's 22px leading slot. Supplied by the host, because what\n * a row *is* is the host's business (see the note on this interface).\n *\n * The slot is drawn whether or not a row has one, so labels line up in a\n * single lane down the panel -- the same reason NavItem's trailing slot is\n * fixed-width (CONTEXT.md, \"Trailing slot\").\n */\n icon?: ReactNode\n}\n\n/** One titled run of results -- the artboard's Pages, Products and Actions. */\nexport interface CommandPaletteGroup {\n /** Stable within one palette; the group's React key and its heading's DOM id. */\n id: string\n /**\n * The group's uppercase label, e.g. \"Pages\". The host's words, not this\n * package's: the palette owns the grouping chrome and not the grouping.\n *\n * **Omit it and the group draws its rows with no label at all.** That is the\n * state the artboard's annotation describes -- \"before a search starts, the\n * same list shows Recent pages instead of grouped results, same shell, no\n * group labels needed\" -- expressed as the absence of a heading rather than as\n * a second mode. One prop, not a variant (CLAUDE.md, \"build-once components\").\n */\n heading?: string\n /** The rows, in the order the host wants them read. An empty group is skipped. */\n results: CommandPaletteResult[]\n}\n\nexport interface CommandPaletteProps {\n /**\n * The grouped results, in the order they should appear.\n *\n * **The palette takes these as props and owns no index.** That is the decision\n * recorded on B33-495 on 2026-10-06: Pages, Products and Actions are all the\n * host's, there is no cross-suite search index in any repo, and this component\n * must not imply one. It is scope-agnostic by construction -- four products'\n * worth of results render exactly as one product's do -- so a real index later\n * changes what is passed in and not what is here.\n */\n groups: CommandPaletteGroup[]\n /**\n * What is in the search field. Rendered as the input's initial value.\n *\n * Uncontrolled on purpose for now: a `value` with no `onChange` is a React\n * warning and a field nobody can type in, and the handler is Stage B. The\n * element and its markup do not change when the wiring arrives.\n */\n query?: string\n /**\n * The `id` of the highlighted result, if any.\n *\n * Settable from day one for the same reason `useAnchoredOverlay` takes `open`:\n * it is what lets a specimen route draw the highlighted row statically, which\n * is Stage A rather than wiring (ADR-0009). What *moves* the highlight is\n * Stage B. That the palette has a highlight at all, rather than moving DOM\n * focus between rows, is settled -- ADR-0010 puts it on the combobox pattern\n * with `aria-activedescendant`, and B33-693 is closed.\n *\n * An id matching no result is a supported state and simply draws no highlight.\n */\n activeResultId?: string\n /**\n * Every user-facing string that is not result data. Each field defaults to\n * English, and a field left out -- or supplied as `undefined`, which is what a\n * missed next-intl key looks like -- keeps its default (B33-873).\n */\n labels?: Partial<CommandPaletteLabels>\n /**\n * The element a navigating result renders through. Defaults to a plain `a`; a\n * router-owning consumer passes its own so rows route client-side with the\n * locale prefix intact (ADR-0011, B33-847).\n *\n * Consulted only for the linked form, as ADR-0011 requires: a result with no\n * `href` is an action and stays a `<button>`, and `linkComponent` is ignored\n * on it rather than rendered.\n */\n linkComponent?: ElementType\n}\n\n/**\n * The command palette: a search field over grouped results, opened from the top\n * bar's search button or `⌘K` (B33-495).\n *\n * **Stage A. Static, and not yet through its fidelity gate.** It holds no state,\n * wires no handler and registers no shortcut. It is not the modal variant yet\n * either: ADR-0009 folds this component into the one dismissal contract behind a\n * `modal` flag and it is the only one of the four anchored overlays that sets\n * it, but modality *is* interaction -- the focus trap, the `inert` background\n * and backdrop dismissal all arrive with the wiring.\n *\n * A combobox over a listbox, not a disclosure (ADR-0010): the input carries\n * `role=\"combobox\"` and names the highlighted row through\n * `aria-activedescendant`, the list is a `listbox`, each result an `option` and\n * each group a `group` with its own label. That markup is what the ADR settles;\n * what the arrow keys do inside it is Stage B's to implement.\n */\nexport function CommandPalette({\n groups,\n query,\n activeResultId,\n labels,\n linkComponent,\n}: CommandPaletteProps) {\n const t = resolveCommandPaletteLabels(labels)\n const Link: ElementType = linkComponent ?? 'a'\n\n // One base per mounted palette, so the specimen can stack several on a page\n // without two listboxes sharing an id and leaving aria-controls ambiguous.\n const base = useId()\n const listId = `${base}-results`\n const optionId = (resultId: string) => `${base}-result-${resultId}`\n const headingId = (groupId: string) => `${base}-heading-${groupId}`\n\n // A group with no rows is not drawn -- a heading over nothing is a promise the\n // panel does not keep.\n const populated = groups.filter((group) => group.results.length > 0)\n\n // The highlight is only announced if it names a row that is actually on\n // screen. An `aria-activedescendant` pointing at a missing id is worse than\n // none: it tells a screen reader there is a selection and then gives it\n // nothing to read.\n const highlighted =\n activeResultId !== undefined &&\n populated.some((group) => group.results.some((result) => result.id === activeResultId))\n ? activeResultId\n : undefined\n\n return (\n <div className={styles.panel}>\n <div className={styles.searchRow}>\n <SearchGlyph className={styles.searchGlyph} />\n <input\n type=\"text\"\n className={styles.input}\n // ADR-0010. The input is the combobox; the list it controls is the\n // popup. `aria-expanded` describes that popup and nothing else, which\n // is why it is false when there is no list to point at -- the panel\n // being on screen is a separate fact, and in Stage B it is the dialog\n // that carries it.\n role=\"combobox\"\n aria-label={t.search}\n aria-expanded={populated.length > 0}\n aria-controls={populated.length > 0 ? listId : undefined}\n aria-activedescendant={highlighted === undefined ? undefined : optionId(highlighted)}\n aria-autocomplete=\"list\"\n placeholder={t.placeholder}\n defaultValue={query}\n />\n <span className={styles.dismissKey}>{t.dismissKey}</span>\n </div>\n\n {populated.length > 0 ? (\n <div id={listId} className={styles.results} role=\"listbox\" aria-label={t.results}>\n {populated.map((group) => (\n <div\n key={group.id}\n className={styles.group}\n role=\"group\"\n aria-labelledby={group.heading === undefined ? undefined : headingId(group.id)}\n >\n {group.heading !== undefined && (\n <p id={headingId(group.id)} className={styles.groupHeading}>\n {group.heading}\n </p>\n )}\n {group.results.map((result) => {\n const selected = result.id === highlighted\n // Children of an `option` are presentational in ARIA, so a\n // focusable descendant is a conflict rather than a convenience:\n // the row's own text is what gets announced either way. Taking\n // the row out of the tab sequence is what the role already\n // implies, not an anticipation of traversal -- focus stays in\n // the input under ADR-0010's combobox model.\n const rowProps = {\n id: optionId(result.id),\n className: styles.row,\n role: 'option',\n 'aria-selected': selected,\n tabIndex: -1,\n }\n const body = (\n <>\n <span className={styles.icon}>{result.icon}</span>\n <span className={styles.label}>{result.label}</span>\n </>\n )\n return result.href === undefined ? (\n <button key={result.id} type=\"button\" {...rowProps}>\n {body}\n </button>\n ) : (\n <Link key={result.id} href={result.href} {...rowProps}>\n {body}\n </Link>\n )\n })}\n </div>\n ))}\n </div>\n ) : (\n <p className={styles.empty}>{t.empty}</p>\n )}\n\n <div className={styles.footer}>\n <span className={styles.hints}>{t.footerHints}</span>\n </div>\n </div>\n )\n}\n"],"names":["CommandPalette","groups","query","activeResultId","labels","linkComponent","t","resolveCommandPaletteLabels","Link","base","useId","listId","optionId","resultId","headingId","groupId","populated","group","highlighted","result","jsxs","styles","jsx","SearchGlyph","selected","rowProps","body","Fragment"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const s = "_panel_1hdli_22", _ = "_searchRow_1hdli_38", o = "_searchGlyph_1hdli_49", t = "_input_1hdli_63", i = "_dismissKey_1hdli_94", l = "_results_1hdli_109", e = "_group_1hdli_115", n = "_groupHeading_1hdli_127", h = "_row_1hdli_146", c = "_icon_1hdli_184", r = "_label_1hdli_197", d = "_empty_1hdli_209", p = "_footer_1hdli_217", a = "_hints_1hdli_227", u = {
|
|
2
|
+
panel: s,
|
|
3
|
+
searchRow: _,
|
|
4
|
+
searchGlyph: o,
|
|
5
|
+
input: t,
|
|
6
|
+
dismissKey: i,
|
|
7
|
+
results: l,
|
|
8
|
+
group: e,
|
|
9
|
+
groupHeading: n,
|
|
10
|
+
row: h,
|
|
11
|
+
icon: c,
|
|
12
|
+
label: r,
|
|
13
|
+
empty: d,
|
|
14
|
+
footer: p,
|
|
15
|
+
hints: a
|
|
16
|
+
};
|
|
17
|
+
export {
|
|
18
|
+
u as default,
|
|
19
|
+
i as dismissKey,
|
|
20
|
+
d as empty,
|
|
21
|
+
p as footer,
|
|
22
|
+
e as group,
|
|
23
|
+
n as groupHeading,
|
|
24
|
+
a as hints,
|
|
25
|
+
c as icon,
|
|
26
|
+
t as input,
|
|
27
|
+
r as label,
|
|
28
|
+
s as panel,
|
|
29
|
+
l as results,
|
|
30
|
+
h as row,
|
|
31
|
+
o as searchGlyph,
|
|
32
|
+
_ as searchRow
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=CommandPalette.module.css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommandPalette.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsxs as o, jsx as r } from "react/jsx-runtime";
|
|
2
|
+
function i({ className: e }) {
|
|
3
|
+
return /* @__PURE__ */ o(
|
|
4
|
+
"svg",
|
|
5
|
+
{
|
|
6
|
+
className: e,
|
|
7
|
+
viewBox: "0 0 16 16",
|
|
8
|
+
fill: "none",
|
|
9
|
+
stroke: "currentColor",
|
|
10
|
+
strokeWidth: "1.5",
|
|
11
|
+
strokeLinecap: "round",
|
|
12
|
+
"aria-hidden": "true",
|
|
13
|
+
children: [
|
|
14
|
+
/* @__PURE__ */ r("circle", { cx: "7", cy: "7", r: "5" }),
|
|
15
|
+
/* @__PURE__ */ r("path", { d: "M10.8 10.8L14 14" })
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
i as SearchGlyph
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.js","sources":["../../../src/components/CommandPalette/icons.tsx"],"sourcesContent":["// The palette's own chrome glyph, drawn in `currentColor` so the surrounding\n// text colour carries it and the no-hardcoded-hex guard stays satisfied -- the\n// same idiom as AppSwitcher/icons.tsx. Decorative, so it is aria-hidden: the\n// input beside it carries the accessible name.\n//\n// There is exactly one glyph here, and the artboard draws three. The other two\n// -- a page glyph on every Pages row and a plus-in-circle on every Actions row\n// -- are NOT in this file, because a result's icon is the host's (`icon` on\n// `CommandPaletteResult`). Whether those two should instead be chrome this\n// package ships is a real question and it is the person at the fidelity gate's,\n// not an agent's: the groups are host-supplied and arbitrary, so nothing here\n// can map \"this is a page\" to a glyph without the package learning what the\n// host's groups mean. See B33-495.\n\n/**\n * The magnifier at the head of the search row. 16px, a 5px-radius lens with a\n * handle -- read off the SearchRow's own SVG on the artboard rather than lifted\n * from an icon set, so it matches the field it sits in.\n */\nexport function SearchGlyph({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n aria-hidden=\"true\"\n >\n <circle cx=\"7\" cy=\"7\" r=\"5\" />\n <path d=\"M10.8 10.8L14 14\" />\n </svg>\n )\n}\n"],"names":["SearchGlyph","className","jsxs","jsx"],"mappings":";AAmBO,SAASA,EAAY,EAAE,WAAAC,KAAqC;AACjE,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAAD;AAAA,MACA,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,eAAY;AAAA,MAEZ,UAAA;AAAA,QAAA,gBAAAE,EAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI;AAAA,QAC5B,gBAAAA,EAAC,QAAA,EAAK,GAAE,mBAAA,CAAmB;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGjC;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const r = Object.freeze({
|
|
2
|
+
search: "Search",
|
|
3
|
+
placeholder: "Search pages, products and actions",
|
|
4
|
+
dismissKey: "esc",
|
|
5
|
+
results: "Results",
|
|
6
|
+
empty: "No results",
|
|
7
|
+
footerHints: "↑↓ Navigate ↵ Select esc Close"
|
|
8
|
+
});
|
|
9
|
+
function a(e) {
|
|
10
|
+
const t = Object.fromEntries(
|
|
11
|
+
Object.entries(e ?? {}).filter(([, s]) => s !== void 0)
|
|
12
|
+
);
|
|
13
|
+
return { ...r, ...t };
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
r as defaultCommandPaletteLabels,
|
|
17
|
+
a as resolveCommandPaletteLabels
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","sources":["../../../src/components/CommandPalette/labels.ts"],"sourcesContent":["// The palette's own user-facing words, each a prop with an English default.\n//\n// This follows `WalletChipLabels` exactly, and unlike `AppSwitcherLabels`'s\n// opening comment that claim is meant literally: `labels` is a `Partial`, a\n// `resolve*` step filters `undefined` before merging, and the defaults object is\n// frozen with `satisfies` and no type annotation. B33-1007 records those as the\n// three ways the switcher's contract diverged from the chip's while asserting it\n// did not; two of them have since been corrected there and the freeze has not.\n// This module copies the chip's spelling verbatim rather than inventing a fourth\n// dialect -- see the PR for B33-495.\n//\n// No label here carries a value either, so this module names no placeholder. The\n// one a future field would use is `%name%` and not `{name}`: a brace is ICU\n// MessageFormat argument syntax, and a consumer keeps these strings in an ICU\n// catalogue (B33-1277; the reasoning is in `src/fill-template.ts`).\n//\n// What is NOT here: the group headings, and each result's label. Those are the\n// host's data, supplied per row on `groups`, not copy this package owns. The\n// palette takes grouped results as props and owns no index (B33-495, decided\n// 2026-10-06), so the only strings it is entitled to default are its own chrome.\n\n/** Every user-facing string the palette renders that is not result data. */\nexport interface CommandPaletteLabels {\n /**\n * The search input's accessible name. The artboard draws no visible label --\n * the magnifier beside the field is decorative -- so this is the only thing\n * naming the only control in the panel. Default \"Search\".\n */\n search: string\n /**\n * The search input's placeholder, shown before anything is typed. Default\n * \"Search pages, products and actions\".\n *\n * Deliberately not \"search everything\" or \"search the suite\". The palette\n * renders whatever groups the host passes, and today that is one product's\n * results rather than four (B33-495, the 2026-10-06 decision). A placeholder\n * promising a cross-suite index would be the component claiming a scope it\n * does not have.\n */\n placeholder: string\n /**\n * The key badge at the right of the search row, which the artboard draws\n * reading \"esc\". Default \"esc\".\n *\n * A label rather than a literal because it is a word on screen, and locales do\n * not all legend that key the same way -- a French keyboard reads \"échap\".\n * What it does is Stage B's; this is only what it says.\n */\n dismissKey: string\n /**\n * The results list's accessible name. The list is a `listbox` (ADR-0010) and\n * takes a name like any other widget. Default \"Results\".\n */\n results: string\n /**\n * The line shown in place of the list when no group holds a result. Default\n * \"No results\".\n *\n * **The artboard does not draw this state**, which is worth saying plainly.\n * Its empty-state annotation describes the *pre-search* case -- \"before a\n * search starts, the same list shows Recent pages instead of grouped results\"\n * -- and that case is already expressible without new copy: the host passes one\n * group with no heading. A list that genuinely matches nothing is a different\n * state, it is reachable the moment anyone types, and a panel that answers it\n * with blank space is not finished. So this exists, and the person at the\n * fidelity gate owns whether the words and the treatment are right.\n */\n empty: string\n /**\n * The footer's keyboard legend, supplied whole. Default\n * \"↑↓ Navigate ↵ Select esc Close\".\n *\n * One field rather than six (three key glyphs and three verbs) for the reason\n * `WalletChipLabels` gives for its templates: word order is not a property of\n * English, and a legend reassembled from fragments on the consumer's side\n * cannot be translated. A locale is entitled to put the glyph after the verb,\n * to separate the pairs differently, or to drop a hint it has no key for. The\n * artboard draws it as a single text run, so one string is also what it is.\n */\n footerHints: string\n}\n\n/**\n * The English defaults.\n *\n * Frozen, and with no type annotation. `const` protects the binding and not the\n * contents, and this is a public export reaching four products on a version\n * bump: without the freeze a consumer aliasing it -- `const mine =\n * defaultCommandPaletteLabels; mine.empty = 'Aucun résultat'` -- renames every\n * palette in the process (B33-877). The annotation is left off on purpose too:\n * `: CommandPaletteLabels` on a frozen object widens `Readonly` back to mutable\n * in the emitted `.d.ts`, so `satisfies` carries the checking instead (B33-916,\n * and B33-1007 asking that the two exports not drift again).\n */\nexport const defaultCommandPaletteLabels = Object.freeze({\n search: 'Search',\n placeholder: 'Search pages, products and actions',\n dismissKey: 'esc',\n results: 'Results',\n empty: 'No results',\n footerHints: '↑↓ Navigate ↵ Select esc Close',\n} satisfies CommandPaletteLabels)\n\n/**\n * Merge a consumer's partial `labels` onto the English defaults, treating an\n * explicitly-`undefined` field as unsupplied.\n *\n * The same resolution `resolveWalletChipLabels` performs, for the same two\n * reasons. A `Partial` means a consumer translates the fields it cares about and\n * inherits the rest, today and at the next field added -- so a new label is not\n * a breaking change across four products on a patch bump. And a next-intl\n * `t('...')` returns `undefined` on a missed key, so `{ search: undefined }` is\n * what one missing translation looks like at the call site: a plain spread\n * copies that `undefined` across and leaves the palette's only control with no\n * accessible name at all, which is B33-873 exactly. A per-field skip does not.\n */\nexport function resolveCommandPaletteLabels(\n labels?: Partial<CommandPaletteLabels>,\n): CommandPaletteLabels {\n const supplied = Object.fromEntries(\n Object.entries(labels ?? {}).filter(([, value]) => value !== undefined),\n ) as Partial<CommandPaletteLabels>\n return { ...defaultCommandPaletteLabels, ...supplied }\n}\n"],"names":["defaultCommandPaletteLabels","resolveCommandPaletteLabels","labels","supplied","value"],"mappings":"AA8FO,MAAMA,IAA8B,OAAO,OAAO;AAAA,EACvD,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,OAAO;AAAA,EACP,aAAa;AACf,CAAgC;AAezB,SAASC,EACdC,GACsB;AACtB,QAAMC,IAAW,OAAO;AAAA,IACtB,OAAO,QAAQD,KAAU,EAAE,EAAE,OAAO,CAAC,CAAA,EAAGE,CAAK,MAAMA,MAAU,MAAS;AAAA,EAAA;AAExE,SAAO,EAAE,GAAGJ,GAA6B,GAAGG,EAAA;AAC9C;"}
|
|
@@ -12,8 +12,12 @@ export interface LaunchLoaderProps {
|
|
|
12
12
|
* package's -- the same reason WalletChip's labels take whole templates.
|
|
13
13
|
*/
|
|
14
14
|
caption: string;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @deprecated Ignored since 0.5.1 (B33-1401). Every product's launch screen
|
|
17
|
+
* is the same Boost33 background, built in. Optional and still typed only so
|
|
18
|
+
* a consumer on `^0.5.0` that passes it keeps compiling; stop passing it.
|
|
19
|
+
*/
|
|
20
|
+
stops?: LaunchGradientStops;
|
|
17
21
|
/**
|
|
18
22
|
* 0-100, or `null`/omitted while the page has no honest number. Indeterminate
|
|
19
23
|
* omits `aria-valuenow` entirely: passing 0 to mean "unknown" announces 0%.
|
|
@@ -32,7 +36,7 @@ export interface LaunchLoaderProps {
|
|
|
32
36
|
*/
|
|
33
37
|
busy?: boolean;
|
|
34
38
|
/**
|
|
35
|
-
* An optional layer painted over the
|
|
39
|
+
* An optional layer painted over the glow and under the content --
|
|
36
40
|
* where an animated backdrop goes. Never required: the screen is complete
|
|
37
41
|
* without it, and dropped entirely under `prefers-contrast`.
|
|
38
42
|
*/
|
|
@@ -47,4 +51,4 @@ export interface LaunchLoaderProps {
|
|
|
47
51
|
* No "use client" and no client-only hook: useId is in React's server build, so
|
|
48
52
|
* this renders -- and its dots animate -- straight from server HTML.
|
|
49
53
|
*/
|
|
50
|
-
export declare function LaunchLoader({ caption,
|
|
54
|
+
export declare function LaunchLoader({ caption, progress, dotColor, busy, backdrop, className, }: LaunchLoaderProps): import("react").JSX.Element;
|
|
@@ -1,70 +1,57 @@
|
|
|
1
1
|
import { jsxs as t, jsx as e } from "react/jsx-runtime";
|
|
2
2
|
import { useId as m } from "react";
|
|
3
|
-
import { DotMatrixLoader as
|
|
4
|
-
import { launchRamp as f, launchSolid as x, launchGround as M, LAUNCH_MESH as S, launchShapeStyle as L } from "../../launch-gradient.js";
|
|
3
|
+
import { DotMatrixLoader as h } from "../DotMatrixLoader/DotMatrixLoader.js";
|
|
5
4
|
import a from "./LaunchLoader.module.css.js";
|
|
6
|
-
function
|
|
7
|
-
return Math.min(100, Math.max(0,
|
|
5
|
+
function p(l) {
|
|
6
|
+
return Math.min(100, Math.max(0, l));
|
|
8
7
|
}
|
|
9
|
-
function
|
|
10
|
-
caption:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
busy: h = !0,
|
|
8
|
+
function M({
|
|
9
|
+
caption: l,
|
|
10
|
+
progress: r = null,
|
|
11
|
+
dotColor: n,
|
|
12
|
+
busy: u = !0,
|
|
15
13
|
backdrop: o,
|
|
16
|
-
className:
|
|
14
|
+
className: s
|
|
17
15
|
}) {
|
|
18
|
-
const
|
|
19
|
-
"--launch-ground": M(i),
|
|
20
|
-
"--launch-solid": x(i),
|
|
21
|
-
...c ? { "--launch-accent-input": c } : {}
|
|
22
|
-
};
|
|
16
|
+
const d = m(), c = m(), i = typeof r == "number" && Number.isFinite(r) ? Math.round(p(r)) : null, v = n ? { "--launch-accent-input": n } : void 0;
|
|
23
17
|
return /* @__PURE__ */ t(
|
|
24
18
|
"div",
|
|
25
19
|
{
|
|
26
|
-
className:
|
|
20
|
+
className: s ? `${a.root} ${s}` : a.root,
|
|
27
21
|
style: v,
|
|
28
|
-
"aria-busy":
|
|
29
|
-
"aria-describedby":
|
|
22
|
+
"aria-busy": u,
|
|
23
|
+
"aria-describedby": d,
|
|
30
24
|
"data-launch-loader": "",
|
|
31
25
|
children: [
|
|
32
|
-
/* @__PURE__ */ e("div", { className: a.
|
|
33
|
-
"div",
|
|
34
|
-
{
|
|
35
|
-
className: a.shape,
|
|
36
|
-
style: L(b, p)
|
|
37
|
-
},
|
|
38
|
-
N
|
|
39
|
-
)) }),
|
|
26
|
+
/* @__PURE__ */ e("div", { className: a.glow, "aria-hidden": "true" }),
|
|
40
27
|
o ? /* @__PURE__ */ e("div", { className: a.backdrop, children: o }) : null,
|
|
41
28
|
/* @__PURE__ */ t("div", { className: a.content, children: [
|
|
42
|
-
/* @__PURE__ */ e(
|
|
29
|
+
/* @__PURE__ */ e(h, { label: null, className: a.dots }),
|
|
43
30
|
/* @__PURE__ */ t(
|
|
44
31
|
"div",
|
|
45
32
|
{
|
|
46
|
-
id:
|
|
33
|
+
id: d,
|
|
47
34
|
className: a.bar,
|
|
48
35
|
role: "progressbar",
|
|
49
|
-
"aria-labelledby":
|
|
36
|
+
"aria-labelledby": c,
|
|
50
37
|
"aria-valuemin": 0,
|
|
51
38
|
"aria-valuemax": 100,
|
|
52
|
-
"aria-valuenow":
|
|
53
|
-
"data-indeterminate":
|
|
54
|
-
style:
|
|
39
|
+
"aria-valuenow": i ?? void 0,
|
|
40
|
+
"data-indeterminate": i === null,
|
|
41
|
+
style: i === null ? void 0 : { "--launch-progress": i },
|
|
55
42
|
children: [
|
|
56
43
|
/* @__PURE__ */ e("div", { className: a.track }),
|
|
57
44
|
/* @__PURE__ */ e("div", { className: a.fill })
|
|
58
45
|
]
|
|
59
46
|
}
|
|
60
47
|
),
|
|
61
|
-
/* @__PURE__ */ e("p", { id:
|
|
48
|
+
/* @__PURE__ */ e("p", { id: c, className: a.caption, "aria-live": "polite", children: l })
|
|
62
49
|
] })
|
|
63
50
|
]
|
|
64
51
|
}
|
|
65
52
|
);
|
|
66
53
|
}
|
|
67
54
|
export {
|
|
68
|
-
|
|
55
|
+
M as LaunchLoader
|
|
69
56
|
};
|
|
70
57
|
//# sourceMappingURL=LaunchLoader.js.map
|