@cboxdk/cbox-ui 0.10.0 → 0.10.1
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/README.md +25 -2
- package/dist/index.d.ts +36 -7
- package/dist/index.js +116 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/tokens/shell.css +15 -0
package/README.md
CHANGED
|
@@ -278,16 +278,39 @@ type Shell = {
|
|
|
278
278
|
page?: { title; route? }; // "On this page" and the chat's page intent
|
|
279
279
|
nav: { areas: NavArea[]; activeArea; activePage? };
|
|
280
280
|
context: { levels: ContextLevel[]; switchUrl }; // 1–3 levels, organization first
|
|
281
|
-
palette: { searchUrl?; gotoUrl?; actions: PaletteAction[] };
|
|
281
|
+
palette: { searchUrl?; gotoUrl?; actions: PaletteAction[]; placeholder? };
|
|
282
282
|
help: { enabled; topic?; sessionUrl?; scriptUrl?; portalUrl?; updatesUrl?; searchUrl?; articlesUrl? };
|
|
283
283
|
notifications: { enabled: false } | { enabled: true; unread; url };
|
|
284
284
|
apps: { catalogUrl; productsUrl? };
|
|
285
|
-
account
|
|
285
|
+
account?: { profileUrl?; switchAccountUrl?; signOutUrl?; signOutMethod?; languages?; formats?; signedInWith? };
|
|
286
286
|
banner?: { kind: 'sandbox' | 'impersonation' | 'notice'; text; action? };
|
|
287
287
|
preferences: { theme; locale; railPinned; helpOpen; subnavCollapsed?; regionalFormat?; timeZone? };
|
|
288
288
|
};
|
|
289
289
|
```
|
|
290
290
|
|
|
291
|
+
```ts
|
|
292
|
+
type NavArea = { key; label; url; icon?; pages?: NavPage[] };
|
|
293
|
+
type NavPage = {
|
|
294
|
+
key; label; url; icon?;
|
|
295
|
+
locked?: boolean; // not in the plan: a lock and "(locked)", `url` leads to the upgrade prompt
|
|
296
|
+
count?: number; // a badge (open drafts); hidden at 0
|
|
297
|
+
group?: string; // a heading in the subnav and the phone nav ("Organization", "Project")
|
|
298
|
+
};
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Pages of one `group` show together under its heading, in the order each group first appears.
|
|
302
|
+
Locked pages still show in the palette's Pages, marked "Locked". Every nav link (and the
|
|
303
|
+
banner action) also accepts `href` in place of `url`, the name laravel-console-kit 0.2.2 sends.
|
|
304
|
+
`palette.placeholder` replaces "Search or ask…" in the palette's field (the header button keeps
|
|
305
|
+
"Search or ask…").
|
|
306
|
+
|
|
307
|
+
`account` and each of its URLs are optional: the account menu leaves out a row it has no URL
|
|
308
|
+
for, and without `account` it holds only the preferences (laravel-console-kit's
|
|
309
|
+
`->account()` builds it).
|
|
310
|
+
|
|
311
|
+
The shell's first focusable element is a "Skip to content" link, hidden until focused. It
|
|
312
|
+
moves focus to `<main id={mainId}>` (default `main-content`).
|
|
313
|
+
|
|
291
314
|
`ContextLevel.settingsUrl` is a URL template on the wire: `{id}` is replaced with the row's id
|
|
292
315
|
(`/orgs/{id}/settings`). Nav and action icons are Lucide names (`"rocket"`, `"server"`); pass
|
|
293
316
|
`icons` to `CboxShell` for others.
|
package/dist/index.d.ts
CHANGED
|
@@ -294,22 +294,45 @@ declare const SHELL_ICONS: Readonly<Record<string, ShellIcon>>;
|
|
|
294
294
|
*/
|
|
295
295
|
/** The product key (URL standard §1). Unknown keys are allowed so a new app needs no release here. */
|
|
296
296
|
type AppKey = 'id' | 'billing' | 'telemetry' | 'work' | 'brain' | 'infra' | 'engage' | 'assistant' | 'sites' | 'stache' | 'status' | 'tax' | 'signals' | 'domains' | (string & {});
|
|
297
|
+
/**
|
|
298
|
+
* A labelled link. `href` is the same URL under the name laravel-console-kit 0.2 sends; the
|
|
299
|
+
* shell reads `url` first, then `href`.
|
|
300
|
+
*/
|
|
297
301
|
type Link = {
|
|
298
302
|
label: string;
|
|
299
303
|
url: string;
|
|
304
|
+
href?: string;
|
|
300
305
|
};
|
|
301
|
-
/**
|
|
306
|
+
/**
|
|
307
|
+
* One page inside an area. `icon` is a Lucide icon name (`"git-branch"`), resolved by the shell.
|
|
308
|
+
* `href` is the same URL under the name laravel-console-kit 0.2 sends; the shell reads `url`
|
|
309
|
+
* first, then `href`.
|
|
310
|
+
*/
|
|
302
311
|
type NavPage = {
|
|
303
312
|
key: string;
|
|
304
313
|
label: string;
|
|
305
314
|
url: string;
|
|
315
|
+
href?: string;
|
|
306
316
|
icon?: string;
|
|
317
|
+
/**
|
|
318
|
+
* The page is not part of the organization's plan: it shows with a lock and an accessible
|
|
319
|
+
* "(locked)", and `url` leads to the upgrade prompt.
|
|
320
|
+
*/
|
|
321
|
+
locked?: boolean;
|
|
322
|
+
/** A badge, such as open drafts. Not shown when 0 or absent. */
|
|
323
|
+
count?: number;
|
|
324
|
+
/**
|
|
325
|
+
* A heading inside the area's subnav (Settings → "Organization", "Project"). Pages of one
|
|
326
|
+
* group show together under it, in the order each group first appears.
|
|
327
|
+
*/
|
|
328
|
+
group?: string;
|
|
307
329
|
};
|
|
308
330
|
/** One area in the rail. The subnav shows its pages when it has more than one. */
|
|
309
331
|
type NavArea = {
|
|
310
332
|
key: string;
|
|
311
333
|
label: string;
|
|
312
334
|
url: string;
|
|
335
|
+
href?: string;
|
|
313
336
|
icon?: string;
|
|
314
337
|
pages?: NavPage[];
|
|
315
338
|
};
|
|
@@ -411,12 +434,15 @@ type ShellOption = {
|
|
|
411
434
|
code: string;
|
|
412
435
|
label: string;
|
|
413
436
|
};
|
|
414
|
-
/**
|
|
437
|
+
/**
|
|
438
|
+
* What the account menu (§10) links to. A row whose URL is absent is not shown (laravel-console-kit
|
|
439
|
+
* leaves out what the app has no route for).
|
|
440
|
+
*/
|
|
415
441
|
type ShellAccount = {
|
|
416
442
|
/** Profile and security, in Cbox ID. */
|
|
417
|
-
profileUrl
|
|
418
|
-
switchAccountUrl
|
|
419
|
-
signOutUrl
|
|
443
|
+
profileUrl?: string;
|
|
444
|
+
switchAccountUrl?: string;
|
|
445
|
+
signOutUrl?: string;
|
|
420
446
|
/** Default `post`. */
|
|
421
447
|
signOutMethod?: 'get' | 'post';
|
|
422
448
|
/** Languages the app is translated into. */
|
|
@@ -461,6 +487,8 @@ type Shell = {
|
|
|
461
487
|
/** `GET ?q=` → level 2/3 combinations across organizations (§6.1.4). */
|
|
462
488
|
gotoUrl?: string;
|
|
463
489
|
actions: PaletteAction[];
|
|
490
|
+
/** The palette search field's placeholder, e.g. "Search customers, invoices… or pages". Default "Search or ask…". */
|
|
491
|
+
placeholder?: string;
|
|
464
492
|
};
|
|
465
493
|
help: ShellHelp;
|
|
466
494
|
notifications: ShellNotifications;
|
|
@@ -470,7 +498,8 @@ type Shell = {
|
|
|
470
498
|
/** "All products ↗". Default https://cbox.dk. */
|
|
471
499
|
productsUrl?: string;
|
|
472
500
|
};
|
|
473
|
-
account:
|
|
501
|
+
/** The account menu's links. Absent (laravel-console-kit 0.2.2): the menu has only the preferences. */
|
|
502
|
+
account?: ShellAccount;
|
|
474
503
|
banner?: ShellBanner;
|
|
475
504
|
preferences: ShellPreferences;
|
|
476
505
|
};
|
|
@@ -534,7 +563,7 @@ type CboxShellProps = {
|
|
|
534
563
|
helpStore?: HelpStore;
|
|
535
564
|
/** Where the Cbox wordmark is served. Default `/brand`. */
|
|
536
565
|
brandAssetBase?: string;
|
|
537
|
-
/** `id` of the `<main>` landmark
|
|
566
|
+
/** `id` of the `<main>` landmark, which the shell's "Skip to content" link targets. Default `main-content`. */
|
|
538
567
|
mainId?: string;
|
|
539
568
|
};
|
|
540
569
|
/**
|
package/dist/index.js
CHANGED
|
@@ -350,7 +350,8 @@ function Avatar({ size = 30 }) {
|
|
|
350
350
|
}
|
|
351
351
|
function AccountMenu({ inline = false, onDone }) {
|
|
352
352
|
const { shell, t, preferences, setPreference, navigate } = useShell();
|
|
353
|
-
const {
|
|
353
|
+
const { person } = shell;
|
|
354
|
+
const account = shell.account ?? {};
|
|
354
355
|
const [view, setView] = useState("main");
|
|
355
356
|
const menu = useRef(null);
|
|
356
357
|
const tab = inline ? 0 : -1;
|
|
@@ -396,7 +397,7 @@ function AccountMenu({ inline = false, onDone }) {
|
|
|
396
397
|
] })
|
|
397
398
|
] }),
|
|
398
399
|
/* @__PURE__ */ jsxs("div", { className: "cbx-list", role: "none", children: [
|
|
399
|
-
/* @__PURE__ */ jsxs("a", { role: "menuitem", tabIndex: tab, className: "cbx-row cbx-row-action", href: account.profileUrl, onClick: onDone, children: [
|
|
400
|
+
account.profileUrl !== void 0 && /* @__PURE__ */ jsxs("a", { role: "menuitem", tabIndex: tab, className: "cbx-row cbx-row-action", href: account.profileUrl, onClick: onDone, children: [
|
|
400
401
|
/* @__PURE__ */ jsx(UserRound, { size: 16, strokeWidth: 1.8, "aria-hidden": true }),
|
|
401
402
|
/* @__PURE__ */ jsx("span", { className: "cbx-row-name", children: t("Profile and security") }),
|
|
402
403
|
/* @__PURE__ */ jsx(ArrowUpRight, { className: "cbx-row-trail", size: 14, strokeWidth: 1.8, "aria-hidden": true })
|
|
@@ -439,12 +440,12 @@ function AccountMenu({ inline = false, onDone }) {
|
|
|
439
440
|
)) })
|
|
440
441
|
] })
|
|
441
442
|
] }),
|
|
442
|
-
/* @__PURE__ */ jsxs("div", { className: "cbx-list cbx-list-foot", role: "none", children: [
|
|
443
|
-
/* @__PURE__ */ jsxs("a", { role: "menuitem", tabIndex: tab, className: "cbx-row cbx-row-action", href: account.switchAccountUrl, onClick: onDone, children: [
|
|
443
|
+
(account.switchAccountUrl !== void 0 || account.signOutUrl !== void 0) && /* @__PURE__ */ jsxs("div", { className: "cbx-list cbx-list-foot", role: "none", children: [
|
|
444
|
+
account.switchAccountUrl !== void 0 && /* @__PURE__ */ jsxs("a", { role: "menuitem", tabIndex: tab, className: "cbx-row cbx-row-action", href: account.switchAccountUrl, onClick: onDone, children: [
|
|
444
445
|
/* @__PURE__ */ jsx(Users, { size: 16, strokeWidth: 1.8, "aria-hidden": true }),
|
|
445
446
|
/* @__PURE__ */ jsx("span", { className: "cbx-row-name", children: t("Switch account") })
|
|
446
447
|
] }),
|
|
447
|
-
/* @__PURE__ */ jsxs("button", { role: "menuitem", tabIndex: tab, type: "button", className: "cbx-row cbx-row-action", onClick: () => {
|
|
448
|
+
account.signOutUrl !== void 0 && /* @__PURE__ */ jsxs("button", { role: "menuitem", tabIndex: tab, type: "button", className: "cbx-row cbx-row-action", onClick: () => {
|
|
448
449
|
onDone?.();
|
|
449
450
|
navigate(account.signOutUrl, { method: account.signOutMethod ?? "post" });
|
|
450
451
|
}, children: [
|
|
@@ -1799,6 +1800,40 @@ function resolveIcon(name, extra = {}) {
|
|
|
1799
1800
|
if (name === void 0) return Circle;
|
|
1800
1801
|
return extra[name] ?? SHELL_ICONS[name] ?? Circle;
|
|
1801
1802
|
}
|
|
1803
|
+
function navUrl(entry) {
|
|
1804
|
+
return entry.url ?? entry.href ?? "#";
|
|
1805
|
+
}
|
|
1806
|
+
function groupPages(pages) {
|
|
1807
|
+
const runs = /* @__PURE__ */ new Map();
|
|
1808
|
+
for (const page of pages) {
|
|
1809
|
+
const key = page.group === void 0 || page.group === "" ? "" : `g:${page.group}`;
|
|
1810
|
+
const run = runs.get(key) ?? { group: key === "" ? void 0 : page.group, pages: [] };
|
|
1811
|
+
run.pages.push(page);
|
|
1812
|
+
runs.set(key, run);
|
|
1813
|
+
}
|
|
1814
|
+
return Array.from(runs.values());
|
|
1815
|
+
}
|
|
1816
|
+
function NavPageMarks({ page }) {
|
|
1817
|
+
const { t } = useShell();
|
|
1818
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1819
|
+
page.locked === true && /* @__PURE__ */ jsxs("span", { className: "cbx-nav-lock", title: t("Not in your plan"), children: [
|
|
1820
|
+
/* @__PURE__ */ jsx(Lock, { size: 13, strokeWidth: 1.9, "aria-hidden": true }),
|
|
1821
|
+
/* @__PURE__ */ jsx("span", { className: "cbx-sr-only", children: t("(locked)") })
|
|
1822
|
+
] }),
|
|
1823
|
+
page.locked !== true && page.count !== void 0 && page.count > 0 && /* @__PURE__ */ jsx("span", { className: "cbx-nav-count", children: page.count > 999 ? "999+" : page.count })
|
|
1824
|
+
] });
|
|
1825
|
+
}
|
|
1826
|
+
function NavPageList({ pages, renderPage }) {
|
|
1827
|
+
const id = useId();
|
|
1828
|
+
const runs = groupPages(pages);
|
|
1829
|
+
if (runs.every((run) => run.group === void 0)) return /* @__PURE__ */ jsx(Fragment, { children: pages.map(renderPage) });
|
|
1830
|
+
return /* @__PURE__ */ jsx(Fragment, { children: runs.map(
|
|
1831
|
+
(run, index) => run.group === void 0 ? /* @__PURE__ */ jsx("div", { className: "cbx-nav-run", children: run.pages.map(renderPage) }, `run-${index}`) : /* @__PURE__ */ jsxs("div", { role: "group", "aria-labelledby": `${id}-${index}`, className: "cbx-nav-run", children: [
|
|
1832
|
+
/* @__PURE__ */ jsx("div", { id: `${id}-${index}`, className: "cbx-nav-group", children: run.group }),
|
|
1833
|
+
run.pages.map(renderPage)
|
|
1834
|
+
] }, `run-${index}`)
|
|
1835
|
+
) });
|
|
1836
|
+
}
|
|
1802
1837
|
function Sheet({ label, side, onClose, children, head }) {
|
|
1803
1838
|
const { t } = useShell();
|
|
1804
1839
|
const panel = useRef(null);
|
|
@@ -1861,14 +1896,23 @@ function NavSheet({ onClose }) {
|
|
|
1861
1896
|
const Icon = resolveIcon(area.icon, icons);
|
|
1862
1897
|
const activeArea = area.key === shell.nav.activeArea;
|
|
1863
1898
|
return /* @__PURE__ */ jsxs("div", { className: "cbx-sheet-area", children: [
|
|
1864
|
-
/* @__PURE__ */ jsxs(Link, { href: area
|
|
1899
|
+
/* @__PURE__ */ jsxs(Link, { href: navUrl(area), className: `cbx-row cbx-row-action ${activeArea ? (area.pages ?? []).length > 1 ? "is-open" : "is-current" : ""}`, "aria-current": activeArea && (area.pages ?? []).length <= 1 ? "page" : void 0, onClick: onClose, children: [
|
|
1865
1900
|
/* @__PURE__ */ jsx(Icon, { size: 16, strokeWidth: 1.8, "aria-hidden": true }),
|
|
1866
1901
|
/* @__PURE__ */ jsx("span", { className: "cbx-row-name", children: area.label })
|
|
1867
1902
|
] }),
|
|
1868
|
-
(area.pages ?? []).length > 1 && /* @__PURE__ */ jsx("div", { className: "cbx-sheet-pages", children:
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1903
|
+
(area.pages ?? []).length > 1 && /* @__PURE__ */ jsx("div", { className: "cbx-sheet-pages", children: /* @__PURE__ */ jsx(
|
|
1904
|
+
NavPageList,
|
|
1905
|
+
{
|
|
1906
|
+
pages: area.pages ?? [],
|
|
1907
|
+
renderPage: (page) => {
|
|
1908
|
+
const on = activeArea && page.key === shell.nav.activePage;
|
|
1909
|
+
return /* @__PURE__ */ jsxs(Link, { href: navUrl(page), className: `cbx-row cbx-row-action ${on ? "is-current" : ""} ${page.locked === true ? "is-locked" : ""}`, "aria-current": on ? "page" : void 0, "data-locked": page.locked === true ? "true" : void 0, onClick: onClose, children: [
|
|
1910
|
+
/* @__PURE__ */ jsx("span", { className: "cbx-row-name", children: page.label }),
|
|
1911
|
+
/* @__PURE__ */ jsx(NavPageMarks, { page })
|
|
1912
|
+
] }, page.key);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
) })
|
|
1872
1916
|
] }, area.key);
|
|
1873
1917
|
}) }),
|
|
1874
1918
|
/* @__PURE__ */ jsxs("div", { className: "cbx-list cbx-list-foot", children: [
|
|
@@ -1936,13 +1980,16 @@ function matchScore(text, query2) {
|
|
|
1936
1980
|
}
|
|
1937
1981
|
return score;
|
|
1938
1982
|
}
|
|
1939
|
-
function localPages(shell, query2, open) {
|
|
1983
|
+
function localPages(shell, query2, open, lockedLabel) {
|
|
1940
1984
|
const entries = [];
|
|
1941
1985
|
for (const area of shell.nav.areas) {
|
|
1942
|
-
|
|
1986
|
+
const areaUrl = navUrl(area);
|
|
1987
|
+
entries.push({ id: `area:${area.key}`, title: area.label, url: areaUrl, icon: area.icon });
|
|
1943
1988
|
for (const page of area.pages ?? []) {
|
|
1944
|
-
|
|
1945
|
-
|
|
1989
|
+
const url = navUrl(page);
|
|
1990
|
+
if (url === areaUrl) continue;
|
|
1991
|
+
const subtitle = page.locked === true ? `${area.label} \xB7 ${lockedLabel}` : area.label;
|
|
1992
|
+
entries.push({ id: `page:${area.key}:${page.key}`, title: page.label, subtitle, url, icon: page.locked === true ? "lock" : page.icon ?? area.icon });
|
|
1946
1993
|
}
|
|
1947
1994
|
}
|
|
1948
1995
|
return entries.map((entry) => ({ entry, score: matchScore(`${entry.title} ${entry.subtitle ?? ""}`, query2) })).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score).map(({ entry }) => {
|
|
@@ -1950,8 +1997,13 @@ function localPages(shell, query2, open) {
|
|
|
1950
1997
|
return { id: entry.id, title: entry.title, subtitle: entry.subtitle, href: entry.url, icon: /* @__PURE__ */ jsx(Icon, { size: 16, strokeWidth: 1.8, "aria-hidden": true }), run: (newTab) => open(entry.url, newTab) };
|
|
1951
1998
|
});
|
|
1952
1999
|
}
|
|
1953
|
-
function rows(body) {
|
|
1954
|
-
|
|
2000
|
+
function rows(body, group) {
|
|
2001
|
+
let data = Array.isArray(body) ? body : typeof body === "object" && body !== null ? body.data : null;
|
|
2002
|
+
if (data === void 0 && group !== void 0 && typeof body === "object" && body !== null) {
|
|
2003
|
+
const groups = body.groups;
|
|
2004
|
+
const match = Array.isArray(groups) ? groups.find((g) => typeof g === "object" && g !== null && g.key === group) : void 0;
|
|
2005
|
+
data = match?.items;
|
|
2006
|
+
}
|
|
1955
2007
|
return Array.isArray(data) ? data.filter((row) => typeof row === "object" && row !== null) : [];
|
|
1956
2008
|
}
|
|
1957
2009
|
function CommandPalette({ onClose }) {
|
|
@@ -2000,7 +2052,7 @@ function CommandPalette({ onClose }) {
|
|
|
2000
2052
|
if (shell.palette.searchUrl !== void 0) {
|
|
2001
2053
|
run(
|
|
2002
2054
|
"records",
|
|
2003
|
-
async () => rows(await requestJson(withQuery(shell.palette.searchUrl, { q: q2 }), { signal })).flatMap((row) => {
|
|
2055
|
+
async () => rows(await requestJson(withQuery(shell.palette.searchUrl, { q: q2, group: "records" }), { signal }), "records").flatMap((row) => {
|
|
2004
2056
|
const url = safeUrl(row.url);
|
|
2005
2057
|
if (typeof row.title !== "string" || url === void 0) return [];
|
|
2006
2058
|
return [{ id: `record:${String(row.id ?? url)}`, title: row.title, subtitle: typeof row.subtitle === "string" ? row.subtitle : void 0, href: url, icon: /* @__PURE__ */ jsx(FileText, { size: 16, strokeWidth: 1.8, "aria-hidden": true }), run: (newTab) => open(url, newTab) }];
|
|
@@ -2010,7 +2062,19 @@ function CommandPalette({ onClose }) {
|
|
|
2010
2062
|
const organization = shell.context.levels[0];
|
|
2011
2063
|
run("goto", async () => {
|
|
2012
2064
|
const loads = [];
|
|
2013
|
-
|
|
2065
|
+
const kitGoto = shell.palette.gotoUrl === void 0 && shell.palette.searchUrl !== void 0;
|
|
2066
|
+
if (kitGoto) {
|
|
2067
|
+
loads.push(
|
|
2068
|
+
requestJson(withQuery(shell.palette.searchUrl, { q: q2, group: "goto" }), { signal }).then(
|
|
2069
|
+
(body) => rows(body, "goto").flatMap((row) => {
|
|
2070
|
+
const url = safeUrl(row.url);
|
|
2071
|
+
if (typeof row.title !== "string" || url === void 0) return [];
|
|
2072
|
+
return [{ id: `goto:${String(row.id ?? url)}`, title: row.title, subtitle: typeof row.subtitle === "string" ? row.subtitle : void 0, href: url, icon: /* @__PURE__ */ jsx(Building2, { size: 16, strokeWidth: 1.8, "aria-hidden": true }), run: (newTab) => open(url, newTab) }];
|
|
2073
|
+
})
|
|
2074
|
+
)
|
|
2075
|
+
);
|
|
2076
|
+
}
|
|
2077
|
+
if (organization !== void 0 && !kitGoto) {
|
|
2014
2078
|
loads.push(
|
|
2015
2079
|
requestJson(withQuery(organization.listUrl, { q: q2, limit: "5" }), { signal }).then(
|
|
2016
2080
|
(body) => rows(body).flatMap((row) => {
|
|
@@ -2069,7 +2133,7 @@ function CommandPalette({ onClose }) {
|
|
|
2069
2133
|
return () => controller.abort();
|
|
2070
2134
|
}, [query2, shell]);
|
|
2071
2135
|
const q = input.trim();
|
|
2072
|
-
const pages = useMemo(() => localPages(shell, q, open), [shell, q]);
|
|
2136
|
+
const pages = useMemo(() => localPages(shell, q, open, t("Locked")), [shell, q, t]);
|
|
2073
2137
|
const actions = useMemo(
|
|
2074
2138
|
() => shell.palette.actions.filter((action) => matchScore(`${action.label} ${(action.keywords ?? []).join(" ")}`, q) > 0).map((action) => {
|
|
2075
2139
|
const Icon = action.icon !== void 0 ? resolveIcon(action.icon) : Zap;
|
|
@@ -2178,8 +2242,8 @@ function CommandPalette({ onClose }) {
|
|
|
2178
2242
|
"aria-controls": `${id}-list`,
|
|
2179
2243
|
"aria-activedescendant": activeOption !== void 0 ? `${id}-${active}` : void 0,
|
|
2180
2244
|
"aria-autocomplete": "list",
|
|
2181
|
-
"aria-label": t("Search or ask\u2026"),
|
|
2182
|
-
placeholder: t("Search or ask\u2026"),
|
|
2245
|
+
"aria-label": shell.palette.placeholder ?? t("Search or ask\u2026"),
|
|
2246
|
+
placeholder: shell.palette.placeholder ?? t("Search or ask\u2026"),
|
|
2183
2247
|
value: input,
|
|
2184
2248
|
onChange: (event) => setInput(event.target.value),
|
|
2185
2249
|
autoComplete: "off",
|
|
@@ -2358,16 +2422,31 @@ function CboxShell({ shell, children, navigate = defaultNavigate, LinkComponent
|
|
|
2358
2422
|
const helpOpen = useHelpState(store, (state) => helpVisible(state, docked));
|
|
2359
2423
|
const banner = shell.banner !== void 0 && (shell.banner.kind !== "sandbox" || testData) ? shell.banner : void 0;
|
|
2360
2424
|
return /* @__PURE__ */ jsx(ShellContext.Provider, { value: api, children: /* @__PURE__ */ jsxs("div", { className: "cbx-shell", "data-help-open": helpOpen, children: [
|
|
2425
|
+
/* @__PURE__ */ jsx(
|
|
2426
|
+
"a",
|
|
2427
|
+
{
|
|
2428
|
+
className: "cbx-skip-link",
|
|
2429
|
+
href: `#${mainId}`,
|
|
2430
|
+
onClick: (event) => {
|
|
2431
|
+
const main = document.getElementById(mainId);
|
|
2432
|
+
if (main === null) return;
|
|
2433
|
+
event.preventDefault();
|
|
2434
|
+
main.focus();
|
|
2435
|
+
main.scrollIntoView?.({ block: "start" });
|
|
2436
|
+
},
|
|
2437
|
+
children: t("Skip to content")
|
|
2438
|
+
}
|
|
2439
|
+
),
|
|
2361
2440
|
/* @__PURE__ */ jsx(Rail, { brandAssetBase }),
|
|
2362
2441
|
/* @__PURE__ */ jsxs("div", { className: "cbx-shell-column", children: [
|
|
2363
2442
|
/* @__PURE__ */ jsx(Header, { mobile }),
|
|
2364
2443
|
banner !== void 0 && /* @__PURE__ */ jsxs("div", { className: `cbx-banner cbx-banner-${banner.kind}`, role: "status", children: [
|
|
2365
2444
|
/* @__PURE__ */ jsx("span", { className: "cbx-banner-text", children: banner.text }),
|
|
2366
|
-
banner.action !== void 0 && /* @__PURE__ */ jsx(LinkComponent, { href: banner.action
|
|
2445
|
+
banner.action !== void 0 && /* @__PURE__ */ jsx(LinkComponent, { href: navUrl(banner.action), className: "cbx-banner-action", children: banner.action.label })
|
|
2367
2446
|
] }),
|
|
2368
2447
|
/* @__PURE__ */ jsxs("div", { className: "cbx-shell-body", children: [
|
|
2369
2448
|
/* @__PURE__ */ jsx(Subnav, {}),
|
|
2370
|
-
/* @__PURE__ */ jsx("main", { id: mainId, className: "cbx-shell-main canvas-gradient", children })
|
|
2449
|
+
/* @__PURE__ */ jsx("main", { id: mainId, tabIndex: -1, className: "cbx-shell-main canvas-gradient", children })
|
|
2371
2450
|
] })
|
|
2372
2451
|
] }),
|
|
2373
2452
|
/* @__PURE__ */ jsx(HelpColumn, { docked }),
|
|
@@ -2424,7 +2503,7 @@ function Rail({ brandAssetBase }) {
|
|
|
2424
2503
|
/* @__PURE__ */ jsx("nav", { className: "cbx-rail-nav", "aria-label": name, children: shell.nav.areas.map((area) => {
|
|
2425
2504
|
const Icon = resolveIcon(area.icon, icons);
|
|
2426
2505
|
const active = area.key === shell.nav.activeArea;
|
|
2427
|
-
return /* @__PURE__ */ jsxs(Link, { href: area
|
|
2506
|
+
return /* @__PURE__ */ jsxs(Link, { href: navUrl(area), className: `cbx-rail-link ${active ? "is-active" : ""}`, "aria-current": active ? "page" : void 0, title: open ? void 0 : area.label, "aria-label": area.label, children: [
|
|
2428
2507
|
/* @__PURE__ */ jsx(Icon, { size: 18, strokeWidth: 1.7, "aria-hidden": true }),
|
|
2429
2508
|
/* @__PURE__ */ jsx("span", { className: "cbx-rail-label", children: area.label })
|
|
2430
2509
|
] }, area.key);
|
|
@@ -2471,10 +2550,19 @@ function Subnav() {
|
|
|
2471
2550
|
/* @__PURE__ */ jsx("strong", { className: "cbx-truncate", children: area.label }),
|
|
2472
2551
|
/* @__PURE__ */ jsx("button", { type: "button", className: "cbx-icon-button", onClick: () => setPreference("subnavCollapsed", true), "aria-label": t("Collapse {area}", { area: area.label }), title: "\u2318.", children: /* @__PURE__ */ jsx(PanelLeftClose, { size: 16, strokeWidth: 1.8, "aria-hidden": true }) })
|
|
2473
2552
|
] }),
|
|
2474
|
-
/* @__PURE__ */ jsx("nav", { "aria-label": area.label, className: "cbx-subnav-list", children:
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2553
|
+
/* @__PURE__ */ jsx("nav", { "aria-label": area.label, className: "cbx-subnav-list", children: /* @__PURE__ */ jsx(
|
|
2554
|
+
NavPageList,
|
|
2555
|
+
{
|
|
2556
|
+
pages,
|
|
2557
|
+
renderPage: (page) => {
|
|
2558
|
+
const active = page.key === shell.nav.activePage;
|
|
2559
|
+
return /* @__PURE__ */ jsxs(Link, { href: navUrl(page), className: `cbx-subnav-link ${active ? "is-active" : ""} ${page.locked === true ? "is-locked" : ""}`, "aria-current": active ? "page" : void 0, "data-locked": page.locked === true ? "true" : void 0, children: [
|
|
2560
|
+
/* @__PURE__ */ jsx("span", { className: "cbx-truncate", title: page.label, children: page.label }),
|
|
2561
|
+
/* @__PURE__ */ jsx(NavPageMarks, { page })
|
|
2562
|
+
] }, page.key);
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
) })
|
|
2478
2566
|
] });
|
|
2479
2567
|
}
|
|
2480
2568
|
function Header({ mobile }) {
|