@boost33/ui 0.5.1 → 0.7.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 +2973 -0
- 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/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/ProductMark/ProductMark.d.ts +66 -76
- package/dist/components/ProductMark/ProductMark.js +218 -64
- package/dist/components/ProductMark/ProductMark.js.map +1 -1
- 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 +17 -0
- package/dist/index.js +45 -29
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -2
|
@@ -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;"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { jsxs as r, jsx as a, Fragment as u } from "react/jsx-runtime";
|
|
2
|
+
import { useId as f } from "react";
|
|
3
|
+
import { ProductMark as b } from "../ProductMark/ProductMark.js";
|
|
4
|
+
import { EmptyBell as v, SourceBellMark as T } from "./icons.js";
|
|
5
|
+
import { resolveNotificationCenterLabels as g } from "./labels.js";
|
|
6
|
+
import e from "./NotificationCenter.module.css.js";
|
|
7
|
+
const h = 22;
|
|
8
|
+
function C({
|
|
9
|
+
items: n,
|
|
10
|
+
viewAllHref: t,
|
|
11
|
+
labels: p,
|
|
12
|
+
linkComponent: N
|
|
13
|
+
}) {
|
|
14
|
+
const s = g(p), c = N ?? "a", d = f(), i = n.filter((l) => l.unread === !0).length, o = n.length === 0;
|
|
15
|
+
return (
|
|
16
|
+
// Named by the heading it already draws rather than by a second copy of the
|
|
17
|
+
// same word in an aria-label (ADR-0010; see `title` in labels.ts).
|
|
18
|
+
/* @__PURE__ */ r("div", { className: e.panel, "aria-labelledby": d, children: [
|
|
19
|
+
/* @__PURE__ */ r("div", { className: e.header, children: [
|
|
20
|
+
/* @__PURE__ */ a("h2", { className: e.title, id: d, children: s.title }),
|
|
21
|
+
!o && /* @__PURE__ */ a("button", { type: "button", className: e.markAll, children: s.markAllAsRead })
|
|
22
|
+
] }),
|
|
23
|
+
o ? /* @__PURE__ */ r("div", { className: e.empty, children: [
|
|
24
|
+
/* @__PURE__ */ a(v, {}),
|
|
25
|
+
/* @__PURE__ */ r("div", { className: e.emptyText, children: [
|
|
26
|
+
/* @__PURE__ */ a("p", { className: e.emptyTitle, children: s.emptyTitle }),
|
|
27
|
+
/* @__PURE__ */ a("p", { className: e.emptyBody, children: s.emptyBody })
|
|
28
|
+
] })
|
|
29
|
+
] }) : /* @__PURE__ */ r(u, { children: [
|
|
30
|
+
/* @__PURE__ */ r("div", { className: e.tabs, children: [
|
|
31
|
+
/* @__PURE__ */ a("button", { type: "button", className: e.tab, "aria-pressed": "true", children: s.all }),
|
|
32
|
+
/* @__PURE__ */ r("button", { type: "button", className: e.tab, "aria-pressed": "false", children: [
|
|
33
|
+
s.unread,
|
|
34
|
+
i > 0 && /* @__PURE__ */ a("span", { className: e.count, children: i })
|
|
35
|
+
] })
|
|
36
|
+
] }),
|
|
37
|
+
/* @__PURE__ */ a("ul", { className: e.list, children: n.map((l) => {
|
|
38
|
+
const m = l.unread === !0, y = l.href != null ? c : "div";
|
|
39
|
+
return /* @__PURE__ */ a("li", { children: /* @__PURE__ */ r(
|
|
40
|
+
y,
|
|
41
|
+
{
|
|
42
|
+
className: e.row,
|
|
43
|
+
href: l.href,
|
|
44
|
+
"data-unread": m ? "true" : void 0,
|
|
45
|
+
children: [
|
|
46
|
+
l.slug != null ? /* @__PURE__ */ a(b, { slug: l.slug, size: h, className: e.sourceMark }) : /* @__PURE__ */ a(T, { size: h }),
|
|
47
|
+
/* @__PURE__ */ r("span", { className: e.rowText, children: [
|
|
48
|
+
/* @__PURE__ */ a("span", { className: e.rowTitle, children: l.title }),
|
|
49
|
+
/* @__PURE__ */ a("span", { className: e.rowMeta, children: l.dateTime != null ? /* @__PURE__ */ a("time", { dateTime: l.dateTime, children: s.meta(l.source, l.time) }) : s.meta(l.source, l.time) })
|
|
50
|
+
] }),
|
|
51
|
+
/* @__PURE__ */ a("span", { className: e.unreadSlot, children: m && /* @__PURE__ */ r(u, { children: [
|
|
52
|
+
/* @__PURE__ */ a("span", { className: e.dot }),
|
|
53
|
+
/* @__PURE__ */ a("span", { className: e.srOnly, children: s.unreadItem })
|
|
54
|
+
] }) })
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
) }, l.id);
|
|
58
|
+
}) }),
|
|
59
|
+
t != null && /* @__PURE__ */ a("div", { className: e.footer, children: /* @__PURE__ */ a(c, { className: e.viewAll, href: t, children: s.viewAll }) })
|
|
60
|
+
] })
|
|
61
|
+
] })
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
C as NotificationCenter
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=NotificationCenter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationCenter.js","sources":["../../../src/components/NotificationCenter/NotificationCenter.tsx"],"sourcesContent":["// Not a client module, and that is a statement about this stage rather than\n// about the component. Stage A holds no state, wires no handler and reads no\n// clock, so there is nothing here a Server Component cannot carry. Stage B adds\n// `useAnchoredOverlay` and the directive with it -- see the note on the panel\n// below, and tests/guards.test.ts, which pins the exact set of built modules\n// carrying \"use client\" so the directive cannot appear here unnoticed.\n\nimport { useId, type ElementType } from 'react'\nimport { ProductMark } from '../ProductMark/ProductMark'\nimport { EmptyBell, SourceBellMark } from './icons'\nimport { resolveNotificationCenterLabels, type NotificationCenterLabels } from './labels'\nimport styles from './NotificationCenter.module.css'\n\n/**\n * The size the source mark renders at, in px.\n *\n * 22, which is `--spacing-5_5` written as a number because `ProductMark.size` is\n * a React prop and cannot read a custom property. ProductMark's own default is\n * 20 and the AppSwitcher's rows deliberately take it -- that is the Wallet's\n * size at the Wallet's call sites, settled against three approved baselines, and\n * its comment warns against passing a size at all. This is the other case the\n * comment contemplates and not a contradiction of it: there is no Wallet\n * rendering of this panel and no approved baseline to move, so 22 is the drawing\n * on page 004 reproduced rather than a settled measurement overruled. The person\n * at the fidelity gate settles it (CLAUDE.md, \"The three components the Wallet\n * never rendered\"), and until then nothing here is authoritative.\n */\nconst SOURCE_MARK_PX = 22\n\n/**\n * One notification, as the host supplies it. **This package invents no backend\n * and fetches nothing** -- the array is the host's, and so is every value in a\n * row (B33-494's data decision, 2026-10-06; CLAUDE.md, \"it renders what it is\n * given\").\n *\n * The shape is deliberately generic. Nothing in it names a lead, a campaign or a\n * prospect, and nothing in it should: a field that carried product meaning is\n * how a shared component turns back into four private ones (CLAUDE.md). A\n * notification here is a title, where it came from, when, whether it has been\n * read, and optionally somewhere to go.\n */\nexport interface NotificationCenterItem {\n /** Stable identity for the row, the host's. Used as the React key, never rendered. */\n id: string\n /** What happened, in the host's words. The row's first line. */\n title: string\n /**\n * Where it came from, in the host's words -- a product's display name, or\n * something that is not a product at all (\"Account\"). The first half of the\n * row's second line.\n *\n * A display string and not an identifier: `slug` below is what selects the\n * artwork, and the two are separate for the same reason `AppSwitcherProduct`\n * keeps `slug` and `name` apart. Identity owns names, and this package does\n * not translate them.\n */\n source: string\n /**\n * When it happened, **already formatted by the host** -- \"12 minutes ago\",\n * \"Yesterday\", \"3 Oct\". The second half of the row's second line.\n *\n * **This package does not format it, and the choice is deliberate.** The chip\n * formats its figures from a `locale` prop (B33-876), so the obvious move is\n * to do the same here and take a `Date`. Three things separate the two.\n *\n * A number is a pure function of its value and a locale; a *relative* time is\n * not. It needs a `now`, so the component would have to read a clock, and then\n * re-read it on a timer or go stale on screen -- which is state, in a\n * component whose whole contract is that it has none.\n *\n * It would also make this component's own fidelity gate unreproducible. The\n * baseline for an unbuilt component is captured from the specimen route by the\n * person approving it (CLAUDE.md, tests/baselines/README.md \"Designed\n * baselines\"), and a panel that renders \"12 minutes ago\" from `Date.now()`\n * renders a different string an hour later, so the diff would fail for reasons\n * no change caused. `4,600` is `4,600` forever; \"12 minutes ago\" is not.\n *\n * And the hard part is editorial rather than linguistic. Where a product cuts\n * over from \"12 minutes ago\" to \"Yesterday\" to a date is a policy each product\n * is entitled to differ on, and `Intl.RelativeTimeFormat` does not decide it\n * -- a caller has to pick the value and the unit before it can be called. The\n * host already holds the raw timestamp under B33-494's decision; it is the\n * side that can answer.\n *\n * `dateTime` below is how the machine-readable value still reaches the page.\n */\n time: string\n /**\n * The machine-readable timestamp for the `<time>` element's `datetime`\n * attribute -- an ISO 8601 string. Optional: supply it and the row's time is a\n * `<time dateTime>`; omit it and the same text renders in a plain `<span>`.\n *\n * This is what `time` being preformatted costs and how the cost is paid back.\n * A relative phrase on its own tells assistive technology and anything else\n * reading the DOM nothing about *when*; the attribute carries the instant\n * without this package deciding how to say it.\n */\n dateTime?: string\n /**\n * Identity's product slug, selecting the ProductMark artwork for the row's\n * tile. Optional, because a notification need not come from a product -- an\n * account or security event does not, and the drawing's own fifth row is one.\n * Omit it and the row draws the panel's bell instead (see `SourceBellMark`).\n *\n * A slug this package has no artwork for degrades to the bare tile rather than\n * throwing, exactly as it does in the switcher (ADR-0003).\n */\n slug?: string\n /**\n * Where selecting this notification goes. Optional: a row with no `href` is\n * not a link and is drawn as plain content, which is the honest rendering for\n * something there is nothing to open for.\n *\n * A row that does navigate renders through `linkComponent` (ADR-0011).\n */\n href?: string\n /**\n * Whether this notification is still unread. Defaults to `false`.\n *\n * **The flag is spelled `unread` and defaults to not-lit on purpose**, which\n * is the same decision the TopBar's bell already carries and for the same\n * reason B33-494 records: a permanently lit marker on a panel nobody has\n * cleared trains people to ignore it, and that attention does not come back.\n * A host that does not track read state passes nothing and gets a quiet panel;\n * a host that does says so row by row.\n */\n unread?: boolean\n}\n\nexport interface NotificationCenterProps {\n /**\n * The notifications, in the order the host wants them read. Rendered whole --\n * this component does not sort, filter, page or truncate, because every one of\n * those is a decision about data it does not own.\n *\n * An empty array is not an error state. It is the empty rendering, and it is\n * the state most consumers see first: a host with no feed wired yet has\n * nothing to pass (B33-494).\n */\n items: NotificationCenterItem[]\n /**\n * Where the footer's \"View all notifications\" link goes. Omit it and the\n * footer is not rendered -- a link to a page the host does not have is worse\n * than no link.\n *\n * The empty rendering never draws the footer, whether this is supplied or not:\n * there is nothing to see more of.\n */\n viewAllHref?: string\n /**\n * Every user-facing string that is not row 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<NotificationCenterLabels>\n /**\n * The element a row with an `href` renders through, and the footer link with\n * it. Defaults to a plain `a`; a router-owning consumer passes its own so the\n * rows route client-side with the locale prefix intact (ADR-0011, B33-847).\n */\n linkComponent?: ElementType\n}\n\n/**\n * The panel behind the top bar's bell: everything the four products did, in one\n * list, with the unread ones marked (B33-494).\n *\n * **It is presentational and it owns no feed.** The notifications arrive as a\n * prop and this package neither fetches, stores nor subscribes to anything --\n * there is no cross-product event source in any repo, and a component that\n * implied one would make the shared shell the place four services integrate,\n * which is the opposite of the dependency direction every other component here\n * has. That was decided on the ticket on 2026-10-06; the feed is separate work,\n * outside 1.0.\n *\n * **This is Stage A: static.** The panel renders, the tabs and the header action\n * draw, and nothing responds to anything (CLAUDE.md, \"Presentational-first\").\n * There is no open state here because there is no trigger here either: the bell\n * is the TopBar's, and connecting the two -- `useAnchoredOverlay` for the shared\n * dismissal contract (ADR-0009), the bell's `aria-haspopup`/`aria-expanded`, the\n * filter the tabs select, the mark-all handler -- is Stage B, after a human has\n * approved what this draws.\n *\n * **A disclosure, not a menu** (ADR-0010): the panel carries no widget role, the\n * tabs are not an ARIA `tablist`, the rows are the real links they already are,\n * and Tab is the document's own order, so the header button, both filters, every\n * row and the footer link are each their own tab stop. An ARIA tab set or a\n * `menu` would promise a composite widget with one tab stop and arrow-key\n * traversal, which is the promise ADR-0010 took the switcher out of.\n */\nexport function NotificationCenter({\n items,\n viewAllHref,\n labels,\n linkComponent,\n}: NotificationCenterProps) {\n const t = resolveNotificationCenterLabels(labels)\n const Link: ElementType = linkComponent ?? 'a'\n const headingId = useId()\n const unreadCount = items.filter((item) => item.unread === true).length\n const isEmpty = items.length === 0\n\n return (\n // Named by the heading it already draws rather than by a second copy of the\n // same word in an aria-label (ADR-0010; see `title` in labels.ts).\n <div className={styles.panel} aria-labelledby={headingId}>\n <div className={styles.header}>\n <h2 className={styles.title} id={headingId}>\n {t.title}\n </h2>\n {/* Nothing to mark, and nothing to mark it on: the empty rendering drops\n the action rather than offering a control that would do nothing even\n once it is wired. */}\n {!isEmpty && (\n <button type=\"button\" className={styles.markAll}>\n {t.markAllAsRead}\n </button>\n )}\n </div>\n\n {isEmpty ? (\n <div className={styles.empty}>\n <EmptyBell />\n <div className={styles.emptyText}>\n <p className={styles.emptyTitle}>{t.emptyTitle}</p>\n <p className={styles.emptyBody}>{t.emptyBody}</p>\n </div>\n </div>\n ) : (\n <>\n {/* Two toggle buttons, not a `role=\"tablist\"`. The ARIA tabs pattern\n requires one tab stop for the set and arrow keys to move between\n them, which contradicts ADR-0010's \"Tab is the document's tab\n order, unchanged and unmanaged\" -- and the APG's own banner, \"No\n ARIA is better than Bad ARIA\". `aria-pressed` says which filter is\n on without claiming a composite widget.\n\n Both are pressed-state-only in Stage A: \"All\" is on because the\n list under it is every row. Which filter is selected becomes state\n when the filtering is wired, and the markup does not change when it\n does. */}\n <div className={styles.tabs}>\n <button type=\"button\" className={styles.tab} aria-pressed=\"true\">\n {t.all}\n </button>\n <button type=\"button\" className={styles.tab} aria-pressed=\"false\">\n {t.unread}\n {/* Counted off `items`, never passed in, so it cannot disagree\n with the list beneath it. Drawn only when there is something to\n count -- a \"0\" pill is a decoration that reads as a state. */}\n {unreadCount > 0 && <span className={styles.count}>{unreadCount}</span>}\n </button>\n </div>\n\n <ul className={styles.list}>\n {items.map((item) => {\n const unread = item.unread === true\n // A row that navigates is a link; a row with nowhere to go is not\n // dressed as one. `linkComponent` is only consulted for the linked\n // form, exactly as ADR-0011 has NavItem consult it.\n const Row: ElementType = item.href != null ? Link : 'div'\n\n return (\n <li key={item.id}>\n <Row\n className={styles.row}\n href={item.href}\n data-unread={unread ? 'true' : undefined}\n >\n {item.slug != null ? (\n <ProductMark slug={item.slug} size={SOURCE_MARK_PX} className={styles.sourceMark} />\n ) : (\n <SourceBellMark size={SOURCE_MARK_PX} />\n )}\n <span className={styles.rowText}>\n <span className={styles.rowTitle}>{item.title}</span>\n <span className={styles.rowMeta}>\n {/* The whole second line through one label, so a locale\n owns both the word order and the separator. The\n machine-readable instant rides on the <time> element\n when the host supplies one; the text is the host's\n either way. */}\n {item.dateTime != null ? (\n <time dateTime={item.dateTime}>{t.meta(item.source, item.time)}</time>\n ) : (\n t.meta(item.source, item.time)\n )}\n </span>\n </span>\n {/* A fixed lane, drawn on every row whether or not it holds\n a dot, so the dots line up in one column and a read row\n does not reflow its text wider than an unread one. */}\n <span className={styles.unreadSlot}>\n {unread && (\n <>\n <span className={styles.dot} />\n {/* The dot is a colour and nothing else, which reaches\n nobody on a screen reader. This is the same state\n in words (CLAUDE.md, \"Accessibility is part of\n done\"). */}\n <span className={styles.srOnly}>{t.unreadItem}</span>\n </>\n )}\n </span>\n </Row>\n </li>\n )\n })}\n </ul>\n\n {viewAllHref != null && (\n <div className={styles.footer}>\n <Link className={styles.viewAll} href={viewAllHref}>\n {t.viewAll}\n </Link>\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n"],"names":["SOURCE_MARK_PX","NotificationCenter","items","viewAllHref","labels","linkComponent","t","resolveNotificationCenterLabels","Link","headingId","useId","unreadCount","item","isEmpty","styles","jsxs","jsx","EmptyBell","Fragment","unread","Row","ProductMark","SourceBellMark"],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const t = "_panel_sl837_36", _ = "_header_sl837_54", s = "_title_sl837_62", o = "_markAll_sl837_73", l = "_tab_sl837_86", e = "_viewAll_sl837_87", r = "_tabs_sl837_96", n = "_count_sl837_131", c = "_list_sl837_141", a = "_row_sl837_156", y = "_sourceMark_sl837_187", p = "_sourceMarkGround_sl837_196", m = "_rowText_sl837_201", d = "_rowTitle_sl837_212", u = "_rowMeta_sl837_223", i = "_unreadSlot_sl837_234", w = "_dot_sl837_243", T = "_empty_sl837_258", k = "_emptyGlyph_sl837_267", M = "_emptyText_sl837_275", x = "_emptyTitle_sl837_282", b = "_emptyBody_sl837_290", h = "_footer_sl837_299", A = "_srOnly_sl837_321", G = {
|
|
2
|
+
panel: t,
|
|
3
|
+
header: _,
|
|
4
|
+
title: s,
|
|
5
|
+
markAll: o,
|
|
6
|
+
tab: l,
|
|
7
|
+
viewAll: e,
|
|
8
|
+
tabs: r,
|
|
9
|
+
count: n,
|
|
10
|
+
list: c,
|
|
11
|
+
row: a,
|
|
12
|
+
sourceMark: y,
|
|
13
|
+
sourceMarkGround: p,
|
|
14
|
+
rowText: m,
|
|
15
|
+
rowTitle: d,
|
|
16
|
+
rowMeta: u,
|
|
17
|
+
unreadSlot: i,
|
|
18
|
+
dot: w,
|
|
19
|
+
empty: T,
|
|
20
|
+
emptyGlyph: k,
|
|
21
|
+
emptyText: M,
|
|
22
|
+
emptyTitle: x,
|
|
23
|
+
emptyBody: b,
|
|
24
|
+
footer: h,
|
|
25
|
+
srOnly: A
|
|
26
|
+
};
|
|
27
|
+
export {
|
|
28
|
+
n as count,
|
|
29
|
+
G as default,
|
|
30
|
+
w as dot,
|
|
31
|
+
T as empty,
|
|
32
|
+
b as emptyBody,
|
|
33
|
+
k as emptyGlyph,
|
|
34
|
+
M as emptyText,
|
|
35
|
+
x as emptyTitle,
|
|
36
|
+
h as footer,
|
|
37
|
+
_ as header,
|
|
38
|
+
c as list,
|
|
39
|
+
o as markAll,
|
|
40
|
+
t as panel,
|
|
41
|
+
a as row,
|
|
42
|
+
u as rowMeta,
|
|
43
|
+
m as rowText,
|
|
44
|
+
d as rowTitle,
|
|
45
|
+
y as sourceMark,
|
|
46
|
+
p as sourceMarkGround,
|
|
47
|
+
A as srOnly,
|
|
48
|
+
l as tab,
|
|
49
|
+
r as tabs,
|
|
50
|
+
s as title,
|
|
51
|
+
i as unreadSlot,
|
|
52
|
+
e as viewAll
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=NotificationCenter.module.css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationCenter.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;"}
|