@stealthscale/sdk-host 0.1.0 → 0.4.0

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