@broberg/app-shell 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/css/app-shell.css +13 -3
- package/dist/index.cjs +17 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/preact.cjs +97 -10
- package/dist/preact.cjs.map +1 -1
- package/dist/preact.d.cts +31 -1
- package/dist/preact.d.ts +31 -1
- package/dist/preact.js +97 -11
- package/dist/preact.js.map +1 -1
- package/package.json +1 -1
package/dist/preact.d.ts
CHANGED
|
@@ -32,6 +32,12 @@ declare function isActivePath(href: string, currentPath: string): boolean;
|
|
|
32
32
|
* http(s) URL is followed; anything else returns null and the row just closes.
|
|
33
33
|
*/
|
|
34
34
|
declare function safeNavigate(target: string | null | undefined): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* F092.10 — is this link leaving the app? An http(s) link to another origin.
|
|
37
|
+
* Paths, "#…", mailto:/tel: and the app's own origin are not. Owner decision
|
|
38
|
+
* D-d28547: every external link opens in a new tab.
|
|
39
|
+
*/
|
|
40
|
+
declare function isExternal(href: string | null | undefined, origin?: string | undefined): boolean;
|
|
35
41
|
/**
|
|
36
42
|
* The label of the nav item the user is on, for the content header (F092.4).
|
|
37
43
|
* Sub-items count, and the most specific match wins: on "/models/genesis" a
|
|
@@ -100,6 +106,8 @@ declare const TEXT: {
|
|
|
100
106
|
readonly openMenu: "Åbn menu";
|
|
101
107
|
readonly closeMenu: "Luk menu";
|
|
102
108
|
readonly home: "Forside";
|
|
109
|
+
readonly language: "Sprog";
|
|
110
|
+
readonly couldNotMarkAll: "Kunne ikke markere alle som læst. Prøv igen.";
|
|
103
111
|
readonly collapse: "Skjul sidemenu";
|
|
104
112
|
readonly expand: "Vis sidemenu";
|
|
105
113
|
readonly notifications: "Notifikationer";
|
|
@@ -126,6 +134,8 @@ declare const TEXT: {
|
|
|
126
134
|
readonly openMenu: "Open menu";
|
|
127
135
|
readonly closeMenu: "Close menu";
|
|
128
136
|
readonly home: "Home";
|
|
137
|
+
readonly language: "Language";
|
|
138
|
+
readonly couldNotMarkAll: "Could not mark all as read. Try again.";
|
|
129
139
|
readonly collapse: "Hide sidebar";
|
|
130
140
|
readonly expand: "Show sidebar";
|
|
131
141
|
readonly notifications: "Notifications";
|
|
@@ -179,6 +189,8 @@ interface SidebarProps {
|
|
|
179
189
|
homeHref?: string;
|
|
180
190
|
/** Accessible name of the brandMark link (it has no visible text). Default "Forside"/"Home". */
|
|
181
191
|
homeLabel?: string;
|
|
192
|
+
/** data-testid of the brand link in the sidebar head. */
|
|
193
|
+
brandTestId?: string;
|
|
182
194
|
/** Phone, drawer mode: is the drawer open. */
|
|
183
195
|
mobileOpen?: boolean;
|
|
184
196
|
onClose?: () => void;
|
|
@@ -222,6 +234,18 @@ interface UserMenuProps {
|
|
|
222
234
|
onNavigate?: Navigate;
|
|
223
235
|
/** Show Theme · Palette · Surfaces · Backdrop. Default true. */
|
|
224
236
|
appearance?: boolean;
|
|
237
|
+
/**
|
|
238
|
+
* F092.11 — a «Sprog»/«Language» row with a segmented control, like the
|
|
239
|
+
* appearance rows. The app owns the language; the shell shows and reports it.
|
|
240
|
+
*/
|
|
241
|
+
language?: {
|
|
242
|
+
value: string;
|
|
243
|
+
options: {
|
|
244
|
+
id: string;
|
|
245
|
+
label: string;
|
|
246
|
+
}[];
|
|
247
|
+
onChange: (id: string) => void;
|
|
248
|
+
};
|
|
225
249
|
lang: Lang;
|
|
226
250
|
}
|
|
227
251
|
declare function Avatar({ user, size }: {
|
|
@@ -294,6 +318,12 @@ interface AppShellProps {
|
|
|
294
318
|
collapse?: "offcanvas" | "icon";
|
|
295
319
|
/** The app's logo icon for the top of the icon rail. */
|
|
296
320
|
brandMark?: ComponentChildren;
|
|
321
|
+
/**
|
|
322
|
+
* F092.8 — "inset" (default, shadcn dashboard-01): no full-width top bar; the
|
|
323
|
+
* brand heads the sidebar, and the content's top row is sidebar button ·
|
|
324
|
+
* title · actions · bell · user menu. "topbar": the 0.2.x full-width bar.
|
|
325
|
+
*/
|
|
326
|
+
layout?: "inset" | "topbar";
|
|
297
327
|
/** F092.7 — the app's start page. Brand and brandMark become links to it; on a phone the click closes the drawer. */
|
|
298
328
|
homeHref?: string;
|
|
299
329
|
/** Accessible name for the brandMark link. Default "Forside"/"Home". */
|
|
@@ -311,4 +341,4 @@ interface AppShellProps {
|
|
|
311
341
|
}
|
|
312
342
|
declare function AppShell(p: AppShellProps): JSX.Element;
|
|
313
343
|
|
|
314
|
-
export { AppShell, type AppShellProps, Avatar, type Lang, type NavGroup, type NavItem, type Navigate, NotificationBell, type NotificationBellProps, type NotificationSource, PageHeader, type PageTab, PageTabs, type PreactNavGroup, type PreactNavItem, type ShellUser, Sidebar, type SidebarProps, TEXT, TopBar, type TopBarProps, UserMenu, type UserMenuItem, type UserMenuProps, activeNavLabel, badgeLabel, createFetchNotificationSource, createMemoryNotificationSource, initials, isActivePath, readFlag, readSet, relativeTime, safeNavigate, useIsMobile, writeFlag, writeSet };
|
|
344
|
+
export { AppShell, type AppShellProps, Avatar, type Lang, type NavGroup, type NavItem, type Navigate, NotificationBell, type NotificationBellProps, type NotificationSource, PageHeader, type PageTab, PageTabs, type PreactNavGroup, type PreactNavItem, type ShellUser, Sidebar, type SidebarProps, TEXT, TopBar, type TopBarProps, UserMenu, type UserMenuItem, type UserMenuProps, activeNavLabel, badgeLabel, createFetchNotificationSource, createMemoryNotificationSource, initials, isActivePath, isExternal, readFlag, readSet, relativeTime, safeNavigate, useIsMobile, writeFlag, writeSet };
|
package/dist/preact.js
CHANGED
|
@@ -23,6 +23,18 @@ function safeNavigate(target) {
|
|
|
23
23
|
return null;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
+
function isExternal(href, origin = typeof location !== "undefined" ? location.origin : void 0) {
|
|
27
|
+
if (typeof href !== "string") return false;
|
|
28
|
+
const h = href.trim();
|
|
29
|
+
if (!origin) return /^(https?:)?\/\//i.test(h);
|
|
30
|
+
let u;
|
|
31
|
+
try {
|
|
32
|
+
u = new URL(h, origin);
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return (u.protocol === "http:" || u.protocol === "https:") && u.origin !== origin;
|
|
37
|
+
}
|
|
26
38
|
function activeNavLabel(groups, footer, currentPath) {
|
|
27
39
|
let best;
|
|
28
40
|
const visit = (it) => {
|
|
@@ -172,6 +184,8 @@ var TEXT = {
|
|
|
172
184
|
openMenu: "\xC5bn menu",
|
|
173
185
|
closeMenu: "Luk menu",
|
|
174
186
|
home: "Forside",
|
|
187
|
+
language: "Sprog",
|
|
188
|
+
couldNotMarkAll: "Kunne ikke markere alle som l\xE6st. Pr\xF8v igen.",
|
|
175
189
|
collapse: "Skjul sidemenu",
|
|
176
190
|
expand: "Vis sidemenu",
|
|
177
191
|
notifications: "Notifikationer",
|
|
@@ -198,6 +212,8 @@ var TEXT = {
|
|
|
198
212
|
openMenu: "Open menu",
|
|
199
213
|
closeMenu: "Close menu",
|
|
200
214
|
home: "Home",
|
|
215
|
+
language: "Language",
|
|
216
|
+
couldNotMarkAll: "Could not mark all as read. Try again.",
|
|
201
217
|
collapse: "Hide sidebar",
|
|
202
218
|
expand: "Show sidebar",
|
|
203
219
|
notifications: "Notifications",
|
|
@@ -236,6 +252,9 @@ function useIsMobile() {
|
|
|
236
252
|
}
|
|
237
253
|
function NavLink(props) {
|
|
238
254
|
const { href, onNavigate, onAfter, children, ...rest } = props;
|
|
255
|
+
if (isExternal(href)) {
|
|
256
|
+
return /* @__PURE__ */ jsx("a", { ...rest, href, target: "_blank", rel: "noopener noreferrer", onClick: () => onAfter?.(), children });
|
|
257
|
+
}
|
|
239
258
|
return /* @__PURE__ */ jsx(
|
|
240
259
|
"a",
|
|
241
260
|
{
|
|
@@ -411,7 +430,7 @@ function Sidebar(p) {
|
|
|
411
430
|
"aria-label": "Navigation",
|
|
412
431
|
children: [
|
|
413
432
|
p.header || p.brandMark ? /* @__PURE__ */ jsxs("div", { class: "bas-sidebar__head", children: [
|
|
414
|
-
p.header ? /* @__PURE__ */ jsx("div", { class: "bas-sidebar__brand", children: p.homeHref ? /* @__PURE__ */ jsx(NavLink, { href: p.homeHref, onNavigate: p.onNavigate, onAfter: close, class: "bas-home", "data-testid": "sidebar-brand-home", children: p.header }) : p.header }) : null,
|
|
433
|
+
p.header ? /* @__PURE__ */ jsx("div", { class: "bas-sidebar__brand", children: p.homeHref ? /* @__PURE__ */ jsx(NavLink, { href: p.homeHref, onNavigate: p.onNavigate, onAfter: close, class: "bas-home", "data-testid": p.brandTestId ?? "sidebar-brand-home", children: p.header }) : p.header }) : null,
|
|
415
434
|
p.brandMark ? /* @__PURE__ */ jsx("div", { class: "bas-sidebar__mark", "data-testid": "sidebar-brand-mark", children: p.homeHref ? /* @__PURE__ */ jsx(
|
|
416
435
|
NavLink,
|
|
417
436
|
{
|
|
@@ -484,14 +503,42 @@ function NotificationBell({ source, onNavigate, lang }) {
|
|
|
484
503
|
else void shell.refresh();
|
|
485
504
|
});
|
|
486
505
|
}, [shell, source]);
|
|
506
|
+
const bellRef = useRef(null);
|
|
507
|
+
const panelRef = useRef(null);
|
|
487
508
|
useEffect(() => {
|
|
488
509
|
if (!state.open) return;
|
|
489
510
|
const onKey = (e) => {
|
|
490
|
-
if (e.key === "Escape" && shell.escape() === "close")
|
|
511
|
+
if (e.key === "Escape" && shell.escape() === "close") {
|
|
512
|
+
e.preventDefault();
|
|
513
|
+
bellRef.current?.focus();
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
const onDown = (e) => {
|
|
517
|
+
const t2 = e.target;
|
|
518
|
+
if (t2 && (panelRef.current?.contains(t2) || bellRef.current?.contains(t2))) return;
|
|
519
|
+
shell.close();
|
|
491
520
|
};
|
|
492
521
|
document.addEventListener("keydown", onKey);
|
|
493
|
-
|
|
522
|
+
document.addEventListener("mousedown", onDown);
|
|
523
|
+
return () => {
|
|
524
|
+
document.removeEventListener("keydown", onKey);
|
|
525
|
+
document.removeEventListener("mousedown", onDown);
|
|
526
|
+
};
|
|
494
527
|
}, [state.open, shell]);
|
|
528
|
+
const [markAllFailed, setMarkAllFailed] = useState(false);
|
|
529
|
+
useEffect(() => {
|
|
530
|
+
if (!state.open) setMarkAllFailed(false);
|
|
531
|
+
}, [state.open]);
|
|
532
|
+
const onMarkAll = async () => {
|
|
533
|
+
setMarkAllFailed(false);
|
|
534
|
+
try {
|
|
535
|
+
await shell.markAllSeen();
|
|
536
|
+
} catch {
|
|
537
|
+
setMarkAllFailed(true);
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
shell.close();
|
|
541
|
+
};
|
|
495
542
|
const label = badgeLabel(state.count);
|
|
496
543
|
const onRow = async (n) => {
|
|
497
544
|
shell.close();
|
|
@@ -500,7 +547,9 @@ function NotificationBell({ source, onNavigate, lang }) {
|
|
|
500
547
|
await shell.refresh();
|
|
501
548
|
}
|
|
502
549
|
const target = safeNavigate(n.navigate);
|
|
503
|
-
if (target) {
|
|
550
|
+
if (target && isExternal(target)) {
|
|
551
|
+
if (typeof window !== "undefined") window.open(target, "_blank", "noopener,noreferrer");
|
|
552
|
+
} else if (target) {
|
|
504
553
|
if (onNavigate) onNavigate(target);
|
|
505
554
|
else if (typeof window !== "undefined") window.location.assign(target);
|
|
506
555
|
}
|
|
@@ -511,6 +560,7 @@ function NotificationBell({ source, onNavigate, lang }) {
|
|
|
511
560
|
"button",
|
|
512
561
|
{
|
|
513
562
|
type: "button",
|
|
563
|
+
ref: bellRef,
|
|
514
564
|
class: "bas-iconbtn",
|
|
515
565
|
"data-testid": "topbar-notifications",
|
|
516
566
|
"aria-label": t.notifications,
|
|
@@ -530,6 +580,7 @@ function NotificationBell({ source, onNavigate, lang }) {
|
|
|
530
580
|
/* @__PURE__ */ jsxs(
|
|
531
581
|
"div",
|
|
532
582
|
{
|
|
583
|
+
ref: panelRef,
|
|
533
584
|
class: "bas-panel " + (mobile ? "bas-panel--sheet" : "bas-panel--drop"),
|
|
534
585
|
role: "dialog",
|
|
535
586
|
"aria-label": shell.labels.panel,
|
|
@@ -537,8 +588,9 @@ function NotificationBell({ source, onNavigate, lang }) {
|
|
|
537
588
|
children: [
|
|
538
589
|
/* @__PURE__ */ jsxs("div", { class: "bas-panel__head", children: [
|
|
539
590
|
/* @__PURE__ */ jsx("h3", { children: t.notifications }),
|
|
540
|
-
/* @__PURE__ */ jsx("button", { type: "button", class: "bas-link", "data-testid": "notifications-mark-all", onClick: () => void
|
|
591
|
+
/* @__PURE__ */ jsx("button", { type: "button", class: "bas-link", "data-testid": "notifications-mark-all", onClick: () => void onMarkAll(), disabled: !state.count, children: shell.labels.markAll })
|
|
541
592
|
] }),
|
|
593
|
+
markAllFailed ? /* @__PURE__ */ jsx("p", { class: "bas-panel__note is-error", role: "alert", "data-testid": "notifications-mark-all-error", children: t.couldNotMarkAll }) : null,
|
|
542
594
|
/* @__PURE__ */ jsx("div", { class: "bas-panel__list", "data-testid": "notifications-list", children: error && state.rows.length === 0 ? /* @__PURE__ */ jsx("p", { class: "bas-panel__note is-error", "data-testid": "notifications-error", children: t.couldNotLoad }) : state.rows.length === 0 ? /* @__PURE__ */ jsx("p", { class: "bas-panel__note", "data-testid": "notifications-empty", children: shell.labels.empty }) : state.rows.map((n) => /* @__PURE__ */ jsxs(
|
|
543
595
|
"button",
|
|
544
596
|
{
|
|
@@ -573,7 +625,16 @@ function Avatar({ user, size = 28 }) {
|
|
|
573
625
|
return /* @__PURE__ */ jsx("span", { class: "bas-avatar bas-avatar--initials", style, "data-testid": "avatar-initials", "aria-hidden": "true", children: initials(user.name, user.email) });
|
|
574
626
|
}
|
|
575
627
|
function Segmented(props) {
|
|
576
|
-
|
|
628
|
+
const onKeyDown = (e) => {
|
|
629
|
+
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;
|
|
630
|
+
const buttons = [...e.currentTarget.querySelectorAll("button")];
|
|
631
|
+
const i = buttons.indexOf(document.activeElement);
|
|
632
|
+
if (i < 0) return;
|
|
633
|
+
e.preventDefault();
|
|
634
|
+
const next = (i + (e.key === "ArrowRight" ? 1 : -1) + buttons.length) % buttons.length;
|
|
635
|
+
buttons[next].focus();
|
|
636
|
+
};
|
|
637
|
+
return /* @__PURE__ */ jsx("div", { class: "bas-seg", "data-testid": props.testid, role: "group", "aria-label": props.label, onKeyDown, children: props.options.map(([v, label]) => /* @__PURE__ */ jsx("button", { type: "button", "aria-pressed": props.value === v, "data-testid": `${props.testid}-${v}`, onClick: () => props.onChange(v), children: label }, v)) });
|
|
577
638
|
}
|
|
578
639
|
function UserMenu(p) {
|
|
579
640
|
const t = TEXT[p.lang];
|
|
@@ -642,7 +703,7 @@ function UserMenu(p) {
|
|
|
642
703
|
] })
|
|
643
704
|
] }),
|
|
644
705
|
/* @__PURE__ */ jsx("div", { class: "bas-sep" }),
|
|
645
|
-
p.accountHref ? /* @__PURE__ */ jsxs(
|
|
706
|
+
p.accountHref ? /* @__PURE__ */ jsxs(NavLink, { href: p.accountHref, onNavigate: p.onNavigate, onAfter: () => setOpen(false), class: "bas-mi", "data-testid": "user-menu-account", role: "menuitem", children: [
|
|
646
707
|
/* @__PURE__ */ jsx(IconUser, {}),
|
|
647
708
|
/* @__PURE__ */ jsx("span", { children: t.account })
|
|
648
709
|
] }) : null,
|
|
@@ -701,6 +762,22 @@ function UserMenu(p) {
|
|
|
701
762
|
] })
|
|
702
763
|
] })
|
|
703
764
|
] }) : null,
|
|
765
|
+
p.language ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
766
|
+
p.appearance === false ? /* @__PURE__ */ jsx("div", { class: "bas-sep" }) : null,
|
|
767
|
+
/* @__PURE__ */ jsx("div", { class: "bas-prefs", children: /* @__PURE__ */ jsxs("div", { class: "bas-pref", children: [
|
|
768
|
+
/* @__PURE__ */ jsx("span", { children: t.language }),
|
|
769
|
+
/* @__PURE__ */ jsx(
|
|
770
|
+
Segmented,
|
|
771
|
+
{
|
|
772
|
+
testid: "user-menu-language",
|
|
773
|
+
label: t.language,
|
|
774
|
+
value: p.language.value,
|
|
775
|
+
options: p.language.options.map((o) => [o.id, o.label]),
|
|
776
|
+
onChange: p.language.onChange
|
|
777
|
+
}
|
|
778
|
+
)
|
|
779
|
+
] }) })
|
|
780
|
+
] }) : null,
|
|
704
781
|
p.onSignOut ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
705
782
|
/* @__PURE__ */ jsx("div", { class: "bas-sep" }),
|
|
706
783
|
/* @__PURE__ */ jsxs("button", { type: "button", class: "bas-mi is-danger", role: "menuitem", "data-testid": "topbar-sign-out", disabled: busy, onClick: () => void signOut(), children: [
|
|
@@ -750,6 +827,8 @@ function PageTabs(p) {
|
|
|
750
827
|
function AppShell(p) {
|
|
751
828
|
const prefix = p.storageKey ?? "broberg-app-shell";
|
|
752
829
|
const mode = p.mobile ?? "drawer";
|
|
830
|
+
const layout = p.layout ?? "inset";
|
|
831
|
+
const inset = layout === "inset";
|
|
753
832
|
const collapse = p.collapse ?? (mode === "rail" ? "icon" : "offcanvas");
|
|
754
833
|
const [collapsed, setCollapsed] = useState(() => readFlag(`${prefix}.collapsed`, false));
|
|
755
834
|
const [drawer, setDrawer] = useState(false);
|
|
@@ -765,8 +844,8 @@ function AppShell(p) {
|
|
|
765
844
|
const expanded = drawerMode ? drawer : !collapsed;
|
|
766
845
|
const triggerLabel = drawerMode ? drawer ? t.closeMenu : t.openMenu : collapsed ? t.expand : t.collapse;
|
|
767
846
|
const heading = p.title ?? activeNavLabel(p.groups, p.footer, p.currentPath);
|
|
768
|
-
return /* @__PURE__ */ jsxs("div", { class: "bas-root", "data-testid": "app-shell", "data-mobile": mode, children: [
|
|
769
|
-
/* @__PURE__ */ jsx(
|
|
847
|
+
return /* @__PURE__ */ jsxs("div", { class: "bas-root", "data-testid": "app-shell", "data-mobile": mode, "data-layout": layout, children: [
|
|
848
|
+
inset ? null : /* @__PURE__ */ jsx(
|
|
770
849
|
TopBar,
|
|
771
850
|
{
|
|
772
851
|
brand: p.brand,
|
|
@@ -796,7 +875,8 @@ function AppShell(p) {
|
|
|
796
875
|
mobileOpen: drawer,
|
|
797
876
|
onClose: () => setDrawer(false),
|
|
798
877
|
mobile: mode,
|
|
799
|
-
header: mode === "drawer" ? p.brand : void 0,
|
|
878
|
+
header: inset || mode === "drawer" ? p.brand : void 0,
|
|
879
|
+
brandTestId: inset ? "brand-home" : void 0,
|
|
800
880
|
groupsKey: `${prefix}.groups`,
|
|
801
881
|
itemsKey: `${prefix}.items`,
|
|
802
882
|
lang: p.lang
|
|
@@ -820,6 +900,12 @@ function AppShell(p) {
|
|
|
820
900
|
heading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
821
901
|
/* @__PURE__ */ jsx("span", { class: "bas-contenthead__sep", "data-testid": "content-header-separator", "aria-hidden": "true" }),
|
|
822
902
|
/* @__PURE__ */ jsx("h1", { class: "bas-contenthead__title", "data-testid": "content-header-title", children: heading })
|
|
903
|
+
] }) : null,
|
|
904
|
+
inset ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
905
|
+
/* @__PURE__ */ jsx("div", { class: "bas-spacer" }),
|
|
906
|
+
p.actions ? /* @__PURE__ */ jsx("div", { class: "bas-contenthead__actions", children: p.actions }) : null,
|
|
907
|
+
/* @__PURE__ */ jsx(NotificationBell, { source: p.notifications, onNavigate: p.onNavigate, lang: p.lang }),
|
|
908
|
+
p.user ? /* @__PURE__ */ jsx(UserMenu, { user: p.user, ...p.userMenu, onNavigate: p.onNavigate, lang: p.lang }) : null
|
|
823
909
|
] }) : null
|
|
824
910
|
] }),
|
|
825
911
|
p.children
|
|
@@ -828,6 +914,6 @@ function AppShell(p) {
|
|
|
828
914
|
] });
|
|
829
915
|
}
|
|
830
916
|
|
|
831
|
-
export { AppShell, Avatar, NotificationBell, PageHeader, PageTabs, Sidebar, TEXT, TopBar, UserMenu, activeNavLabel, badgeLabel, createFetchNotificationSource, createMemoryNotificationSource, initials, isActivePath, readFlag, readSet, relativeTime, safeNavigate, useIsMobile, writeFlag, writeSet };
|
|
917
|
+
export { AppShell, Avatar, NotificationBell, PageHeader, PageTabs, Sidebar, TEXT, TopBar, UserMenu, activeNavLabel, badgeLabel, createFetchNotificationSource, createMemoryNotificationSource, initials, isActivePath, isExternal, readFlag, readSet, relativeTime, safeNavigate, useIsMobile, writeFlag, writeSet };
|
|
832
918
|
//# sourceMappingURL=preact.js.map
|
|
833
919
|
//# sourceMappingURL=preact.js.map
|