@stealthscale/sdk-host 0.1.0 → 0.3.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.
@@ -0,0 +1,2499 @@
1
+ import { a as settingsListed, d as HostContent, i as menusOf, n as HostRoot, o as useListed, s as usePalette, u as useInternals } from "./create-routes-D4iCBYZe.js";
2
+ import { r as useProductName, t as pluginWordsOf } from "./words-yI-WdYM3.js";
3
+ import { hostContract, subjectOf } from "@stealthscale/sdk-core";
4
+ import { Slot, useNavigation, useResolvedProduct, useSession, useSlot } from "@stealthscale/sdk-plugin";
5
+ import { settingKey } from "@stealthscale/settings";
6
+ import { createLink, useDeclaredRoute, useLinkProps, useLocation } from "@stealthscale/provider-router";
7
+ import { c } from "react/compiler-runtime";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ import { useEffect, useState, useSyncExternalStore } from "react";
10
+ import { useTranslation } from "@stealthscale/provider-i18n";
11
+ import { Button, ButtonPropsProvider, ColorModeToggle } from "@stealthscale/component-actions";
12
+ import { CheckIcon, ChevronRightIcon, ChevronsUpDownIcon, EllipsisIcon, Icon, MoonIcon, PanelLeftCloseIcon, PanelLeftIcon, PanelRightCloseIcon, PanelRightIcon, SearchIcon, SunIcon, XIcon } from "lucide-react";
13
+ import { Group } from "@stealthscale/component-layout";
14
+ import { Link, NavList } from "@stealthscale/component-navigation";
15
+ import { AppShell, Sidebar, Toolbar } from "@stealthscale/component-screen";
16
+ import { Icon as Icon$1, Text } from "@stealthscale/component-typography";
17
+ import { LocaleSwitcher, ThemeSwitcher } from "@stealthscale/component-screen/shell";
18
+ import { Avatar } from "@stealthscale/component-media";
19
+ import { SkipNav } from "@stealthscale/component-a11y";
20
+ import { useBreakpoint } from "@stealthscale/provider-viewport";
21
+ //#region src/app/opener.tsx
22
+ /**
23
+ * The icons of each side's panel while it is closed and while it is open.
24
+ */
25
+ const ICONS = {
26
+ end: {
27
+ closed: PanelRightIcon,
28
+ open: PanelRightCloseIcon
29
+ },
30
+ start: {
31
+ closed: PanelLeftIcon,
32
+ open: PanelLeftCloseIcon
33
+ }
34
+ };
35
+ /**
36
+ * Renders the shell's trigger as a small square ghost button with the panel's icon.
37
+ *
38
+ * @remarks
39
+ * The toolbar's item renders it through `as`, and it renders the trigger through `as` in turn, so
40
+ * one element takes the row's tab stop, the reference to the panel and the button's styles. While
41
+ * the panel is open, the icon points into the panel. The icon is hidden from a screen reader, and
42
+ * the trigger has the name and the state.
43
+ * @returns The control.
44
+ */
45
+ function Opener(t0) {
46
+ const $ = c(11);
47
+ let rest;
48
+ let side;
49
+ let t1;
50
+ if ($[0] !== t0) {
51
+ ({panel: t1, side, ...rest} = t0);
52
+ $[0] = t0;
53
+ $[1] = rest;
54
+ $[2] = side;
55
+ $[3] = t1;
56
+ } else {
57
+ rest = $[1];
58
+ side = $[2];
59
+ t1 = $[3];
60
+ }
61
+ const panel = t1 === void 0 ? "navbar" : t1;
62
+ const open = AppShell.useAppShellPanel(panel)?.open ?? false;
63
+ const icons = ICONS[side];
64
+ let t2;
65
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
66
+ t2 = {
67
+ palette: "neutral",
68
+ shape: "square",
69
+ size: "sm",
70
+ variant: "ghost"
71
+ };
72
+ $[4] = t2;
73
+ } else t2 = $[4];
74
+ const t3 = open ? icons.open : icons.closed;
75
+ let t4;
76
+ if ($[5] !== t3) {
77
+ t4 = /* @__PURE__ */ jsx(Icon$1, {
78
+ as: t3,
79
+ size: "sm"
80
+ });
81
+ $[5] = t3;
82
+ $[6] = t4;
83
+ } else t4 = $[6];
84
+ let t5;
85
+ if ($[7] !== panel || $[8] !== rest || $[9] !== t4) {
86
+ t5 = /* @__PURE__ */ jsx(ButtonPropsProvider, {
87
+ value: t2,
88
+ children: /* @__PURE__ */ jsx(AppShell.Trigger, {
89
+ as: Button,
90
+ panel,
91
+ ...rest,
92
+ children: t4
93
+ })
94
+ });
95
+ $[7] = panel;
96
+ $[8] = rest;
97
+ $[9] = t4;
98
+ $[10] = t5;
99
+ } else t5 = $[10];
100
+ return t5;
101
+ }
102
+ //#endregion
103
+ //#region src/app/switchers.tsx
104
+ /**
105
+ * Glyph that marks the picked row of a switcher's menu.
106
+ */
107
+ const CHECK = /* @__PURE__ */ jsx(CheckIcon, {
108
+ "aria-hidden": true,
109
+ size: "1em"
110
+ });
111
+ /**
112
+ * Glyph at the end of a switcher's control, which opens a list to pick from.
113
+ */
114
+ const INDICATOR = /* @__PURE__ */ jsx(Icon$1, {
115
+ as: ChevronsUpDownIcon,
116
+ size: "sm"
117
+ });
118
+ /**
119
+ * Where a switcher's menu opens: below the control and aligned to its end, at the bar's end.
120
+ */
121
+ const POSITIONING = { placement: "bottom-end" };
122
+ /**
123
+ * Renders each switcher as an item of the bar's row.
124
+ *
125
+ * @remarks
126
+ * The language and the theme switchers are the screen package's, in the outline look, named in
127
+ * the host's words. The colour mode toggle shows a moon and a sun. Each reads a provider of the
128
+ * product's shell, so the frame renders them inside `Shell`.
129
+ */
130
+ function FrameSwitchers(t0) {
131
+ const $ = c(7);
132
+ const { switchers } = t0;
133
+ const { t } = useTranslation("host");
134
+ let t1;
135
+ if ($[0] !== switchers || $[1] !== t) {
136
+ let t2;
137
+ if ($[3] !== t) {
138
+ t2 = (switcher) => {
139
+ if (switcher === "locale") return /* @__PURE__ */ jsx(LocaleSwitcher, {
140
+ checkIcon: CHECK,
141
+ indicator: INDICATOR,
142
+ label: t("frame.language"),
143
+ positioning: POSITIONING,
144
+ variant: "outline"
145
+ }, switcher);
146
+ if (switcher === "theme") return /* @__PURE__ */ jsx(ThemeSwitcher, {
147
+ checkIcon: CHECK,
148
+ indicator: INDICATOR,
149
+ label: t("frame.theme"),
150
+ positioning: POSITIONING,
151
+ variant: "outline"
152
+ }, switcher);
153
+ return /* @__PURE__ */ jsx(Toolbar.Item, {
154
+ as: ColorModeToggle,
155
+ dark: /* @__PURE__ */ jsx(Icon$1, {
156
+ as: MoonIcon,
157
+ size: "sm"
158
+ }),
159
+ label: t("frame.darkMode"),
160
+ light: /* @__PURE__ */ jsx(Icon$1, {
161
+ as: SunIcon,
162
+ size: "sm"
163
+ }),
164
+ size: "sm"
165
+ }, switcher);
166
+ };
167
+ $[3] = t;
168
+ $[4] = t2;
169
+ } else t2 = $[4];
170
+ t1 = switchers.map(t2);
171
+ $[0] = switchers;
172
+ $[1] = t;
173
+ $[2] = t1;
174
+ } else t1 = $[2];
175
+ let t2;
176
+ if ($[5] !== t1) {
177
+ t2 = /* @__PURE__ */ jsx(Fragment, { children: t1 });
178
+ $[5] = t1;
179
+ $[6] = t2;
180
+ } else t2 = $[6];
181
+ return t2;
182
+ }
183
+ //#endregion
184
+ //#region src/app/bar-end.tsx
185
+ /**
186
+ * Renders the end band of the bar's toolbar.
187
+ *
188
+ * @remarks
189
+ * The search is an action that opens the palette `Mod+K` opens, which lists the commands and
190
+ * every page of the main menu. A narrow bar shows its icon alone.
191
+ * @returns The toolbar's end band.
192
+ */
193
+ function BarEnd(t0) {
194
+ const $ = c(14);
195
+ const { bar, panel } = t0;
196
+ const { t } = useTranslation("host");
197
+ const { setOpen } = usePalette();
198
+ let t1;
199
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
200
+ t1 = /* @__PURE__ */ jsx(Slot, { slot: hostContract.slots.header });
201
+ $[0] = t1;
202
+ } else t1 = $[0];
203
+ let t2;
204
+ if ($[1] !== bar.search || $[2] !== setOpen || $[3] !== t) {
205
+ t2 = bar.search ? /* @__PURE__ */ jsx(Toolbar.Action, {
206
+ "aria-keyshortcuts": "Control+K Meta+K",
207
+ icon: /* @__PURE__ */ jsx(Icon$1, {
208
+ as: SearchIcon,
209
+ size: "sm"
210
+ }),
211
+ onClick: () => {
212
+ setOpen(true);
213
+ },
214
+ children: t("frame.search")
215
+ }) : null;
216
+ $[1] = bar.search;
217
+ $[2] = setOpen;
218
+ $[3] = t;
219
+ $[4] = t2;
220
+ } else t2 = $[4];
221
+ let t3;
222
+ if ($[5] !== bar.switchers) {
223
+ t3 = /* @__PURE__ */ jsx(FrameSwitchers, { switchers: bar.switchers });
224
+ $[5] = bar.switchers;
225
+ $[6] = t3;
226
+ } else t3 = $[6];
227
+ let t4;
228
+ if ($[7] !== panel || $[8] !== t) {
229
+ t4 = panel ? /* @__PURE__ */ jsx(Toolbar.Item, {
230
+ "aria-label": t("frame.panel"),
231
+ as: Opener,
232
+ panel: "panel",
233
+ side: "end"
234
+ }) : null;
235
+ $[7] = panel;
236
+ $[8] = t;
237
+ $[9] = t4;
238
+ } else t4 = $[9];
239
+ let t5;
240
+ if ($[10] !== t2 || $[11] !== t3 || $[12] !== t4) {
241
+ t5 = /* @__PURE__ */ jsxs(Toolbar.End, { children: [
242
+ t1,
243
+ t2,
244
+ t3,
245
+ t4
246
+ ] });
247
+ $[10] = t2;
248
+ $[11] = t3;
249
+ $[12] = t4;
250
+ $[13] = t5;
251
+ } else t5 = $[13];
252
+ return t5;
253
+ }
254
+ //#endregion
255
+ //#region src/app/brand.tsx
256
+ /**
257
+ * Renders the brand as the router's link, so it opens the site root without a reload.
258
+ */
259
+ const Home = createLink(Link);
260
+ /**
261
+ * Renders the logo and the product's name in the bar's own ink.
262
+ *
263
+ * @remarks
264
+ * The logo is the media package's avatar in its rounded shape, the mark of a company, with no
265
+ * text alternative, because the name beside it names the link. A compact brand renders the mark
266
+ * alone and takes the name as its link's name. The name is semibold at the small size. The
267
+ * router's link passes its children to the element as one list, so the mark and the name are one
268
+ * fragment.
269
+ * @returns The link.
270
+ */
271
+ function FrameBrand(t0) {
272
+ const $ = c(18);
273
+ let logo;
274
+ let rest;
275
+ let t1;
276
+ if ($[0] !== t0) {
277
+ ({compact: t1, logo, ...rest} = t0);
278
+ $[0] = t0;
279
+ $[1] = logo;
280
+ $[2] = rest;
281
+ $[3] = t1;
282
+ } else {
283
+ logo = $[1];
284
+ rest = $[2];
285
+ t1 = $[3];
286
+ }
287
+ const compact = t1 === void 0 ? false : t1;
288
+ const name = useProductName(useResolvedProduct());
289
+ const marked = compact || logo !== void 0;
290
+ const t2 = compact ? name : void 0;
291
+ let t3;
292
+ if ($[4] !== logo || $[5] !== marked || $[6] !== name) {
293
+ t3 = marked ? /* @__PURE__ */ jsxs(Avatar.Root, {
294
+ "aria-hidden": true,
295
+ name,
296
+ shape: "rounded",
297
+ size: "xs",
298
+ children: [logo === void 0 ? null : /* @__PURE__ */ jsx(Avatar.Image, {
299
+ alt: "",
300
+ src: logo
301
+ }), /* @__PURE__ */ jsx(Avatar.Fallback, {})]
302
+ }) : null;
303
+ $[4] = logo;
304
+ $[5] = marked;
305
+ $[6] = name;
306
+ $[7] = t3;
307
+ } else t3 = $[7];
308
+ let t4;
309
+ if ($[8] !== compact || $[9] !== name) {
310
+ t4 = compact ? null : /* @__PURE__ */ jsx(Text, {
311
+ as: "span",
312
+ size: "sm",
313
+ weight: "semibold",
314
+ children: name
315
+ });
316
+ $[8] = compact;
317
+ $[9] = name;
318
+ $[10] = t4;
319
+ } else t4 = $[10];
320
+ let t5;
321
+ if ($[11] !== t3 || $[12] !== t4) {
322
+ t5 = /* @__PURE__ */ jsxs(Fragment, { children: [t3, t4] });
323
+ $[11] = t3;
324
+ $[12] = t4;
325
+ $[13] = t5;
326
+ } else t5 = $[13];
327
+ let t6;
328
+ if ($[14] !== rest || $[15] !== t2 || $[16] !== t5) {
329
+ t6 = /* @__PURE__ */ jsx(Home, {
330
+ "aria-label": t2,
331
+ inherit: true,
332
+ to: "/",
333
+ variant: "plain",
334
+ ...rest,
335
+ children: t5
336
+ });
337
+ $[14] = rest;
338
+ $[15] = t2;
339
+ $[16] = t5;
340
+ $[17] = t6;
341
+ } else t6 = $[17];
342
+ return t6;
343
+ }
344
+ //#endregion
345
+ //#region src/app/section-link.tsx
346
+ /**
347
+ * Renders the section's link as a toolbar link in the neutral ghost look.
348
+ *
349
+ * @remarks
350
+ * The router's link props open the section without a reload and leave a press with a modifier
351
+ * key to the browser. A narrow bar renders the link as a row of the bar's menu, which calls the
352
+ * same handler.
353
+ * @returns The toolbar's link.
354
+ */
355
+ function SectionLink(t0) {
356
+ const $ = c(7);
357
+ const { current, section } = t0;
358
+ let t1;
359
+ if ($[0] !== section.href) {
360
+ t1 = { to: section.href };
361
+ $[0] = section.href;
362
+ $[1] = t1;
363
+ } else t1 = $[1];
364
+ const { href: t2, onClick } = useLinkProps(t1);
365
+ const href = t2 === void 0 ? "" : t2;
366
+ let t3;
367
+ if ($[2] !== current || $[3] !== href || $[4] !== onClick || $[5] !== section.label) {
368
+ t3 = /* @__PURE__ */ jsx(Toolbar.Link, {
369
+ current,
370
+ href,
371
+ onClick,
372
+ palette: "neutral",
373
+ children: section.label
374
+ });
375
+ $[2] = current;
376
+ $[3] = href;
377
+ $[4] = onClick;
378
+ $[5] = section.label;
379
+ $[6] = t3;
380
+ } else t3 = $[6];
381
+ return t3;
382
+ }
383
+ //#endregion
384
+ //#region src/app/bar-start.tsx
385
+ /**
386
+ * Renders the start band of the bar's toolbar.
387
+ *
388
+ * @remarks
389
+ * The opener renders while the sidebar is beside the page, and while a sidebar shown only as a
390
+ * sheet lies over a narrow page. The brand is the toolbar's title, so the sections start a wider
391
+ * gap after it. The `brand` region renders in place of the logo and the name while a plugin fills
392
+ * it. A narrow bar moves the sections into its menu.
393
+ * @returns The toolbar's start band.
394
+ */
395
+ function BarStart(t0) {
396
+ const $ = c(14);
397
+ const { brand, links, logo, navigation, sections } = t0;
398
+ const { t } = useTranslation("host");
399
+ const branded = useSlot(hostContract.slots.brand).filled;
400
+ const overlaid = AppShell.useAppShellPanel("navigation")?.overlaid === true;
401
+ const opened = navigation === "body" || navigation === "sheet" && overlaid;
402
+ let t1;
403
+ if ($[0] !== opened || $[1] !== t) {
404
+ t1 = opened ? /* @__PURE__ */ jsx(Toolbar.Item, {
405
+ "aria-label": t("frame.navigation"),
406
+ as: Opener,
407
+ panel: "navigation",
408
+ side: "start"
409
+ }) : null;
410
+ $[0] = opened;
411
+ $[1] = t;
412
+ $[2] = t1;
413
+ } else t1 = $[2];
414
+ let t2;
415
+ if ($[3] !== brand || $[4] !== branded || $[5] !== logo) {
416
+ t2 = brand ? /* @__PURE__ */ jsx(Toolbar.Title, { children: branded ? /* @__PURE__ */ jsx(Slot, { slot: hostContract.slots.brand }) : /* @__PURE__ */ jsx(Toolbar.Item, {
417
+ as: FrameBrand,
418
+ logo
419
+ }) }) : null;
420
+ $[3] = brand;
421
+ $[4] = branded;
422
+ $[5] = logo;
423
+ $[6] = t2;
424
+ } else t2 = $[6];
425
+ let t3;
426
+ if ($[7] !== links || $[8] !== sections) {
427
+ t3 = links ? sections.sections.map((section) => /* @__PURE__ */ jsx(SectionLink, {
428
+ current: section === sections.current,
429
+ section
430
+ }, section.routeId)) : null;
431
+ $[7] = links;
432
+ $[8] = sections;
433
+ $[9] = t3;
434
+ } else t3 = $[9];
435
+ let t4;
436
+ if ($[10] !== t1 || $[11] !== t2 || $[12] !== t3) {
437
+ t4 = /* @__PURE__ */ jsxs(Toolbar.Start, { children: [
438
+ t1,
439
+ t2,
440
+ t3
441
+ ] });
442
+ $[10] = t1;
443
+ $[11] = t2;
444
+ $[12] = t3;
445
+ $[13] = t4;
446
+ } else t4 = $[13];
447
+ return t4;
448
+ }
449
+ //#endregion
450
+ //#region src/app/mode.ts
451
+ /**
452
+ * Returns the attribute that renders a part in a colour mode, or none where the part takes the
453
+ * page's mode.
454
+ *
455
+ * @remarks
456
+ * The theme writes every colour that differs between the modes as one `light-dark()` value. The
457
+ * browser evaluates it against the `color-scheme` of the element that uses it, so the mode
458
+ * attribute alone switches every colour inside the part.
459
+ * @param mode - The part's colour mode. The page's where left out.
460
+ */
461
+ function modeAttributes(mode) {
462
+ return mode === void 0 ? {} : { "data-color-mode": mode };
463
+ }
464
+ //#endregion
465
+ //#region src/app/bar.tsx
466
+ /**
467
+ * Renders the bar as the shell's header, with the toolbar and the user menu in a row.
468
+ *
469
+ * @remarks
470
+ * Every control of the toolbar is an item of its row, so the row is one tab stop and the arrow
471
+ * keys move between the controls. A narrow toolbar moves the controls it folds into a menu behind
472
+ * an ellipsis at the end of the row. The user menu is a region of its own after the toolbar,
473
+ * because a plugin's menu there is no item of the row.
474
+ * @returns The `header` element.
475
+ */
476
+ function FrameBar(t0) {
477
+ const $ = c(26);
478
+ const { frame, panel, start, userMenu } = t0;
479
+ const { t } = useTranslation("host");
480
+ let t1;
481
+ if ($[0] !== frame.bar.mode) {
482
+ t1 = modeAttributes(frame.bar.mode);
483
+ $[0] = frame.bar.mode;
484
+ $[1] = t1;
485
+ } else t1 = $[1];
486
+ const mode = t1;
487
+ const t2 = frame.bar.sticky;
488
+ let t3;
489
+ if ($[2] !== t) {
490
+ t3 = t("frame.bar");
491
+ $[2] = t;
492
+ $[3] = t3;
493
+ } else t3 = $[3];
494
+ let t4;
495
+ if ($[4] !== t) {
496
+ t4 = t("frame.more");
497
+ $[4] = t;
498
+ $[5] = t4;
499
+ } else t4 = $[5];
500
+ let t5;
501
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
502
+ t5 = /* @__PURE__ */ jsx(EllipsisIcon, { "aria-hidden": true });
503
+ $[6] = t5;
504
+ } else t5 = $[6];
505
+ let t6;
506
+ if ($[7] !== start) {
507
+ t6 = /* @__PURE__ */ jsx(BarStart, { ...start });
508
+ $[7] = start;
509
+ $[8] = t6;
510
+ } else t6 = $[8];
511
+ let t7;
512
+ if ($[9] !== frame.bar || $[10] !== panel) {
513
+ t7 = /* @__PURE__ */ jsx(BarEnd, {
514
+ bar: frame.bar,
515
+ panel
516
+ });
517
+ $[9] = frame.bar;
518
+ $[10] = panel;
519
+ $[11] = t7;
520
+ } else t7 = $[11];
521
+ let t8;
522
+ if ($[12] !== t3 || $[13] !== t4 || $[14] !== t6 || $[15] !== t7) {
523
+ t8 = /* @__PURE__ */ jsxs(Toolbar.Root, {
524
+ "aria-label": t3,
525
+ more: t4,
526
+ moreIcon: t5,
527
+ size: "sm",
528
+ children: [t6, t7]
529
+ });
530
+ $[12] = t3;
531
+ $[13] = t4;
532
+ $[14] = t6;
533
+ $[15] = t7;
534
+ $[16] = t8;
535
+ } else t8 = $[16];
536
+ let t9;
537
+ if ($[17] !== userMenu) {
538
+ t9 = userMenu ? /* @__PURE__ */ jsx(Slot, { slot: hostContract.slots.userMenu }) : null;
539
+ $[17] = userMenu;
540
+ $[18] = t9;
541
+ } else t9 = $[18];
542
+ let t10;
543
+ if ($[19] !== t8 || $[20] !== t9) {
544
+ t10 = /* @__PURE__ */ jsxs(Group, {
545
+ justify: "between",
546
+ children: [t8, t9]
547
+ });
548
+ $[19] = t8;
549
+ $[20] = t9;
550
+ $[21] = t10;
551
+ } else t10 = $[21];
552
+ let t11;
553
+ if ($[22] !== frame.bar.sticky || $[23] !== mode || $[24] !== t10) {
554
+ t11 = /* @__PURE__ */ jsx(AppShell.Header, {
555
+ ...mode,
556
+ sticky: t2,
557
+ children: t10
558
+ });
559
+ $[22] = frame.bar.sticky;
560
+ $[23] = mode;
561
+ $[24] = t10;
562
+ $[25] = t11;
563
+ } else t11 = $[25];
564
+ return t11;
565
+ }
566
+ //#endregion
567
+ //#region src/app/panels.ts
568
+ /**
569
+ * Keeps a person's open state and width of each panel of the frame in the host's setting store,
570
+ * and states the panel's options as the app shell takes them.
571
+ *
572
+ * @remarks
573
+ * A panel's choice is `{"open":false,"size":280}` under
574
+ * `stealth.<productId>.<subject>.frame.<panel>`, where the subject is the session's person and
575
+ * tenant, or `anyone` for a session nobody signed in to. The stored open state applies while the
576
+ * panel is beside the page, because the app shell keeps a sheet's state apart, so a phone opens
577
+ * with its sheets closed. Below the panel's `closedBelow` the panel starts closed for the visit,
578
+ * and its changes there leave the stored choice alone.
579
+ */
580
+ /**
581
+ * The narrowest width a resizable panel takes where its options state none, in pixels.
582
+ */
583
+ const MIN_SIZE = 192;
584
+ /**
585
+ * Returns true for a plain object.
586
+ */
587
+ function isRecord(value) {
588
+ return typeof value === "object" && value !== null && !Array.isArray(value);
589
+ }
590
+ /**
591
+ * Returns true for a width in pixels.
592
+ */
593
+ function isSize(value) {
594
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
595
+ }
596
+ /**
597
+ * Returns the choice stored text contains, with the reason for each member it ignores.
598
+ *
599
+ * @param text - The stored text, or null where nothing is stored.
600
+ */
601
+ function storedPanelOf(text) {
602
+ if (text === null) return {
603
+ dropped: [],
604
+ panel: {}
605
+ };
606
+ let parsed;
607
+ try {
608
+ parsed = JSON.parse(text);
609
+ } catch {
610
+ return {
611
+ dropped: ["the stored value is not JSON"],
612
+ panel: {}
613
+ };
614
+ }
615
+ if (!isRecord(parsed)) return {
616
+ dropped: ["the stored value is not an object"],
617
+ panel: {}
618
+ };
619
+ const { open, size } = parsed;
620
+ return {
621
+ dropped: [...open === void 0 || typeof open === "boolean" ? [] : ["open is not a boolean"], ...size === void 0 || isSize(size) ? [] : ["size is not a width in pixels"]],
622
+ panel: {
623
+ ...typeof open === "boolean" ? { open } : {},
624
+ ...isSize(size) ? { size } : {}
625
+ }
626
+ };
627
+ }
628
+ /**
629
+ * Returns a panel's options as the app shell takes them.
630
+ *
631
+ * @param options - The panel's resolved options.
632
+ */
633
+ function panelPropsOf(options) {
634
+ const { collapse, folds, foldsBelow, railWidth, resizable, shortcut, width } = options;
635
+ const sizes = typeof resizable === "object" ? resizable : {};
636
+ return {
637
+ collapse,
638
+ folds,
639
+ foldsBelow,
640
+ maxSize: sizes.max,
641
+ minSize: resizable === false ? void 0 : sizes.min ?? MIN_SIZE,
642
+ railWidth,
643
+ resizable: resizable !== false,
644
+ shortcut: shortcut === false ? void 0 : shortcut,
645
+ width
646
+ };
647
+ }
648
+ /**
649
+ * Returns true while the window is narrower than a breakpoint, and false where none is given.
650
+ *
651
+ * @param breakpoint - The panel's `closedBelow`.
652
+ */
653
+ function useBelow(breakpoint) {
654
+ const $ = c(2);
655
+ let t0;
656
+ if ($[0] !== breakpoint) {
657
+ t0 = { breakpoints: breakpoint === void 0 ? [] : [breakpoint] };
658
+ $[0] = breakpoint;
659
+ $[1] = t0;
660
+ } else t0 = $[1];
661
+ const at = useBreakpoint(t0);
662
+ return breakpoint !== void 0 && at !== breakpoint;
663
+ }
664
+ /**
665
+ * Returns a panel's open state for the visit below `closedBelow`, which starts closed and closes
666
+ * again each time the window narrows past the breakpoint.
667
+ *
668
+ * @remarks
669
+ * The hook keeps the window's side of the breakpoint with the state, and resets the state while
670
+ * it renders, so a panel never shows its earlier state for one frame.
671
+ * @param below - True while the window is narrower than the panel's `closedBelow`.
672
+ */
673
+ function useVisit(below) {
674
+ const $ = c(7);
675
+ let t0;
676
+ if ($[0] !== below) {
677
+ t0 = {
678
+ below,
679
+ open: false
680
+ };
681
+ $[0] = below;
682
+ $[1] = t0;
683
+ } else t0 = $[1];
684
+ const [visit, setVisit] = useState(t0);
685
+ if (visit.below !== below) setVisit({
686
+ below,
687
+ open: false
688
+ });
689
+ const t1 = visit.below === below && visit.open;
690
+ let t2;
691
+ if ($[2] !== below) {
692
+ t2 = (open) => {
693
+ setVisit({
694
+ below,
695
+ open
696
+ });
697
+ };
698
+ $[2] = below;
699
+ $[3] = t2;
700
+ } else t2 = $[3];
701
+ let t3;
702
+ if ($[4] !== t1 || $[5] !== t2) {
703
+ t3 = [t1, t2];
704
+ $[4] = t1;
705
+ $[5] = t2;
706
+ $[6] = t3;
707
+ } else t3 = $[6];
708
+ return t3;
709
+ }
710
+ /**
711
+ * Returns the person's choice for a panel of the frame, and renders again when it changes in this
712
+ * tab or another.
713
+ *
714
+ * @remarks
715
+ * The hook reports each member of a stored choice it ignores as `setting-dropped`, once per
716
+ * stored text. Below `closedBelow` the panel starts closed, and closes again each time the window
717
+ * narrows past the breakpoint.
718
+ * @param name - The panel, whose name the stored choice's key contains.
719
+ * @param options - The panel's resolved options.
720
+ */
721
+ function usePanelChoice(name, options) {
722
+ const $ = c(31);
723
+ const { runtime } = useInternals();
724
+ const { report, settings } = runtime;
725
+ const t0 = `${subjectOf(useSession()) ?? "anyone"}.frame.${name}`;
726
+ let t1;
727
+ if ($[0] !== runtime.product.productId || $[1] !== t0) {
728
+ t1 = settingKey(runtime.product.productId, t0);
729
+ $[0] = runtime.product.productId;
730
+ $[1] = t0;
731
+ $[2] = t1;
732
+ } else t1 = $[2];
733
+ const key = t1;
734
+ let t2;
735
+ if ($[3] !== key || $[4] !== settings) {
736
+ t2 = () => settings.read(key);
737
+ $[3] = key;
738
+ $[4] = settings;
739
+ $[5] = t2;
740
+ } else t2 = $[5];
741
+ const read = t2;
742
+ let t3;
743
+ if ($[6] !== key || $[7] !== settings) {
744
+ t3 = (changed) => settings.subscribe(key, changed);
745
+ $[6] = key;
746
+ $[7] = settings;
747
+ $[8] = t3;
748
+ } else t3 = $[8];
749
+ const text = useSyncExternalStore(t3, read, read);
750
+ let t4;
751
+ if ($[9] !== text) {
752
+ t4 = storedPanelOf(text);
753
+ $[9] = text;
754
+ $[10] = t4;
755
+ } else t4 = $[10];
756
+ const stored = t4.panel;
757
+ const below = useBelow(options.closedBelow);
758
+ const [visited, setVisited] = useVisit(below);
759
+ let t5;
760
+ let t6;
761
+ if ($[11] !== key || $[12] !== report || $[13] !== text) {
762
+ t5 = () => {
763
+ for (const reason of storedPanelOf(text).dropped) report({
764
+ key,
765
+ kind: "setting-dropped",
766
+ reason
767
+ });
768
+ };
769
+ t6 = [
770
+ key,
771
+ report,
772
+ text
773
+ ];
774
+ $[11] = key;
775
+ $[12] = report;
776
+ $[13] = text;
777
+ $[14] = t5;
778
+ $[15] = t6;
779
+ } else {
780
+ t5 = $[14];
781
+ t6 = $[15];
782
+ }
783
+ useEffect(t5, t6);
784
+ let t7;
785
+ if ($[16] !== key || $[17] !== settings || $[18] !== stored) {
786
+ t7 = (change) => {
787
+ settings.write(key, JSON.stringify({
788
+ ...stored,
789
+ ...change
790
+ }));
791
+ };
792
+ $[16] = key;
793
+ $[17] = settings;
794
+ $[18] = stored;
795
+ $[19] = t7;
796
+ } else t7 = $[19];
797
+ const write = t7;
798
+ let t8;
799
+ if ($[20] !== below || $[21] !== setVisited || $[22] !== write) {
800
+ t8 = (open) => {
801
+ if (below) setVisited(open);
802
+ else write({ open });
803
+ };
804
+ $[20] = below;
805
+ $[21] = setVisited;
806
+ $[22] = write;
807
+ $[23] = t8;
808
+ } else t8 = $[23];
809
+ let t9;
810
+ if ($[24] !== write) {
811
+ t9 = (size) => {
812
+ write({ size });
813
+ };
814
+ $[24] = write;
815
+ $[25] = t9;
816
+ } else t9 = $[25];
817
+ const t10 = below ? visited : stored.open ?? options.defaultOpen;
818
+ let t11;
819
+ if ($[26] !== stored.size || $[27] !== t10 || $[28] !== t8 || $[29] !== t9) {
820
+ t11 = {
821
+ onOpenChange: t8,
822
+ onSizeChange: t9,
823
+ open: t10,
824
+ size: stored.size
825
+ };
826
+ $[26] = stored.size;
827
+ $[27] = t10;
828
+ $[28] = t8;
829
+ $[29] = t9;
830
+ $[30] = t11;
831
+ } else t11 = $[30];
832
+ return t11;
833
+ }
834
+ //#endregion
835
+ //#region src/app/targets.ts
836
+ /**
837
+ * Names the elements the frame's skip links move focus to.
838
+ */
839
+ /**
840
+ * Id of the main region, the first skip link's target.
841
+ */
842
+ const MAIN = "frame-main";
843
+ /**
844
+ * Id of the sidebar.
845
+ */
846
+ const NAVIGATION = "frame-navigation";
847
+ /**
848
+ * Id of the content of the panel at the end side that renders the `aside` region.
849
+ */
850
+ const ASIDE = "frame-aside";
851
+ /**
852
+ * Id of the content of the panel at the end side that renders the `panel` region.
853
+ */
854
+ const PANEL = "frame-panel";
855
+ //#endregion
856
+ //#region src/app/end-panel.tsx
857
+ /**
858
+ * The id of each panel's content, which its skip link moves focus to.
859
+ */
860
+ const TARGETS = {
861
+ aside: ASIDE,
862
+ panel: PANEL
863
+ };
864
+ /**
865
+ * Renders the region in the shell's end panel of the same name, a complementary landmark named in
866
+ * the host's words.
867
+ *
868
+ * @remarks
869
+ * The panel keeps the person's choice of its open state and width. The two end panels take
870
+ * distinct names, so a screen reader tells their landmarks apart.
871
+ * @returns The strip on the panel's edge where its options keep one, and the panel.
872
+ */
873
+ function EndPanel(t0) {
874
+ const $ = c(26);
875
+ const { name, options } = t0;
876
+ const { t } = useTranslation("host");
877
+ const choice = usePanelChoice(name, options);
878
+ let t1;
879
+ if ($[0] !== options.mode) {
880
+ t1 = modeAttributes(options.mode);
881
+ $[0] = options.mode;
882
+ $[1] = t1;
883
+ } else t1 = $[1];
884
+ const mode = t1;
885
+ let t2;
886
+ if ($[2] !== name || $[3] !== options.edge || $[4] !== t) {
887
+ t2 = options.edge ? /* @__PURE__ */ jsx(AppShell.Rail, {
888
+ closeLabel: t(`frame.edge.close.${name}`),
889
+ openLabel: t(`frame.edge.open.${name}`),
890
+ panel: name,
891
+ resizeLabel: t(`frame.edge.resize.${name}`)
892
+ }) : null;
893
+ $[2] = name;
894
+ $[3] = options.edge;
895
+ $[4] = t;
896
+ $[5] = t2;
897
+ } else t2 = $[5];
898
+ let t3;
899
+ if ($[6] !== options) {
900
+ t3 = panelPropsOf(options);
901
+ $[6] = options;
902
+ $[7] = t3;
903
+ } else t3 = $[7];
904
+ const t4 = `frame.${name}`;
905
+ let t5;
906
+ if ($[8] !== t || $[9] !== t4) {
907
+ t5 = t(t4);
908
+ $[8] = t;
909
+ $[9] = t4;
910
+ $[10] = t5;
911
+ } else t5 = $[10];
912
+ const t6 = TARGETS[name];
913
+ const t7 = hostContract.slots[name];
914
+ let t8;
915
+ if ($[11] !== t7) {
916
+ t8 = /* @__PURE__ */ jsx(Slot, { slot: t7 });
917
+ $[11] = t7;
918
+ $[12] = t8;
919
+ } else t8 = $[12];
920
+ let t9;
921
+ if ($[13] !== t6 || $[14] !== t8) {
922
+ t9 = /* @__PURE__ */ jsx(SkipNav.Target, {
923
+ id: t6,
924
+ children: t8
925
+ });
926
+ $[13] = t6;
927
+ $[14] = t8;
928
+ $[15] = t9;
929
+ } else t9 = $[15];
930
+ let t10;
931
+ if ($[16] !== choice || $[17] !== mode || $[18] !== name || $[19] !== t3 || $[20] !== t5 || $[21] !== t9) {
932
+ t10 = /* @__PURE__ */ jsx(AppShell.Aside, {
933
+ ...t3,
934
+ ...choice,
935
+ ...mode,
936
+ "aria-label": t5,
937
+ name,
938
+ children: t9
939
+ });
940
+ $[16] = choice;
941
+ $[17] = mode;
942
+ $[18] = name;
943
+ $[19] = t3;
944
+ $[20] = t5;
945
+ $[21] = t9;
946
+ $[22] = t10;
947
+ } else t10 = $[22];
948
+ let t11;
949
+ if ($[23] !== t10 || $[24] !== t2) {
950
+ t11 = /* @__PURE__ */ jsxs(Fragment, { children: [t2, t10] });
951
+ $[23] = t10;
952
+ $[24] = t2;
953
+ $[25] = t11;
954
+ } else t11 = $[25];
955
+ return t11;
956
+ }
957
+ //#endregion
958
+ //#region src/app/entry-icon.tsx
959
+ /**
960
+ * Returns an icon's data as lucide's component takes it, with each element keyed by its position.
961
+ *
962
+ * @remarks
963
+ * The component renders the elements as one list of children. The `lucide` package writes no
964
+ * key into an icon's data, and the elements of an icon never change order.
965
+ */
966
+ function iconNodeOf(icon) {
967
+ return icon.map(([tag, attributes], index) => {
968
+ return [tag, {
969
+ ...attributes,
970
+ key: String(index)
971
+ }];
972
+ });
973
+ }
974
+ /**
975
+ * Renders the entry's icon from lucide's data, or the initials of its text in an avatar where the
976
+ * row needs a mark, or nothing.
977
+ *
978
+ * @remarks
979
+ * Both are hidden from assistive technology, because the entry's text names the row. A list
980
+ * collapsed to a rail keeps either visible in place of the text.
981
+ * @returns The `svg` element, the mark with the avatar, or nothing.
982
+ */
983
+ function EntryIcon(t0) {
984
+ const $ = c(7);
985
+ const { entry, marked } = t0;
986
+ if (entry.icon !== void 0) {
987
+ let t1;
988
+ if ($[0] !== entry.icon) {
989
+ t1 = iconNodeOf(entry.icon);
990
+ $[0] = entry.icon;
991
+ $[1] = t1;
992
+ } else t1 = $[1];
993
+ let t2;
994
+ if ($[2] !== t1) {
995
+ t2 = /* @__PURE__ */ jsx(Icon, {
996
+ "aria-hidden": true,
997
+ iconNode: t1
998
+ });
999
+ $[2] = t1;
1000
+ $[3] = t2;
1001
+ } else t2 = $[3];
1002
+ return t2;
1003
+ }
1004
+ if (!marked) return null;
1005
+ let t1;
1006
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
1007
+ t1 = /* @__PURE__ */ jsx(Avatar.Fallback, {});
1008
+ $[4] = t1;
1009
+ } else t1 = $[4];
1010
+ let t2;
1011
+ if ($[5] !== entry.label) {
1012
+ t2 = /* @__PURE__ */ jsx(NavList.Mark, { children: /* @__PURE__ */ jsx(Avatar.Root, {
1013
+ name: entry.label,
1014
+ shape: "rounded",
1015
+ size: "2xs",
1016
+ children: t1
1017
+ }) });
1018
+ $[5] = entry.label;
1019
+ $[6] = t2;
1020
+ } else t2 = $[6];
1021
+ return t2;
1022
+ }
1023
+ //#endregion
1024
+ //#region src/app/nested.ts
1025
+ /**
1026
+ * Returns true for an entry whose route's parent the menu lists.
1027
+ */
1028
+ function isNested(entry, listed) {
1029
+ return entry.parent !== void 0 && listed.has(entry.parent);
1030
+ }
1031
+ /**
1032
+ * Returns the entries of a menu whose routes' parents the menu does not list, in menu order.
1033
+ */
1034
+ function topOf(entries) {
1035
+ const listed = new Set(entries.map(({ routeId }) => routeId));
1036
+ return entries.filter((entry) => !isNested(entry, listed));
1037
+ }
1038
+ /**
1039
+ * Returns a menu's entries as a tree: each entry under the entry of its route's parent where the
1040
+ * menu lists that parent, and at the top level otherwise.
1041
+ *
1042
+ * @remarks
1043
+ * Every level keeps the menu's order.
1044
+ */
1045
+ function nestedOf(entries) {
1046
+ /**
1047
+ * Returns the entries whose routes nest under a route, each with its own children.
1048
+ */
1049
+ const under = (routeId) => entries.filter(({ parent }) => parent === routeId).map((entry) => ({
1050
+ children: under(entry.routeId),
1051
+ entry
1052
+ }));
1053
+ return topOf(entries).map((entry) => ({
1054
+ children: under(entry.routeId),
1055
+ entry
1056
+ }));
1057
+ }
1058
+ //#endregion
1059
+ //#region src/app/sections.ts
1060
+ /**
1061
+ * Reads the sections of the main menu and the section the page on screen belongs to.
1062
+ */
1063
+ /**
1064
+ * Returns true where an address is an entry's own address or an address below it.
1065
+ *
1066
+ * @param href - The entry's address.
1067
+ * @param pathname - The address on screen.
1068
+ */
1069
+ function isWithin(href, pathname) {
1070
+ return pathname === href || pathname.startsWith(href.endsWith("/") ? href : `${href}/`);
1071
+ }
1072
+ /**
1073
+ * Returns the section a page belongs to: the section whose address is the longest prefix of the
1074
+ * page's address, else the first section of the page's plugin.
1075
+ *
1076
+ * @param sections - The sections, in menu order.
1077
+ * @param pathname - The page's address.
1078
+ * @param plugin - Id of the plugin that declares the page's route. Absent on a page no plugin
1079
+ * declares.
1080
+ */
1081
+ function currentOf(sections, pathname, plugin) {
1082
+ return sections.filter(({ href }) => isWithin(href, pathname)).toSorted((one, other) => other.href.length - one.href.length)[0] ?? sections.find((section) => section.plugin === plugin);
1083
+ }
1084
+ /**
1085
+ * Returns the main menu's entries, its sections and the current section, and renders again when
1086
+ * the address or an entry changes.
1087
+ *
1088
+ * @remarks
1089
+ * A settings page belongs to the plugin that declares it, so a section's settings pages keep the
1090
+ * section current.
1091
+ */
1092
+ function useSections() {
1093
+ const $ = c(5);
1094
+ const entries = useNavigation();
1095
+ let t0;
1096
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
1097
+ t0 = { select: _temp$1 };
1098
+ $[0] = t0;
1099
+ } else t0 = $[0];
1100
+ const pathname = useLocation(t0);
1101
+ const routeId = useDeclaredRoute()?.id;
1102
+ const plugin = useResolvedProduct().routes.find((t1) => {
1103
+ const { id } = t1;
1104
+ return id === routeId;
1105
+ })?.plugin;
1106
+ const sections = topOf(entries);
1107
+ const t2 = currentOf(sections, pathname, plugin);
1108
+ let t3;
1109
+ if ($[1] !== entries || $[2] !== sections || $[3] !== t2) {
1110
+ t3 = {
1111
+ current: t2,
1112
+ entries,
1113
+ sections
1114
+ };
1115
+ $[1] = entries;
1116
+ $[2] = sections;
1117
+ $[3] = t2;
1118
+ $[4] = t3;
1119
+ } else t3 = $[4];
1120
+ return t3;
1121
+ }
1122
+ function _temp$1(location) {
1123
+ return location.pathname;
1124
+ }
1125
+ //#endregion
1126
+ //#region src/app/entry-row.tsx
1127
+ /**
1128
+ * Renders a row's link as the router's link, current on its page.
1129
+ */
1130
+ const EntryLink = createLink(NavList.Link);
1131
+ /**
1132
+ * Renders the entry's link as a row, or a branch that opens the entries nested under it.
1133
+ *
1134
+ * @remarks
1135
+ * A branch's trigger names the entry, and its first row opens the entry's own page, which is
1136
+ * current on that page alone. A branch starts open while the address is inside the entry. A
1137
+ * nested row renders its icon and no initials. A link names itself in a tooltip while its list is
1138
+ * collapsed to a rail. The router's link passes its children to the element as one list, so the
1139
+ * mark and the text are one fragment, which adds no element between the link and them.
1140
+ * @returns The `li` element of the row or the branch.
1141
+ */
1142
+ function EntryRow(t0) {
1143
+ const $ = c(40);
1144
+ const { marked, nested } = t0;
1145
+ const { children, entry } = nested;
1146
+ let t1;
1147
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
1148
+ t1 = { select: _temp };
1149
+ $[0] = t1;
1150
+ } else t1 = $[0];
1151
+ const pathname = useLocation(t1);
1152
+ if (children.length === 0) {
1153
+ let t2;
1154
+ if ($[1] !== entry || $[2] !== marked) {
1155
+ t2 = /* @__PURE__ */ jsx(EntryIcon, {
1156
+ entry,
1157
+ marked
1158
+ });
1159
+ $[1] = entry;
1160
+ $[2] = marked;
1161
+ $[3] = t2;
1162
+ } else t2 = $[3];
1163
+ let t3;
1164
+ if ($[4] !== entry.label) {
1165
+ t3 = /* @__PURE__ */ jsx("span", { children: entry.label });
1166
+ $[4] = entry.label;
1167
+ $[5] = t3;
1168
+ } else t3 = $[5];
1169
+ let t4;
1170
+ if ($[6] !== t2 || $[7] !== t3) {
1171
+ t4 = /* @__PURE__ */ jsxs(Fragment, { children: [t2, t3] });
1172
+ $[6] = t2;
1173
+ $[7] = t3;
1174
+ $[8] = t4;
1175
+ } else t4 = $[8];
1176
+ let t5;
1177
+ if ($[9] !== entry.href || $[10] !== entry.label || $[11] !== t4) {
1178
+ t5 = /* @__PURE__ */ jsx(NavList.Item, { children: /* @__PURE__ */ jsx(EntryLink, {
1179
+ to: entry.href,
1180
+ tooltip: entry.label,
1181
+ children: t4
1182
+ }) });
1183
+ $[9] = entry.href;
1184
+ $[10] = entry.label;
1185
+ $[11] = t4;
1186
+ $[12] = t5;
1187
+ } else t5 = $[12];
1188
+ return t5;
1189
+ }
1190
+ let t2;
1191
+ if ($[13] !== entry.href || $[14] !== pathname) {
1192
+ t2 = isWithin(entry.href, pathname);
1193
+ $[13] = entry.href;
1194
+ $[14] = pathname;
1195
+ $[15] = t2;
1196
+ } else t2 = $[15];
1197
+ let t3;
1198
+ if ($[16] !== entry || $[17] !== marked) {
1199
+ t3 = /* @__PURE__ */ jsx(EntryIcon, {
1200
+ entry,
1201
+ marked
1202
+ });
1203
+ $[16] = entry;
1204
+ $[17] = marked;
1205
+ $[18] = t3;
1206
+ } else t3 = $[18];
1207
+ let t4;
1208
+ if ($[19] !== entry.label) {
1209
+ t4 = /* @__PURE__ */ jsx("span", { children: entry.label });
1210
+ $[19] = entry.label;
1211
+ $[20] = t4;
1212
+ } else t4 = $[20];
1213
+ let t5;
1214
+ if ($[21] === Symbol.for("react.memo_cache_sentinel")) {
1215
+ t5 = /* @__PURE__ */ jsx(NavList.Indicator, { children: /* @__PURE__ */ jsx(ChevronRightIcon, {
1216
+ "aria-hidden": true,
1217
+ size: "1em"
1218
+ }) });
1219
+ $[21] = t5;
1220
+ } else t5 = $[21];
1221
+ let t6;
1222
+ if ($[22] !== t3 || $[23] !== t4) {
1223
+ t6 = /* @__PURE__ */ jsxs(NavList.Trigger, { children: [
1224
+ t3,
1225
+ t4,
1226
+ t5
1227
+ ] });
1228
+ $[22] = t3;
1229
+ $[23] = t4;
1230
+ $[24] = t6;
1231
+ } else t6 = $[24];
1232
+ let t7;
1233
+ if ($[25] === Symbol.for("react.memo_cache_sentinel")) {
1234
+ t7 = { exact: true };
1235
+ $[25] = t7;
1236
+ } else t7 = $[25];
1237
+ let t8;
1238
+ if ($[26] !== entry.label) {
1239
+ t8 = /* @__PURE__ */ jsx("span", { children: entry.label });
1240
+ $[26] = entry.label;
1241
+ $[27] = t8;
1242
+ } else t8 = $[27];
1243
+ let t9;
1244
+ if ($[28] !== entry.href || $[29] !== t8) {
1245
+ t9 = /* @__PURE__ */ jsx(NavList.Item, { children: /* @__PURE__ */ jsx(EntryLink, {
1246
+ activeOptions: t7,
1247
+ to: entry.href,
1248
+ children: t8
1249
+ }) });
1250
+ $[28] = entry.href;
1251
+ $[29] = t8;
1252
+ $[30] = t9;
1253
+ } else t9 = $[30];
1254
+ let t10;
1255
+ if ($[31] !== children) {
1256
+ t10 = children.map(_temp2);
1257
+ $[31] = children;
1258
+ $[32] = t10;
1259
+ } else t10 = $[32];
1260
+ let t11;
1261
+ if ($[33] !== t10 || $[34] !== t9) {
1262
+ t11 = /* @__PURE__ */ jsxs(NavList.Content, { children: [t9, t10] });
1263
+ $[33] = t10;
1264
+ $[34] = t9;
1265
+ $[35] = t11;
1266
+ } else t11 = $[35];
1267
+ let t12;
1268
+ if ($[36] !== t11 || $[37] !== t2 || $[38] !== t6) {
1269
+ t12 = /* @__PURE__ */ jsxs(NavList.Branch, {
1270
+ defaultOpen: t2,
1271
+ children: [t6, t11]
1272
+ });
1273
+ $[36] = t11;
1274
+ $[37] = t2;
1275
+ $[38] = t6;
1276
+ $[39] = t12;
1277
+ } else t12 = $[39];
1278
+ return t12;
1279
+ }
1280
+ function _temp2(child) {
1281
+ return /* @__PURE__ */ jsx(EntryRow, {
1282
+ marked: false,
1283
+ nested: child
1284
+ }, child.entry.routeId);
1285
+ }
1286
+ function _temp(location) {
1287
+ return location.pathname;
1288
+ }
1289
+ //#endregion
1290
+ //#region src/app/menu-block.tsx
1291
+ /**
1292
+ * Renders the menu's entries the person may open in a nav block, or nothing where it lists none.
1293
+ *
1294
+ * @returns The `nav` element, or nothing.
1295
+ */
1296
+ function MenuBlock(t0) {
1297
+ const $ = c(22);
1298
+ const { label, marked, menu, plugin } = t0;
1299
+ const t1 = useNavigation(menu);
1300
+ let T0;
1301
+ let T1;
1302
+ let t2;
1303
+ let t3;
1304
+ let t4;
1305
+ if ($[0] !== label || $[1] !== marked || $[2] !== plugin || $[3] !== t1) {
1306
+ t4 = Symbol.for("react.early_return_sentinel");
1307
+ bb0: {
1308
+ let t5;
1309
+ if ($[9] !== plugin) {
1310
+ t5 = (entry) => plugin === void 0 || entry.plugin === plugin;
1311
+ $[9] = plugin;
1312
+ $[10] = t5;
1313
+ } else t5 = $[10];
1314
+ const entries = t1.filter(t5);
1315
+ if (entries.length === 0) {
1316
+ t4 = null;
1317
+ break bb0;
1318
+ }
1319
+ T1 = Sidebar.Nav;
1320
+ if ($[11] !== label) {
1321
+ t3 = /* @__PURE__ */ jsx(Sidebar.NavLabel, { children: label });
1322
+ $[11] = label;
1323
+ $[12] = t3;
1324
+ } else t3 = $[12];
1325
+ T0 = NavList.Root;
1326
+ let t6;
1327
+ if ($[13] !== marked) {
1328
+ t6 = (nested) => /* @__PURE__ */ jsx(EntryRow, {
1329
+ marked,
1330
+ nested
1331
+ }, nested.entry.routeId);
1332
+ $[13] = marked;
1333
+ $[14] = t6;
1334
+ } else t6 = $[14];
1335
+ t2 = nestedOf(entries).map(t6);
1336
+ }
1337
+ $[0] = label;
1338
+ $[1] = marked;
1339
+ $[2] = plugin;
1340
+ $[3] = t1;
1341
+ $[4] = T0;
1342
+ $[5] = T1;
1343
+ $[6] = t2;
1344
+ $[7] = t3;
1345
+ $[8] = t4;
1346
+ } else {
1347
+ T0 = $[4];
1348
+ T1 = $[5];
1349
+ t2 = $[6];
1350
+ t3 = $[7];
1351
+ t4 = $[8];
1352
+ }
1353
+ if (t4 !== Symbol.for("react.early_return_sentinel")) return t4;
1354
+ let t5;
1355
+ if ($[15] !== T0 || $[16] !== t2) {
1356
+ t5 = /* @__PURE__ */ jsx(T0, { children: t2 });
1357
+ $[15] = T0;
1358
+ $[16] = t2;
1359
+ $[17] = t5;
1360
+ } else t5 = $[17];
1361
+ let t6;
1362
+ if ($[18] !== T1 || $[19] !== t3 || $[20] !== t5) {
1363
+ t6 = /* @__PURE__ */ jsxs(T1, { children: [t3, t5] });
1364
+ $[18] = T1;
1365
+ $[19] = t3;
1366
+ $[20] = t5;
1367
+ $[21] = t6;
1368
+ } else t6 = $[21];
1369
+ return t6;
1370
+ }
1371
+ //#endregion
1372
+ //#region src/app/section-row.tsx
1373
+ /**
1374
+ * Renders the section's link with its icon or initials, current where the page belongs to the
1375
+ * section.
1376
+ *
1377
+ * @remarks
1378
+ * The link is current on every page of the section's plugin that no other section contains, such
1379
+ * as its settings pages, so it reads the frame's current section and not the router's match. The
1380
+ * router's link props open the section without a reload and leave a press with a modifier key to
1381
+ * the browser. A list collapsed to a rail names the link in a tooltip.
1382
+ * @returns The `li` element of the row.
1383
+ */
1384
+ function SectionRow(t0) {
1385
+ const $ = c(13);
1386
+ const { current, section } = t0;
1387
+ let t1;
1388
+ if ($[0] !== section.href) {
1389
+ t1 = { to: section.href };
1390
+ $[0] = section.href;
1391
+ $[1] = t1;
1392
+ } else t1 = $[1];
1393
+ const { href: t2, onClick } = useLinkProps(t1);
1394
+ const href = t2 === void 0 ? "" : t2;
1395
+ const t3 = current ? "page" : void 0;
1396
+ let t4;
1397
+ if ($[2] !== section) {
1398
+ t4 = /* @__PURE__ */ jsx(EntryIcon, {
1399
+ entry: section,
1400
+ marked: true
1401
+ });
1402
+ $[2] = section;
1403
+ $[3] = t4;
1404
+ } else t4 = $[3];
1405
+ let t5;
1406
+ if ($[4] !== section.label) {
1407
+ t5 = /* @__PURE__ */ jsx("span", { children: section.label });
1408
+ $[4] = section.label;
1409
+ $[5] = t5;
1410
+ } else t5 = $[5];
1411
+ let t6;
1412
+ if ($[6] !== href || $[7] !== onClick || $[8] !== section.label || $[9] !== t3 || $[10] !== t4 || $[11] !== t5) {
1413
+ t6 = /* @__PURE__ */ jsx(NavList.Item, { children: /* @__PURE__ */ jsxs(NavList.Link, {
1414
+ "aria-current": t3,
1415
+ href,
1416
+ onClick,
1417
+ tooltip: section.label,
1418
+ children: [t4, t5]
1419
+ }) });
1420
+ $[6] = href;
1421
+ $[7] = onClick;
1422
+ $[8] = section.label;
1423
+ $[9] = t3;
1424
+ $[10] = t4;
1425
+ $[11] = t5;
1426
+ $[12] = t6;
1427
+ } else t6 = $[12];
1428
+ return t6;
1429
+ }
1430
+ //#endregion
1431
+ //#region src/app/rail.tsx
1432
+ /**
1433
+ * The rail's width where its options state none: the theme's rail.
1434
+ */
1435
+ const RAIL_WIDTH = "var(--sizes-rail)";
1436
+ /**
1437
+ * Renders the rail as the shell's start panel named `rail`, with an iconic sidebar of the
1438
+ * sections.
1439
+ *
1440
+ * @remarks
1441
+ * Each section is a square with its icon or initials, named in a tooltip, and the current one is
1442
+ * marked. Picking a section opens its first page, and the sidebar follows the address. The rail
1443
+ * keeps the person's choice of its open state and width.
1444
+ * @returns The panel, and the strip on its edge where its options keep one.
1445
+ */
1446
+ function FrameRail(t0) {
1447
+ const $ = c(34);
1448
+ const { brand, current, logo, options, sections } = t0;
1449
+ const { t } = useTranslation("host");
1450
+ const choice = usePanelChoice("rail", options);
1451
+ let t1;
1452
+ if ($[0] !== options.mode) {
1453
+ t1 = modeAttributes(options.mode);
1454
+ $[0] = options.mode;
1455
+ $[1] = t1;
1456
+ } else t1 = $[1];
1457
+ const mode = t1;
1458
+ let t2;
1459
+ if ($[2] !== options) {
1460
+ t2 = panelPropsOf(options);
1461
+ $[2] = options;
1462
+ $[3] = t2;
1463
+ } else t2 = $[3];
1464
+ const t3 = options.width ?? RAIL_WIDTH;
1465
+ let t4;
1466
+ if ($[4] !== brand || $[5] !== logo) {
1467
+ t4 = brand ? /* @__PURE__ */ jsx(Sidebar.Header, { children: /* @__PURE__ */ jsx(FrameBrand, {
1468
+ compact: true,
1469
+ logo
1470
+ }) }) : null;
1471
+ $[4] = brand;
1472
+ $[5] = logo;
1473
+ $[6] = t4;
1474
+ } else t4 = $[6];
1475
+ let t5;
1476
+ if ($[7] !== t) {
1477
+ t5 = t("frame.sections");
1478
+ $[7] = t;
1479
+ $[8] = t5;
1480
+ } else t5 = $[8];
1481
+ let t6;
1482
+ if ($[9] !== current || $[10] !== sections) {
1483
+ let t7;
1484
+ if ($[12] !== current) {
1485
+ t7 = (section) => /* @__PURE__ */ jsx(SectionRow, {
1486
+ current: section === current,
1487
+ section
1488
+ }, section.routeId);
1489
+ $[12] = current;
1490
+ $[13] = t7;
1491
+ } else t7 = $[13];
1492
+ t6 = sections.map(t7);
1493
+ $[9] = current;
1494
+ $[10] = sections;
1495
+ $[11] = t6;
1496
+ } else t6 = $[11];
1497
+ let t7;
1498
+ if ($[14] !== t6) {
1499
+ t7 = /* @__PURE__ */ jsx(NavList.Root, { children: t6 });
1500
+ $[14] = t6;
1501
+ $[15] = t7;
1502
+ } else t7 = $[15];
1503
+ let t8;
1504
+ if ($[16] !== t5 || $[17] !== t7) {
1505
+ t8 = /* @__PURE__ */ jsx(Sidebar.Content, { children: /* @__PURE__ */ jsx(Sidebar.Nav, {
1506
+ "aria-label": t5,
1507
+ children: t7
1508
+ }) });
1509
+ $[16] = t5;
1510
+ $[17] = t7;
1511
+ $[18] = t8;
1512
+ } else t8 = $[18];
1513
+ let t9;
1514
+ if ($[19] !== t4 || $[20] !== t8) {
1515
+ t9 = /* @__PURE__ */ jsxs(Sidebar.Root, {
1516
+ iconic: true,
1517
+ children: [t4, t8]
1518
+ });
1519
+ $[19] = t4;
1520
+ $[20] = t8;
1521
+ $[21] = t9;
1522
+ } else t9 = $[21];
1523
+ let t10;
1524
+ if ($[22] !== choice || $[23] !== mode || $[24] !== t2 || $[25] !== t3 || $[26] !== t9) {
1525
+ t10 = /* @__PURE__ */ jsx(AppShell.Navbar, {
1526
+ ...t2,
1527
+ ...choice,
1528
+ ...mode,
1529
+ name: "rail",
1530
+ width: t3,
1531
+ children: t9
1532
+ });
1533
+ $[22] = choice;
1534
+ $[23] = mode;
1535
+ $[24] = t2;
1536
+ $[25] = t3;
1537
+ $[26] = t9;
1538
+ $[27] = t10;
1539
+ } else t10 = $[27];
1540
+ let t11;
1541
+ if ($[28] !== options.edge || $[29] !== t) {
1542
+ t11 = options.edge ? /* @__PURE__ */ jsx(AppShell.Rail, {
1543
+ closeLabel: t("frame.edge.close.rail"),
1544
+ openLabel: t("frame.edge.open.rail"),
1545
+ panel: "rail",
1546
+ resizeLabel: t("frame.edge.resize.rail")
1547
+ }) : null;
1548
+ $[28] = options.edge;
1549
+ $[29] = t;
1550
+ $[30] = t11;
1551
+ } else t11 = $[30];
1552
+ let t12;
1553
+ if ($[31] !== t10 || $[32] !== t11) {
1554
+ t12 = /* @__PURE__ */ jsxs(Fragment, { children: [t10, t11] });
1555
+ $[31] = t10;
1556
+ $[32] = t11;
1557
+ $[33] = t12;
1558
+ } else t12 = $[33];
1559
+ return t12;
1560
+ }
1561
+ //#endregion
1562
+ //#region src/app/section-nav.tsx
1563
+ /**
1564
+ * Renders a block per menu the plugin declares, the `navigation` region with the plugin's
1565
+ * extensions alone, and a block of the plugin's settings pages.
1566
+ *
1567
+ * @remarks
1568
+ * Each menu's label is a key of its plugin's catalogue. A menu that lists no page the person may
1569
+ * open renders nothing.
1570
+ * @returns The blocks, in that order.
1571
+ */
1572
+ function SectionNavigation(t0) {
1573
+ const $ = c(17);
1574
+ const { marked, plugin, settings } = t0;
1575
+ const product = useResolvedProduct();
1576
+ const listed = useListed();
1577
+ const { i18n, t } = useTranslation("host");
1578
+ let t1;
1579
+ if ($[0] !== i18n || $[1] !== listed || $[2] !== marked || $[3] !== plugin || $[4] !== product) {
1580
+ const words = pluginWordsOf(i18n);
1581
+ t1 = menusOf(product, listed, plugin).map((menu) => /* @__PURE__ */ jsx(MenuBlock, {
1582
+ label: words.t(menu.plugin, menu.label),
1583
+ marked,
1584
+ menu: {
1585
+ id: menu.id,
1586
+ kind: "menu"
1587
+ }
1588
+ }, menu.id));
1589
+ $[0] = i18n;
1590
+ $[1] = listed;
1591
+ $[2] = marked;
1592
+ $[3] = plugin;
1593
+ $[4] = product;
1594
+ $[5] = t1;
1595
+ } else t1 = $[5];
1596
+ let t2;
1597
+ if ($[6] !== plugin) {
1598
+ t2 = /* @__PURE__ */ jsx(Slot, {
1599
+ plugin,
1600
+ slot: hostContract.slots.navigation
1601
+ });
1602
+ $[6] = plugin;
1603
+ $[7] = t2;
1604
+ } else t2 = $[7];
1605
+ let t3;
1606
+ if ($[8] !== marked || $[9] !== plugin || $[10] !== settings || $[11] !== t) {
1607
+ t3 = settings ? /* @__PURE__ */ jsx(MenuBlock, {
1608
+ label: t("settings.title"),
1609
+ marked,
1610
+ menu: hostContract.menus.settings,
1611
+ plugin
1612
+ }) : null;
1613
+ $[8] = marked;
1614
+ $[9] = plugin;
1615
+ $[10] = settings;
1616
+ $[11] = t;
1617
+ $[12] = t3;
1618
+ } else t3 = $[12];
1619
+ let t4;
1620
+ if ($[13] !== t1 || $[14] !== t2 || $[15] !== t3) {
1621
+ t4 = /* @__PURE__ */ jsxs(Fragment, { children: [
1622
+ t1,
1623
+ t2,
1624
+ t3
1625
+ ] });
1626
+ $[13] = t1;
1627
+ $[14] = t2;
1628
+ $[15] = t3;
1629
+ $[16] = t4;
1630
+ } else t4 = $[16];
1631
+ return t4;
1632
+ }
1633
+ //#endregion
1634
+ //#region src/app/sheet-sections.tsx
1635
+ /**
1636
+ * Renders a block of the sections while the sidebar lies over the page, and nothing beside it.
1637
+ *
1638
+ * @remarks
1639
+ * The rail hides below its fold, and a frame with more sections than a dock takes lists them in
1640
+ * the sheet, as a sidebar block above the section's navigation.
1641
+ * @returns The `nav` element, or nothing.
1642
+ */
1643
+ function SheetSections(t0) {
1644
+ const $ = c(14);
1645
+ const { sections } = t0;
1646
+ const { t } = useTranslation("host");
1647
+ const { overlaid } = AppShell.useNearestPanel();
1648
+ if (!overlaid) return null;
1649
+ let t1;
1650
+ if ($[0] !== t) {
1651
+ t1 = t("frame.sections");
1652
+ $[0] = t;
1653
+ $[1] = t1;
1654
+ } else t1 = $[1];
1655
+ let t2;
1656
+ if ($[2] !== t1) {
1657
+ t2 = /* @__PURE__ */ jsx(Sidebar.NavLabel, { children: t1 });
1658
+ $[2] = t1;
1659
+ $[3] = t2;
1660
+ } else t2 = $[3];
1661
+ let t3;
1662
+ if ($[4] !== sections.current || $[5] !== sections.sections) {
1663
+ let t4;
1664
+ if ($[7] !== sections.current) {
1665
+ t4 = (section) => /* @__PURE__ */ jsx(SectionRow, {
1666
+ current: section === sections.current,
1667
+ section
1668
+ }, section.routeId);
1669
+ $[7] = sections.current;
1670
+ $[8] = t4;
1671
+ } else t4 = $[8];
1672
+ t3 = sections.sections.map(t4);
1673
+ $[4] = sections.current;
1674
+ $[5] = sections.sections;
1675
+ $[6] = t3;
1676
+ } else t3 = $[6];
1677
+ let t4;
1678
+ if ($[9] !== t3) {
1679
+ t4 = /* @__PURE__ */ jsx(NavList.Root, { children: t3 });
1680
+ $[9] = t3;
1681
+ $[10] = t4;
1682
+ } else t4 = $[10];
1683
+ let t5;
1684
+ if ($[11] !== t2 || $[12] !== t4) {
1685
+ t5 = /* @__PURE__ */ jsxs(Sidebar.Nav, { children: [t2, t4] });
1686
+ $[11] = t2;
1687
+ $[12] = t4;
1688
+ $[13] = t5;
1689
+ } else t5 = $[13];
1690
+ return t5;
1691
+ }
1692
+ //#endregion
1693
+ //#region src/app/sidebar-header.tsx
1694
+ /**
1695
+ * Renders the sidebar's header, or nothing where it has neither the brand nor a search.
1696
+ *
1697
+ * @remarks
1698
+ * The search filters the rows of every block, and its shortcut moves focus to the field with the
1699
+ * platform's modifier pressed.
1700
+ * @returns The header, or nothing.
1701
+ */
1702
+ function SidebarHeader(t0) {
1703
+ const $ = c(9);
1704
+ const { brand, logo, search } = t0;
1705
+ const { t } = useTranslation("host");
1706
+ if (!brand && search === false) return null;
1707
+ let t1;
1708
+ if ($[0] !== brand || $[1] !== logo) {
1709
+ t1 = brand ? /* @__PURE__ */ jsx(FrameBrand, { logo }) : null;
1710
+ $[0] = brand;
1711
+ $[1] = logo;
1712
+ $[2] = t1;
1713
+ } else t1 = $[2];
1714
+ let t2;
1715
+ if ($[3] !== search || $[4] !== t) {
1716
+ t2 = search === false ? null : /* @__PURE__ */ jsx(Sidebar.Search, {
1717
+ "aria-label": t("frame.find"),
1718
+ clearIndicator: /* @__PURE__ */ jsx(XIcon, {}),
1719
+ clearLabel: t("frame.clear"),
1720
+ placeholder: t("frame.find"),
1721
+ searchIndicator: /* @__PURE__ */ jsx(SearchIcon, {}),
1722
+ shortcut: search.shortcut
1723
+ });
1724
+ $[3] = search;
1725
+ $[4] = t;
1726
+ $[5] = t2;
1727
+ } else t2 = $[5];
1728
+ let t3;
1729
+ if ($[6] !== t1 || $[7] !== t2) {
1730
+ t3 = /* @__PURE__ */ jsxs(Sidebar.Header, { children: [t1, t2] });
1731
+ $[6] = t1;
1732
+ $[7] = t2;
1733
+ $[8] = t3;
1734
+ } else t3 = $[8];
1735
+ return t3;
1736
+ }
1737
+ //#endregion
1738
+ //#region src/app/sidebar.tsx
1739
+ /**
1740
+ * Renders the sidebar as the shell's start panel named `navigation`.
1741
+ *
1742
+ * @remarks
1743
+ * The sidebar keeps the person's choice of its open state and width. The sidebar's root is the
1744
+ * target of the skip link to the navigation. A sidebar shown only as a sheet is always closed
1745
+ * beside the page. It has neither a shortcut nor a strip on its edge.
1746
+ * @returns The panel, and the strip on its edge where its options keep one.
1747
+ */
1748
+ function FrameSidebar(props) {
1749
+ const $ = c(38);
1750
+ const { brand, children, logo, options, shown, userMenu } = props;
1751
+ const { t } = useTranslation("host");
1752
+ const choice = usePanelChoice("sidebar", options);
1753
+ let t0;
1754
+ if ($[0] !== options.mode) {
1755
+ t0 = modeAttributes(options.mode);
1756
+ $[0] = options.mode;
1757
+ $[1] = t0;
1758
+ } else t0 = $[1];
1759
+ const mode = t0;
1760
+ let t1;
1761
+ if ($[2] !== options) {
1762
+ t1 = panelPropsOf(options);
1763
+ $[2] = options;
1764
+ $[3] = t1;
1765
+ } else t1 = $[3];
1766
+ const panel = t1;
1767
+ let t2;
1768
+ if ($[4] !== options.search) {
1769
+ t2 = options.search === true ? {} : options.search;
1770
+ $[4] = options.search;
1771
+ $[5] = t2;
1772
+ } else t2 = $[5];
1773
+ const search = t2;
1774
+ const t3 = shown && choice.open;
1775
+ const t4 = shown ? panel.shortcut : void 0;
1776
+ let t5;
1777
+ if ($[6] !== brand || $[7] !== logo || $[8] !== search) {
1778
+ t5 = /* @__PURE__ */ jsx(SidebarHeader, {
1779
+ brand,
1780
+ logo,
1781
+ search
1782
+ });
1783
+ $[6] = brand;
1784
+ $[7] = logo;
1785
+ $[8] = search;
1786
+ $[9] = t5;
1787
+ } else t5 = $[9];
1788
+ let t6;
1789
+ if ($[10] !== search || $[11] !== t) {
1790
+ t6 = search === false ? null : /* @__PURE__ */ jsx(Sidebar.Empty, { children: t("frame.empty") });
1791
+ $[10] = search;
1792
+ $[11] = t;
1793
+ $[12] = t6;
1794
+ } else t6 = $[12];
1795
+ let t7;
1796
+ if ($[13] !== children || $[14] !== t6) {
1797
+ t7 = /* @__PURE__ */ jsxs(Sidebar.Content, { children: [children, t6] });
1798
+ $[13] = children;
1799
+ $[14] = t6;
1800
+ $[15] = t7;
1801
+ } else t7 = $[15];
1802
+ let t8;
1803
+ if ($[16] !== userMenu) {
1804
+ t8 = userMenu ? /* @__PURE__ */ jsx(Sidebar.Footer, { children: /* @__PURE__ */ jsx(Slot, { slot: hostContract.slots.userMenu }) }) : null;
1805
+ $[16] = userMenu;
1806
+ $[17] = t8;
1807
+ } else t8 = $[17];
1808
+ let t9;
1809
+ if ($[18] !== options.look || $[19] !== options.size || $[20] !== t5 || $[21] !== t7 || $[22] !== t8) {
1810
+ t9 = /* @__PURE__ */ jsxs(Sidebar.Root, {
1811
+ id: NAVIGATION,
1812
+ size: options.size,
1813
+ tabIndex: -1,
1814
+ variant: options.look,
1815
+ children: [
1816
+ t5,
1817
+ t7,
1818
+ t8
1819
+ ]
1820
+ });
1821
+ $[18] = options.look;
1822
+ $[19] = options.size;
1823
+ $[20] = t5;
1824
+ $[21] = t7;
1825
+ $[22] = t8;
1826
+ $[23] = t9;
1827
+ } else t9 = $[23];
1828
+ let t10;
1829
+ if ($[24] !== choice || $[25] !== mode || $[26] !== panel || $[27] !== t3 || $[28] !== t4 || $[29] !== t9) {
1830
+ t10 = /* @__PURE__ */ jsx(AppShell.Navbar, {
1831
+ ...panel,
1832
+ ...choice,
1833
+ ...mode,
1834
+ name: "navigation",
1835
+ open: t3,
1836
+ shortcut: t4,
1837
+ children: t9
1838
+ });
1839
+ $[24] = choice;
1840
+ $[25] = mode;
1841
+ $[26] = panel;
1842
+ $[27] = t3;
1843
+ $[28] = t4;
1844
+ $[29] = t9;
1845
+ $[30] = t10;
1846
+ } else t10 = $[30];
1847
+ let t11;
1848
+ if ($[31] !== options.edge || $[32] !== shown || $[33] !== t) {
1849
+ t11 = options.edge && shown ? /* @__PURE__ */ jsx(AppShell.Rail, {
1850
+ closeLabel: t("frame.edge.close.navigation"),
1851
+ openLabel: t("frame.edge.open.navigation"),
1852
+ panel: "navigation",
1853
+ resizeLabel: t("frame.edge.resize.navigation")
1854
+ }) : null;
1855
+ $[31] = options.edge;
1856
+ $[32] = shown;
1857
+ $[33] = t;
1858
+ $[34] = t11;
1859
+ } else t11 = $[34];
1860
+ let t12;
1861
+ if ($[35] !== t10 || $[36] !== t11) {
1862
+ t12 = /* @__PURE__ */ jsxs(Fragment, { children: [t10, t11] });
1863
+ $[35] = t10;
1864
+ $[36] = t11;
1865
+ $[37] = t12;
1866
+ } else t12 = $[37];
1867
+ return t12;
1868
+ }
1869
+ //#endregion
1870
+ //#region src/app/start-panels.tsx
1871
+ /**
1872
+ * Renders the rail and the sidebar the layout calls for.
1873
+ *
1874
+ * @remarks
1875
+ * The `sidebar` layout's sidebar lists the main menu as its first block, then every plugin's
1876
+ * navigation. The `split` and `rail` layouts' sidebar lists the current section's navigation,
1877
+ * after the sections where its sheet lists them on a narrow page. A top-level entry without an
1878
+ * icon renders its initials in the main menu, and in a sidebar that closes to its icons.
1879
+ */
1880
+ function StartPanels(t0) {
1881
+ const $ = c(20);
1882
+ const { model } = t0;
1883
+ const { frame, parts, sections } = model;
1884
+ const { t } = useTranslation("host");
1885
+ const scoped = frame.layout !== "sidebar";
1886
+ const marked = frame.sidebar.collapse === "icons";
1887
+ let t1;
1888
+ if ($[0] !== frame.bar || $[1] !== frame.rail || $[2] !== parts.brand || $[3] !== parts.rail || $[4] !== sections) {
1889
+ t1 = parts.rail ? /* @__PURE__ */ jsx(FrameRail, {
1890
+ brand: parts.brand === "rail",
1891
+ current: sections.current,
1892
+ logo: frame.bar.logo,
1893
+ options: frame.rail,
1894
+ sections: sections.sections
1895
+ }) : null;
1896
+ $[0] = frame.bar;
1897
+ $[1] = frame.rail;
1898
+ $[2] = parts.brand;
1899
+ $[3] = parts.rail;
1900
+ $[4] = sections;
1901
+ $[5] = t1;
1902
+ } else t1 = $[5];
1903
+ let t2;
1904
+ if ($[6] !== frame.bar || $[7] !== frame.sidebar || $[8] !== marked || $[9] !== parts.brand || $[10] !== parts.sheetSections || $[11] !== parts.sidebar || $[12] !== parts.userMenu || $[13] !== scoped || $[14] !== sections || $[15] !== t) {
1905
+ t2 = parts.sidebar === "none" ? null : /* @__PURE__ */ jsxs(FrameSidebar, {
1906
+ brand: parts.brand === "sidebar",
1907
+ logo: frame.bar.logo,
1908
+ options: frame.sidebar,
1909
+ shown: parts.sidebar === "body",
1910
+ userMenu: parts.userMenu === "sidebar",
1911
+ children: [
1912
+ parts.sheetSections ? /* @__PURE__ */ jsx(SheetSections, { sections }) : null,
1913
+ scoped ? null : /* @__PURE__ */ jsx(MenuBlock, {
1914
+ label: t("frame.menu"),
1915
+ marked: true,
1916
+ menu: hostContract.menus.main
1917
+ }),
1918
+ parts.sidebar === "body" ? /* @__PURE__ */ jsx(SectionNavigation, {
1919
+ marked,
1920
+ plugin: scoped ? sections.current?.plugin : void 0,
1921
+ settings: frame.sidebar.settings
1922
+ }) : null
1923
+ ]
1924
+ });
1925
+ $[6] = frame.bar;
1926
+ $[7] = frame.sidebar;
1927
+ $[8] = marked;
1928
+ $[9] = parts.brand;
1929
+ $[10] = parts.sheetSections;
1930
+ $[11] = parts.sidebar;
1931
+ $[12] = parts.userMenu;
1932
+ $[13] = scoped;
1933
+ $[14] = sections;
1934
+ $[15] = t;
1935
+ $[16] = t2;
1936
+ } else t2 = $[16];
1937
+ let t3;
1938
+ if ($[17] !== t1 || $[18] !== t2) {
1939
+ t3 = /* @__PURE__ */ jsxs(Fragment, { children: [t1, t2] });
1940
+ $[17] = t1;
1941
+ $[18] = t2;
1942
+ $[19] = t3;
1943
+ } else t3 = $[19];
1944
+ return t3;
1945
+ }
1946
+ //#endregion
1947
+ //#region src/app/body.tsx
1948
+ /**
1949
+ * Renders the shell's body around the page the router matched.
1950
+ *
1951
+ * @remarks
1952
+ * The main region is the first skip link's target. With the bar beside the start panels, a pane
1953
+ * contains the bar, the main region and the footer, so the start panels run the full height of
1954
+ * the window. The aside renders before the panel at the end side.
1955
+ */
1956
+ function FrameBody(t0) {
1957
+ const $ = c(19);
1958
+ const { bar, model } = t0;
1959
+ const { frame, parts } = model;
1960
+ let t1;
1961
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
1962
+ t1 = /* @__PURE__ */ jsx(AppShell.Main, {
1963
+ id: MAIN,
1964
+ tabIndex: -1,
1965
+ children: /* @__PURE__ */ jsx(HostContent, {})
1966
+ });
1967
+ $[0] = t1;
1968
+ } else t1 = $[0];
1969
+ const main = t1;
1970
+ let t2;
1971
+ if ($[1] !== model) {
1972
+ t2 = /* @__PURE__ */ jsx(StartPanels, { model });
1973
+ $[1] = model;
1974
+ $[2] = t2;
1975
+ } else t2 = $[2];
1976
+ let t3;
1977
+ if ($[3] !== bar || $[4] !== frame.bar.placement || $[5] !== frame.footer || $[6] !== parts.footer) {
1978
+ t3 = frame.bar.placement === "beside" ? /* @__PURE__ */ jsxs(AppShell.Pane, { children: [
1979
+ /* @__PURE__ */ jsx(FrameBar, { ...bar }),
1980
+ main,
1981
+ parts.footer ? /* @__PURE__ */ jsx(AppShell.Footer, {
1982
+ sticky: frame.footer.sticky,
1983
+ children: /* @__PURE__ */ jsx(Slot, { slot: hostContract.slots.footer })
1984
+ }) : null
1985
+ ] }) : main;
1986
+ $[3] = bar;
1987
+ $[4] = frame.bar.placement;
1988
+ $[5] = frame.footer;
1989
+ $[6] = parts.footer;
1990
+ $[7] = t3;
1991
+ } else t3 = $[7];
1992
+ let t4;
1993
+ if ($[8] !== frame.aside || $[9] !== parts.aside) {
1994
+ t4 = parts.aside ? /* @__PURE__ */ jsx(EndPanel, {
1995
+ name: "aside",
1996
+ options: frame.aside
1997
+ }) : null;
1998
+ $[8] = frame.aside;
1999
+ $[9] = parts.aside;
2000
+ $[10] = t4;
2001
+ } else t4 = $[10];
2002
+ let t5;
2003
+ if ($[11] !== frame.panel || $[12] !== parts.panel) {
2004
+ t5 = parts.panel ? /* @__PURE__ */ jsx(EndPanel, {
2005
+ name: "panel",
2006
+ options: frame.panel
2007
+ }) : null;
2008
+ $[11] = frame.panel;
2009
+ $[12] = parts.panel;
2010
+ $[13] = t5;
2011
+ } else t5 = $[13];
2012
+ let t6;
2013
+ if ($[14] !== t2 || $[15] !== t3 || $[16] !== t4 || $[17] !== t5) {
2014
+ t6 = /* @__PURE__ */ jsxs(AppShell.Body, { children: [
2015
+ t2,
2016
+ t3,
2017
+ t4,
2018
+ t5
2019
+ ] });
2020
+ $[14] = t2;
2021
+ $[15] = t3;
2022
+ $[16] = t4;
2023
+ $[17] = t5;
2024
+ $[18] = t6;
2025
+ } else t6 = $[18];
2026
+ return t6;
2027
+ }
2028
+ //#endregion
2029
+ //#region src/app/dock.tsx
2030
+ /**
2031
+ * Renders the sections as a dock in a footer that pins to the bottom of a narrow window.
2032
+ *
2033
+ * @remarks
2034
+ * The footer renders below the `md` breakpoint alone, where the rail hides, and it is the last
2035
+ * bar of the shell, after the footer region and the status bar.
2036
+ * @returns The `footer` element, or nothing at a width the footer leaves out.
2037
+ */
2038
+ function FrameDock(t0) {
2039
+ const $ = c(12);
2040
+ const { sections } = t0;
2041
+ const { t } = useTranslation("host");
2042
+ let t1;
2043
+ if ($[0] !== t) {
2044
+ t1 = t("frame.sections");
2045
+ $[0] = t;
2046
+ $[1] = t1;
2047
+ } else t1 = $[1];
2048
+ let t2;
2049
+ if ($[2] !== sections.current || $[3] !== sections.sections) {
2050
+ let t3;
2051
+ if ($[5] !== sections.current) {
2052
+ t3 = (section) => /* @__PURE__ */ jsx(SectionRow, {
2053
+ current: section === sections.current,
2054
+ section
2055
+ }, section.routeId);
2056
+ $[5] = sections.current;
2057
+ $[6] = t3;
2058
+ } else t3 = $[6];
2059
+ t2 = sections.sections.map(t3);
2060
+ $[2] = sections.current;
2061
+ $[3] = sections.sections;
2062
+ $[4] = t2;
2063
+ } else t2 = $[4];
2064
+ let t3;
2065
+ if ($[7] !== t2) {
2066
+ t3 = /* @__PURE__ */ jsx(NavList.Root, {
2067
+ variant: "dock",
2068
+ children: t2
2069
+ });
2070
+ $[7] = t2;
2071
+ $[8] = t3;
2072
+ } else t3 = $[8];
2073
+ let t4;
2074
+ if ($[9] !== t1 || $[10] !== t3) {
2075
+ t4 = /* @__PURE__ */ jsx(AppShell.Footer, {
2076
+ sticky: true,
2077
+ when: "narrow",
2078
+ children: /* @__PURE__ */ jsx("nav", {
2079
+ "aria-label": t1,
2080
+ children: t3
2081
+ })
2082
+ });
2083
+ $[9] = t1;
2084
+ $[10] = t3;
2085
+ $[11] = t4;
2086
+ } else t4 = $[11];
2087
+ return t4;
2088
+ }
2089
+ //#endregion
2090
+ //#region src/app/foot.tsx
2091
+ /**
2092
+ * Renders the footer region, the status region and the dock, each while it renders, in that
2093
+ * order, so the dock is the last bar of a phone's window.
2094
+ *
2095
+ * @remarks
2096
+ * The footer renders here while the bar is across the top, and in the pane while the bar is
2097
+ * beside the start panels. The status bar's name is the key the frame states in the product's
2098
+ * catalogue, and the host's word where it states none.
2099
+ * @returns The bars.
2100
+ */
2101
+ function FrameFoot(t0) {
2102
+ const $ = c(17);
2103
+ const { model } = t0;
2104
+ const { frame, parts, sections } = model;
2105
+ const { productId } = useResolvedProduct();
2106
+ const { i18n, t } = useTranslation("host");
2107
+ const { label } = frame.status;
2108
+ let t1;
2109
+ if ($[0] !== frame.bar.placement || $[1] !== frame.footer || $[2] !== parts.footer) {
2110
+ t1 = frame.bar.placement === "across" && parts.footer ? /* @__PURE__ */ jsx(AppShell.Footer, {
2111
+ sticky: frame.footer.sticky,
2112
+ children: /* @__PURE__ */ jsx(Slot, { slot: hostContract.slots.footer })
2113
+ }) : null;
2114
+ $[0] = frame.bar.placement;
2115
+ $[1] = frame.footer;
2116
+ $[2] = parts.footer;
2117
+ $[3] = t1;
2118
+ } else t1 = $[3];
2119
+ let t2;
2120
+ if ($[4] !== i18n || $[5] !== label || $[6] !== parts.status || $[7] !== productId || $[8] !== t) {
2121
+ t2 = parts.status ? /* @__PURE__ */ jsx(AppShell.Status, {
2122
+ label: label === void 0 ? t("frame.status") : pluginWordsOf(i18n).t(productId, label),
2123
+ children: /* @__PURE__ */ jsx(Slot, { slot: hostContract.slots.status })
2124
+ }) : null;
2125
+ $[4] = i18n;
2126
+ $[5] = label;
2127
+ $[6] = parts.status;
2128
+ $[7] = productId;
2129
+ $[8] = t;
2130
+ $[9] = t2;
2131
+ } else t2 = $[9];
2132
+ let t3;
2133
+ if ($[10] !== parts.dock || $[11] !== sections) {
2134
+ t3 = parts.dock ? /* @__PURE__ */ jsx(FrameDock, { sections }) : null;
2135
+ $[10] = parts.dock;
2136
+ $[11] = sections;
2137
+ $[12] = t3;
2138
+ } else t3 = $[12];
2139
+ let t4;
2140
+ if ($[13] !== t1 || $[14] !== t2 || $[15] !== t3) {
2141
+ t4 = /* @__PURE__ */ jsxs(Fragment, { children: [
2142
+ t1,
2143
+ t2,
2144
+ t3
2145
+ ] });
2146
+ $[13] = t1;
2147
+ $[14] = t2;
2148
+ $[15] = t3;
2149
+ $[16] = t4;
2150
+ } else t4 = $[16];
2151
+ return t4;
2152
+ }
2153
+ //#endregion
2154
+ //#region src/app/parts.ts
2155
+ /**
2156
+ * Decides which parts of the frame render for the page on screen.
2157
+ *
2158
+ * @remarks
2159
+ * A region nobody fills renders no part of the shell. A rail and a dock list two sections or
2160
+ * more, and a dock five at most, as a navigation bar takes three to five destinations. In the
2161
+ * `rail` layout without a dock, a narrow window lists the sections in the sidebar's sheet.
2162
+ */
2163
+ /**
2164
+ * The fewest sections a rail or a dock lists.
2165
+ */
2166
+ const FEWEST = 2;
2167
+ /**
2168
+ * The most sections a dock lists.
2169
+ */
2170
+ const MOST = 5;
2171
+ /**
2172
+ * Returns true where the sidebar has a block to list: a menu, an extension in the `navigation`
2173
+ * region, or a settings page.
2174
+ */
2175
+ function listsBlocks(frame, sections, listing) {
2176
+ const { navigation, plugin, product, routes } = listing;
2177
+ const scoped = frame.layout !== "sidebar";
2178
+ if (scoped && plugin === void 0) return false;
2179
+ return navigation || menusOf(product, routes, plugin).length > 0 || frame.sidebar.settings && settingsListed(product, routes, plugin) || !scoped && sections.entries.length > 0;
2180
+ }
2181
+ /**
2182
+ * Returns how the sidebar renders.
2183
+ *
2184
+ * @param frame - The resolved frame.
2185
+ * @param blocks - True where the sidebar has a block to list.
2186
+ * @param sheetSections - True where the sidebar's sheet lists the sections.
2187
+ */
2188
+ function sidebarOf(frame, blocks, sheetSections) {
2189
+ if (frame.layout === "stacked") return "none";
2190
+ if (blocks) return "body";
2191
+ return sheetSections ? "sheet" : "none";
2192
+ }
2193
+ /**
2194
+ * Returns where the brand renders.
2195
+ *
2196
+ * @param frame - The resolved frame.
2197
+ * @param rail - True where the rail renders.
2198
+ * @param sidebar - How the sidebar renders.
2199
+ */
2200
+ function brandOf(frame, rail, sidebar) {
2201
+ if (frame.bar.placement === "across") return "bar";
2202
+ if (rail) return "rail";
2203
+ return sidebar === "body" ? "sidebar" : "bar";
2204
+ }
2205
+ /**
2206
+ * Returns the product's resolved frame.
2207
+ *
2208
+ * @throws {@link Error} Where the product renders its own frame, which the build resolves no
2209
+ * options for.
2210
+ */
2211
+ function useFrame() {
2212
+ const { frame } = useResolvedProduct();
2213
+ if (frame === void 0) throw new Error("ProductFrame renders the frame a product's definition states, and this product renders its own frame.");
2214
+ return frame;
2215
+ }
2216
+ /**
2217
+ * Returns where the `userMenu` region renders: at the foot of a sidebar beside the page where the
2218
+ * frame places it there, and in the bar otherwise.
2219
+ *
2220
+ * @param frame - The resolved frame.
2221
+ * @param sidebar - How the sidebar renders.
2222
+ */
2223
+ function userMenuOf(frame, sidebar) {
2224
+ return frame.sidebar.userMenu === "sidebar" && sidebar === "body" ? "sidebar" : "bar";
2225
+ }
2226
+ /**
2227
+ * Returns the parts of the frame that render for the page on screen, and renders again when a
2228
+ * region fills or empties, a section changes, or a menu lists another page.
2229
+ *
2230
+ * @param frame - The resolved frame.
2231
+ * @param sections - The main menu's sections and the current one.
2232
+ */
2233
+ function useFrameParts(frame, sections) {
2234
+ const $ = c(11);
2235
+ const { slots } = hostContract;
2236
+ const product = useResolvedProduct();
2237
+ const routes = useListed();
2238
+ const plugin = frame.layout === "sidebar" ? void 0 : sections.current?.plugin;
2239
+ const navigation = useSlot(slots.navigation, void 0, plugin).filled;
2240
+ const count = sections.sections.length;
2241
+ const rail = frame.layout === "rail" && count >= FEWEST;
2242
+ const dock = frame.dock && count >= FEWEST && count <= MOST;
2243
+ const sheetSections = rail && !dock;
2244
+ const sidebar = sidebarOf(frame, listsBlocks(frame, sections, {
2245
+ navigation,
2246
+ plugin,
2247
+ product,
2248
+ routes
2249
+ }), sheetSections);
2250
+ const t0 = useSlot(slots.aside);
2251
+ const t1 = t0.filled;
2252
+ const t2 = brandOf(frame, rail, sidebar);
2253
+ const t3 = useSlot(slots.footer);
2254
+ const t4 = t3.filled;
2255
+ const t5 = useSlot(slots.panel);
2256
+ const t6 = t5.filled;
2257
+ const t7 = useSlot(slots.status);
2258
+ const t8 = t7.filled;
2259
+ const t9 = userMenuOf(frame, sidebar);
2260
+ let t10;
2261
+ if ($[0] !== dock || $[1] !== rail || $[2] !== sheetSections || $[3] !== sidebar || $[4] !== t0.filled || $[5] !== t2 || $[6] !== t3.filled || $[7] !== t5.filled || $[8] !== t7.filled || $[9] !== t9) {
2262
+ t10 = {
2263
+ aside: t1,
2264
+ brand: t2,
2265
+ dock,
2266
+ footer: t4,
2267
+ panel: t6,
2268
+ rail,
2269
+ sheetSections,
2270
+ sidebar,
2271
+ status: t8,
2272
+ userMenu: t9
2273
+ };
2274
+ $[0] = dock;
2275
+ $[1] = rail;
2276
+ $[2] = sheetSections;
2277
+ $[3] = sidebar;
2278
+ $[4] = t0.filled;
2279
+ $[5] = t2;
2280
+ $[6] = t3.filled;
2281
+ $[7] = t5.filled;
2282
+ $[8] = t7.filled;
2283
+ $[9] = t9;
2284
+ $[10] = t10;
2285
+ } else t10 = $[10];
2286
+ return t10;
2287
+ }
2288
+ //#endregion
2289
+ //#region src/app/skip-links.tsx
2290
+ /**
2291
+ * Returns true while a panel of the shell renders its content beside the page, where the target of
2292
+ * its skip link takes focus.
2293
+ *
2294
+ * @remarks
2295
+ * Focus cannot move into a panel the frame does not render, a panel the shell hides, a sheet over
2296
+ * the page, or a panel closed to nothing, because each is absent or inert. A panel closed to its
2297
+ * icons keeps its rows in the tab order.
2298
+ * @param name - The panel's name.
2299
+ */
2300
+ function useReachable(name) {
2301
+ const panel = AppShell.useAppShellPanel(name);
2302
+ return panel !== void 0 && !panel.hidden && !panel.overlaid && (panel.open || panel.collapse === "icons");
2303
+ }
2304
+ /**
2305
+ * Renders a skip link per region that focus can reach, hidden until it takes focus.
2306
+ *
2307
+ * @remarks
2308
+ * The first Tab reaches the link to the page, so one key press moves focus past the bar and the
2309
+ * panels. The links to the navigation and the end panels follow in the order the regions render.
2310
+ * A panel publishes its state after its first render, so its link renders from the render after.
2311
+ */
2312
+ function SkipLinks() {
2313
+ const $ = c(18);
2314
+ const { t } = useTranslation("host");
2315
+ const navigation = useReachable("navigation");
2316
+ const aside = useReachable("aside");
2317
+ const panel = useReachable("panel");
2318
+ let t0;
2319
+ if ($[0] !== t) {
2320
+ t0 = t("frame.skip.main");
2321
+ $[0] = t;
2322
+ $[1] = t0;
2323
+ } else t0 = $[1];
2324
+ let t1;
2325
+ if ($[2] !== t0) {
2326
+ t1 = /* @__PURE__ */ jsx(SkipNav.Link, {
2327
+ href: `#${MAIN}`,
2328
+ children: t0
2329
+ });
2330
+ $[2] = t0;
2331
+ $[3] = t1;
2332
+ } else t1 = $[3];
2333
+ let t2;
2334
+ if ($[4] !== navigation || $[5] !== t) {
2335
+ t2 = navigation ? /* @__PURE__ */ jsx(SkipNav.Link, {
2336
+ href: `#${NAVIGATION}`,
2337
+ children: t("frame.skip.navigation")
2338
+ }) : null;
2339
+ $[4] = navigation;
2340
+ $[5] = t;
2341
+ $[6] = t2;
2342
+ } else t2 = $[6];
2343
+ let t3;
2344
+ if ($[7] !== aside || $[8] !== t) {
2345
+ t3 = aside ? /* @__PURE__ */ jsx(SkipNav.Link, {
2346
+ href: `#${ASIDE}`,
2347
+ children: t("frame.skip.aside")
2348
+ }) : null;
2349
+ $[7] = aside;
2350
+ $[8] = t;
2351
+ $[9] = t3;
2352
+ } else t3 = $[9];
2353
+ let t4;
2354
+ if ($[10] !== panel || $[11] !== t) {
2355
+ t4 = panel ? /* @__PURE__ */ jsx(SkipNav.Link, {
2356
+ href: `#${PANEL}`,
2357
+ children: t("frame.skip.panel")
2358
+ }) : null;
2359
+ $[10] = panel;
2360
+ $[11] = t;
2361
+ $[12] = t4;
2362
+ } else t4 = $[12];
2363
+ let t5;
2364
+ if ($[13] !== t1 || $[14] !== t2 || $[15] !== t3 || $[16] !== t4) {
2365
+ t5 = /* @__PURE__ */ jsxs(Fragment, { children: [
2366
+ t1,
2367
+ t2,
2368
+ t3,
2369
+ t4
2370
+ ] });
2371
+ $[13] = t1;
2372
+ $[14] = t2;
2373
+ $[15] = t3;
2374
+ $[16] = t4;
2375
+ $[17] = t5;
2376
+ } else t5 = $[17];
2377
+ return t5;
2378
+ }
2379
+ //#endregion
2380
+ //#region src/app/frame.tsx
2381
+ /**
2382
+ * Renders the shell inside the host's root, around the page the router matched.
2383
+ *
2384
+ * @remarks
2385
+ * The frame reads the resolved frame, the main menu's sections and the filled regions, so it
2386
+ * renders a part only while the layout calls for it and a plugin fills it. The skip links come
2387
+ * first, then the bar across the top, the body, and the bars at the foot. The `stacked` and
2388
+ * `split` layouts list the sections in the bar.
2389
+ * @returns The host's root around the shell.
2390
+ * @throws {@link Error} Where the product renders its own frame.
2391
+ */
2392
+ function ProductFrame() {
2393
+ const $ = c(32);
2394
+ const frame = useFrame();
2395
+ const sections = useSections();
2396
+ const parts = useFrameParts(frame, sections);
2397
+ let t0;
2398
+ if ($[0] !== frame || $[1] !== parts || $[2] !== sections) {
2399
+ t0 = {
2400
+ frame,
2401
+ parts,
2402
+ sections
2403
+ };
2404
+ $[0] = frame;
2405
+ $[1] = parts;
2406
+ $[2] = sections;
2407
+ $[3] = t0;
2408
+ } else t0 = $[3];
2409
+ const model = t0;
2410
+ const { bar, layout, shell } = frame;
2411
+ const t1 = parts.brand === "bar";
2412
+ const t2 = layout === "stacked" || layout === "split";
2413
+ let t3;
2414
+ if ($[4] !== bar.logo || $[5] !== parts.sidebar || $[6] !== sections || $[7] !== t1 || $[8] !== t2) {
2415
+ t3 = {
2416
+ brand: t1,
2417
+ links: t2,
2418
+ logo: bar.logo,
2419
+ navigation: parts.sidebar,
2420
+ sections
2421
+ };
2422
+ $[4] = bar.logo;
2423
+ $[5] = parts.sidebar;
2424
+ $[6] = sections;
2425
+ $[7] = t1;
2426
+ $[8] = t2;
2427
+ $[9] = t3;
2428
+ } else t3 = $[9];
2429
+ const t4 = parts.userMenu === "bar";
2430
+ let t5;
2431
+ if ($[10] !== frame || $[11] !== parts.panel || $[12] !== t3 || $[13] !== t4) {
2432
+ t5 = {
2433
+ frame,
2434
+ panel: parts.panel,
2435
+ start: t3,
2436
+ userMenu: t4
2437
+ };
2438
+ $[10] = frame;
2439
+ $[11] = parts.panel;
2440
+ $[12] = t3;
2441
+ $[13] = t4;
2442
+ $[14] = t5;
2443
+ } else t5 = $[14];
2444
+ const props = t5;
2445
+ let t6;
2446
+ if ($[15] === Symbol.for("react.memo_cache_sentinel")) {
2447
+ t6 = /* @__PURE__ */ jsx(SkipLinks, {});
2448
+ $[15] = t6;
2449
+ } else t6 = $[15];
2450
+ let t7;
2451
+ if ($[16] !== bar.placement || $[17] !== props) {
2452
+ t7 = bar.placement === "across" ? /* @__PURE__ */ jsx(FrameBar, { ...props }) : null;
2453
+ $[16] = bar.placement;
2454
+ $[17] = props;
2455
+ $[18] = t7;
2456
+ } else t7 = $[18];
2457
+ let t8;
2458
+ if ($[19] !== model || $[20] !== props) {
2459
+ t8 = /* @__PURE__ */ jsx(FrameBody, {
2460
+ bar: props,
2461
+ model
2462
+ });
2463
+ $[19] = model;
2464
+ $[20] = props;
2465
+ $[21] = t8;
2466
+ } else t8 = $[21];
2467
+ let t9;
2468
+ if ($[22] !== model) {
2469
+ t9 = /* @__PURE__ */ jsx(FrameFoot, { model });
2470
+ $[22] = model;
2471
+ $[23] = t9;
2472
+ } else t9 = $[23];
2473
+ let t10;
2474
+ if ($[24] !== shell.content || $[25] !== shell.divided || $[26] !== shell.scroll || $[27] !== shell.variant || $[28] !== t7 || $[29] !== t8 || $[30] !== t9) {
2475
+ t10 = /* @__PURE__ */ jsx(HostRoot, { children: /* @__PURE__ */ jsxs(AppShell.Root, {
2476
+ content: shell.content,
2477
+ divided: shell.divided,
2478
+ scroll: shell.scroll,
2479
+ variant: shell.variant,
2480
+ children: [
2481
+ t6,
2482
+ t7,
2483
+ t8,
2484
+ t9
2485
+ ]
2486
+ }) });
2487
+ $[24] = shell.content;
2488
+ $[25] = shell.divided;
2489
+ $[26] = shell.scroll;
2490
+ $[27] = shell.variant;
2491
+ $[28] = t7;
2492
+ $[29] = t8;
2493
+ $[30] = t9;
2494
+ $[31] = t10;
2495
+ } else t10 = $[31];
2496
+ return t10;
2497
+ }
2498
+ //#endregion
2499
+ export { useSections as n, ProductFrame as t };