@broberg/app-shell 0.12.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/css/app-shell.css +31 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/preact.cjs +191 -1
- 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 +191 -1
- package/dist/preact.js.map +1 -1
- package/package.json +1 -1
package/dist/preact.d.cts
CHANGED
|
@@ -20,6 +20,28 @@ interface NavItem<Icon = unknown> {
|
|
|
20
20
|
marker?: "working";
|
|
21
21
|
/** F092.20 — shows a pin icon after the label. */
|
|
22
22
|
pinned?: boolean;
|
|
23
|
+
/** F092.21 — row actions: a «…» button opens a menu with these. */
|
|
24
|
+
actions?: NavAction[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* F092.21 — one row action. `submenu` switches the menu to a sub-list (with a
|
|
28
|
+
* back arrow); `input` switches it to a field + save (e.g. rename). A plain
|
|
29
|
+
* action, a submenu leaf and a saved input all call `onItemAction`.
|
|
30
|
+
*/
|
|
31
|
+
interface NavAction {
|
|
32
|
+
id: string;
|
|
33
|
+
label: string;
|
|
34
|
+
icon?: unknown;
|
|
35
|
+
/** A single letter that picks this action while the menu is open (e.g. "P"). */
|
|
36
|
+
kbd?: string;
|
|
37
|
+
/** Shown in the danger colour (delete). */
|
|
38
|
+
danger?: boolean;
|
|
39
|
+
submenu?: NavAction[];
|
|
40
|
+
input?: {
|
|
41
|
+
value: string;
|
|
42
|
+
placeholder?: string;
|
|
43
|
+
saveLabel?: string;
|
|
44
|
+
};
|
|
23
45
|
}
|
|
24
46
|
interface NavSection<Icon = unknown> {
|
|
25
47
|
/** A sub-heading inside one group, e.g. "I dag" / "I går". */
|
|
@@ -250,6 +272,8 @@ declare const TEXT: {
|
|
|
250
272
|
readonly closeMenu: "Luk menu";
|
|
251
273
|
readonly home: "Forside";
|
|
252
274
|
readonly working: "Arbejder";
|
|
275
|
+
readonly moreFor: "Mere for";
|
|
276
|
+
readonly back: "Tilbage";
|
|
253
277
|
readonly pinned: "Fastgjort";
|
|
254
278
|
readonly language: "Sprog";
|
|
255
279
|
readonly zoom: "Zoom";
|
|
@@ -323,6 +347,8 @@ declare const TEXT: {
|
|
|
323
347
|
readonly closeMenu: "Close menu";
|
|
324
348
|
readonly home: "Home";
|
|
325
349
|
readonly working: "Working";
|
|
350
|
+
readonly moreFor: "More for";
|
|
351
|
+
readonly back: "Back";
|
|
326
352
|
readonly pinned: "Pinned";
|
|
327
353
|
readonly language: "Language";
|
|
328
354
|
readonly zoom: "Zoom";
|
|
@@ -437,6 +463,8 @@ interface SidebarProps {
|
|
|
437
463
|
lang: Lang;
|
|
438
464
|
/** F092.15 — rendered at the very bottom of the sidebar (the user menu in "sidebar-footer"). */
|
|
439
465
|
bottom?: ComponentChildren;
|
|
466
|
+
/** F092.21 — a row action was chosen (value: the saved text of an `input` action). */
|
|
467
|
+
onItemAction?: (navItemId: string, actionId: string, value?: string) => void;
|
|
440
468
|
}
|
|
441
469
|
declare function Sidebar(p: SidebarProps): JSX.Element;
|
|
442
470
|
interface NotificationBellProps {
|
|
@@ -569,6 +597,8 @@ declare function PageTabs(p: {
|
|
|
569
597
|
onNavigate?: Navigate;
|
|
570
598
|
}): JSX.Element;
|
|
571
599
|
interface AppShellProps {
|
|
600
|
+
/** F092.21 — passed to the sidebar: a row action was chosen. */
|
|
601
|
+
onItemAction?: SidebarProps["onItemAction"];
|
|
572
602
|
brand?: ComponentChildren;
|
|
573
603
|
actions?: ComponentChildren;
|
|
574
604
|
groups: PreactNavGroup[];
|
|
@@ -706,4 +736,4 @@ interface ConfirmDialogProps {
|
|
|
706
736
|
}
|
|
707
737
|
declare function ConfirmDialog(p: ConfirmDialogProps): JSX.Element | null;
|
|
708
738
|
|
|
709
|
-
export { AVATAR_MAX_BYTES, AVATAR_TYPES, type AccountAdapter, AccountError, AccountPage, type AccountPageProps, type AccountProfile, type AnalyticsAdapter, type AnalyticsData, type AnalyticsDay, AnalyticsError, AnalyticsPage, type AnalyticsPageProps, AppShell, type AppShellProps, Avatar, ConfirmDialog, type ConfirmDialogProps, type Lang, type NavGroup, type NavItem, type NavSection, type Navigate, NotificationBell, type NotificationBellProps, type NotificationSource, PageHeader, type PageTab, PageTabs, type PreactNavGroup, type PreactNavItem, type ShellUser, Sidebar, type SidebarProps, TEXT, type TenantAdapter, TenantLoadError, type TenantMembershipRow, TenantSwitcher, type TenantSwitcherProps, TopBar, type TopBarProps, UserMenu, type UserMenuItem, type UserMenuProps, type UserMenuSection, accountErrorKind, activeNavLabel, analyticsErrorKind, badgeLabel, changePct, checkAvatarFile, copenhagenDay, createFetchAccountAdapter, createFetchAnalyticsAdapter, createFetchNotificationSource, createFetchTenantAdapter, createMemoryNotificationSource, defaultReauthHref, fillDays, initials, isActivePath, isExternal, readFlag, readSet, relativeTime, safeNavigate, useIsMobile, writeFlag, writeSet };
|
|
739
|
+
export { AVATAR_MAX_BYTES, AVATAR_TYPES, type AccountAdapter, AccountError, AccountPage, type AccountPageProps, type AccountProfile, type AnalyticsAdapter, type AnalyticsData, type AnalyticsDay, AnalyticsError, AnalyticsPage, type AnalyticsPageProps, AppShell, type AppShellProps, Avatar, ConfirmDialog, type ConfirmDialogProps, type Lang, type NavAction, type NavGroup, type NavItem, type NavSection, type Navigate, NotificationBell, type NotificationBellProps, type NotificationSource, PageHeader, type PageTab, PageTabs, type PreactNavGroup, type PreactNavItem, type ShellUser, Sidebar, type SidebarProps, TEXT, type TenantAdapter, TenantLoadError, type TenantMembershipRow, TenantSwitcher, type TenantSwitcherProps, TopBar, type TopBarProps, UserMenu, type UserMenuItem, type UserMenuProps, type UserMenuSection, accountErrorKind, activeNavLabel, analyticsErrorKind, badgeLabel, changePct, checkAvatarFile, copenhagenDay, createFetchAccountAdapter, createFetchAnalyticsAdapter, createFetchNotificationSource, createFetchTenantAdapter, createMemoryNotificationSource, defaultReauthHref, fillDays, initials, isActivePath, isExternal, readFlag, readSet, relativeTime, safeNavigate, useIsMobile, writeFlag, writeSet };
|
package/dist/preact.d.ts
CHANGED
|
@@ -20,6 +20,28 @@ interface NavItem<Icon = unknown> {
|
|
|
20
20
|
marker?: "working";
|
|
21
21
|
/** F092.20 — shows a pin icon after the label. */
|
|
22
22
|
pinned?: boolean;
|
|
23
|
+
/** F092.21 — row actions: a «…» button opens a menu with these. */
|
|
24
|
+
actions?: NavAction[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* F092.21 — one row action. `submenu` switches the menu to a sub-list (with a
|
|
28
|
+
* back arrow); `input` switches it to a field + save (e.g. rename). A plain
|
|
29
|
+
* action, a submenu leaf and a saved input all call `onItemAction`.
|
|
30
|
+
*/
|
|
31
|
+
interface NavAction {
|
|
32
|
+
id: string;
|
|
33
|
+
label: string;
|
|
34
|
+
icon?: unknown;
|
|
35
|
+
/** A single letter that picks this action while the menu is open (e.g. "P"). */
|
|
36
|
+
kbd?: string;
|
|
37
|
+
/** Shown in the danger colour (delete). */
|
|
38
|
+
danger?: boolean;
|
|
39
|
+
submenu?: NavAction[];
|
|
40
|
+
input?: {
|
|
41
|
+
value: string;
|
|
42
|
+
placeholder?: string;
|
|
43
|
+
saveLabel?: string;
|
|
44
|
+
};
|
|
23
45
|
}
|
|
24
46
|
interface NavSection<Icon = unknown> {
|
|
25
47
|
/** A sub-heading inside one group, e.g. "I dag" / "I går". */
|
|
@@ -250,6 +272,8 @@ declare const TEXT: {
|
|
|
250
272
|
readonly closeMenu: "Luk menu";
|
|
251
273
|
readonly home: "Forside";
|
|
252
274
|
readonly working: "Arbejder";
|
|
275
|
+
readonly moreFor: "Mere for";
|
|
276
|
+
readonly back: "Tilbage";
|
|
253
277
|
readonly pinned: "Fastgjort";
|
|
254
278
|
readonly language: "Sprog";
|
|
255
279
|
readonly zoom: "Zoom";
|
|
@@ -323,6 +347,8 @@ declare const TEXT: {
|
|
|
323
347
|
readonly closeMenu: "Close menu";
|
|
324
348
|
readonly home: "Home";
|
|
325
349
|
readonly working: "Working";
|
|
350
|
+
readonly moreFor: "More for";
|
|
351
|
+
readonly back: "Back";
|
|
326
352
|
readonly pinned: "Pinned";
|
|
327
353
|
readonly language: "Language";
|
|
328
354
|
readonly zoom: "Zoom";
|
|
@@ -437,6 +463,8 @@ interface SidebarProps {
|
|
|
437
463
|
lang: Lang;
|
|
438
464
|
/** F092.15 — rendered at the very bottom of the sidebar (the user menu in "sidebar-footer"). */
|
|
439
465
|
bottom?: ComponentChildren;
|
|
466
|
+
/** F092.21 — a row action was chosen (value: the saved text of an `input` action). */
|
|
467
|
+
onItemAction?: (navItemId: string, actionId: string, value?: string) => void;
|
|
440
468
|
}
|
|
441
469
|
declare function Sidebar(p: SidebarProps): JSX.Element;
|
|
442
470
|
interface NotificationBellProps {
|
|
@@ -569,6 +597,8 @@ declare function PageTabs(p: {
|
|
|
569
597
|
onNavigate?: Navigate;
|
|
570
598
|
}): JSX.Element;
|
|
571
599
|
interface AppShellProps {
|
|
600
|
+
/** F092.21 — passed to the sidebar: a row action was chosen. */
|
|
601
|
+
onItemAction?: SidebarProps["onItemAction"];
|
|
572
602
|
brand?: ComponentChildren;
|
|
573
603
|
actions?: ComponentChildren;
|
|
574
604
|
groups: PreactNavGroup[];
|
|
@@ -706,4 +736,4 @@ interface ConfirmDialogProps {
|
|
|
706
736
|
}
|
|
707
737
|
declare function ConfirmDialog(p: ConfirmDialogProps): JSX.Element | null;
|
|
708
738
|
|
|
709
|
-
export { AVATAR_MAX_BYTES, AVATAR_TYPES, type AccountAdapter, AccountError, AccountPage, type AccountPageProps, type AccountProfile, type AnalyticsAdapter, type AnalyticsData, type AnalyticsDay, AnalyticsError, AnalyticsPage, type AnalyticsPageProps, AppShell, type AppShellProps, Avatar, ConfirmDialog, type ConfirmDialogProps, type Lang, type NavGroup, type NavItem, type NavSection, type Navigate, NotificationBell, type NotificationBellProps, type NotificationSource, PageHeader, type PageTab, PageTabs, type PreactNavGroup, type PreactNavItem, type ShellUser, Sidebar, type SidebarProps, TEXT, type TenantAdapter, TenantLoadError, type TenantMembershipRow, TenantSwitcher, type TenantSwitcherProps, TopBar, type TopBarProps, UserMenu, type UserMenuItem, type UserMenuProps, type UserMenuSection, accountErrorKind, activeNavLabel, analyticsErrorKind, badgeLabel, changePct, checkAvatarFile, copenhagenDay, createFetchAccountAdapter, createFetchAnalyticsAdapter, createFetchNotificationSource, createFetchTenantAdapter, createMemoryNotificationSource, defaultReauthHref, fillDays, initials, isActivePath, isExternal, readFlag, readSet, relativeTime, safeNavigate, useIsMobile, writeFlag, writeSet };
|
|
739
|
+
export { AVATAR_MAX_BYTES, AVATAR_TYPES, type AccountAdapter, AccountError, AccountPage, type AccountPageProps, type AccountProfile, type AnalyticsAdapter, type AnalyticsData, type AnalyticsDay, AnalyticsError, AnalyticsPage, type AnalyticsPageProps, AppShell, type AppShellProps, Avatar, ConfirmDialog, type ConfirmDialogProps, type Lang, type NavAction, type NavGroup, type NavItem, type NavSection, type Navigate, NotificationBell, type NotificationBellProps, type NotificationSource, PageHeader, type PageTab, PageTabs, type PreactNavGroup, type PreactNavItem, type ShellUser, Sidebar, type SidebarProps, TEXT, type TenantAdapter, TenantLoadError, type TenantMembershipRow, TenantSwitcher, type TenantSwitcherProps, TopBar, type TopBarProps, UserMenu, type UserMenuItem, type UserMenuProps, type UserMenuSection, accountErrorKind, activeNavLabel, analyticsErrorKind, badgeLabel, changePct, checkAvatarFile, copenhagenDay, createFetchAccountAdapter, createFetchAnalyticsAdapter, createFetchNotificationSource, createFetchTenantAdapter, createMemoryNotificationSource, defaultReauthHref, fillDays, initials, isActivePath, isExternal, readFlag, readSet, relativeTime, safeNavigate, useIsMobile, writeFlag, writeSet };
|
package/dist/preact.js
CHANGED
|
@@ -305,6 +305,8 @@ var TEXT = {
|
|
|
305
305
|
closeMenu: "Luk menu",
|
|
306
306
|
home: "Forside",
|
|
307
307
|
working: "Arbejder",
|
|
308
|
+
moreFor: "Mere for",
|
|
309
|
+
back: "Tilbage",
|
|
308
310
|
pinned: "Fastgjort",
|
|
309
311
|
language: "Sprog",
|
|
310
312
|
zoom: "Zoom",
|
|
@@ -378,6 +380,8 @@ var TEXT = {
|
|
|
378
380
|
closeMenu: "Close menu",
|
|
379
381
|
home: "Home",
|
|
380
382
|
working: "Working",
|
|
383
|
+
moreFor: "More for",
|
|
384
|
+
back: "Back",
|
|
381
385
|
pinned: "Pinned",
|
|
382
386
|
language: "Language",
|
|
383
387
|
zoom: "Zoom",
|
|
@@ -505,6 +509,186 @@ var IconUser = () => svg(/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
|
505
509
|
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "8", r: "4" }),
|
|
506
510
|
/* @__PURE__ */ jsx("path", { d: "M4 21a8 8 0 0 1 16 0" })
|
|
507
511
|
] }), 14);
|
|
512
|
+
function RowActions(props) {
|
|
513
|
+
const t = TEXT[props.lang];
|
|
514
|
+
const id = props.item.id;
|
|
515
|
+
const btn = useRef(null);
|
|
516
|
+
const menu = useRef(null);
|
|
517
|
+
const [stack, setStack] = useState([]);
|
|
518
|
+
const [hi, setHi] = useState(0);
|
|
519
|
+
const [value, setValue] = useState("");
|
|
520
|
+
const [pos, setPos] = useState(void 0);
|
|
521
|
+
const view = stack[stack.length - 1];
|
|
522
|
+
const open = !!view;
|
|
523
|
+
const close = (refocus = true) => {
|
|
524
|
+
setStack([]);
|
|
525
|
+
if (refocus) btn.current?.focus();
|
|
526
|
+
};
|
|
527
|
+
const show = (v) => {
|
|
528
|
+
setStack((s) => [...s, v]);
|
|
529
|
+
setHi(0);
|
|
530
|
+
if (v.kind === "input") setValue(v.action.input.value);
|
|
531
|
+
};
|
|
532
|
+
const back = () => {
|
|
533
|
+
setStack((s) => s.slice(0, -1));
|
|
534
|
+
setHi(0);
|
|
535
|
+
};
|
|
536
|
+
const pick = (a) => {
|
|
537
|
+
if (a.submenu?.length) return show({ kind: "list", actions: a.submenu, title: a.label });
|
|
538
|
+
if (a.input) return show({ kind: "input", action: a });
|
|
539
|
+
close();
|
|
540
|
+
props.onAction(a.id);
|
|
541
|
+
};
|
|
542
|
+
const save = (a) => {
|
|
543
|
+
close();
|
|
544
|
+
props.onAction(a.id, value);
|
|
545
|
+
};
|
|
546
|
+
useLayoutEffect(() => {
|
|
547
|
+
if (!open || !btn.current) return setPos(void 0);
|
|
548
|
+
const r = btn.current.getBoundingClientRect();
|
|
549
|
+
const vw = window.innerWidth, vh = window.innerHeight, m = 8;
|
|
550
|
+
const w = Math.min(240, vw - 2 * m);
|
|
551
|
+
const h = menu.current?.offsetHeight ?? 0;
|
|
552
|
+
const left = Math.max(m, Math.min(r.right - w, vw - w - m));
|
|
553
|
+
const top = r.bottom + 4 + h <= vh - m || r.top - 4 - h < m ? Math.min(r.bottom + 4, vh - m - h) : r.top - 4 - h;
|
|
554
|
+
setPos({ position: "fixed", left: `${left}px`, top: `${Math.max(m, top)}px`, width: `${w}px` });
|
|
555
|
+
if (view?.kind === "input") menu.current?.querySelector("input")?.focus();
|
|
556
|
+
else menu.current?.focus();
|
|
557
|
+
}, [open, stack.length]);
|
|
558
|
+
useEffect(() => {
|
|
559
|
+
if (!open) return;
|
|
560
|
+
const outside = (e) => {
|
|
561
|
+
const n = e.target instanceof Node ? e.target : null;
|
|
562
|
+
if (n && (menu.current?.contains(n) || btn.current?.contains(n))) return;
|
|
563
|
+
close(false);
|
|
564
|
+
};
|
|
565
|
+
document.addEventListener("mousedown", outside);
|
|
566
|
+
window.addEventListener("scroll", outside, true);
|
|
567
|
+
window.addEventListener("resize", outside);
|
|
568
|
+
return () => {
|
|
569
|
+
document.removeEventListener("mousedown", outside);
|
|
570
|
+
window.removeEventListener("scroll", outside, true);
|
|
571
|
+
window.removeEventListener("resize", outside);
|
|
572
|
+
};
|
|
573
|
+
}, [open]);
|
|
574
|
+
const onKeyDown = (e) => {
|
|
575
|
+
if (!view) return;
|
|
576
|
+
e.stopPropagation();
|
|
577
|
+
if (e.key === "Escape") {
|
|
578
|
+
e.preventDefault();
|
|
579
|
+
return close();
|
|
580
|
+
}
|
|
581
|
+
if (view.kind === "input") {
|
|
582
|
+
if (e.key === "Enter") {
|
|
583
|
+
e.preventDefault();
|
|
584
|
+
save(view.action);
|
|
585
|
+
}
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if ((e.key === "ArrowLeft" || e.key === "Backspace") && stack.length > 1) {
|
|
589
|
+
e.preventDefault();
|
|
590
|
+
return back();
|
|
591
|
+
}
|
|
592
|
+
const list = view.actions;
|
|
593
|
+
const { state, intent } = selectKeyReducer({ open: true, highlighted: hi }, e.key, list.length);
|
|
594
|
+
if (intent.type === "select") {
|
|
595
|
+
e.preventDefault();
|
|
596
|
+
return pick(list[intent.index]);
|
|
597
|
+
}
|
|
598
|
+
if (state.highlighted !== hi) {
|
|
599
|
+
e.preventDefault();
|
|
600
|
+
return setHi(state.highlighted);
|
|
601
|
+
}
|
|
602
|
+
const byKbd = e.key.length === 1 ? list.find((a) => a.kbd?.toLowerCase() === e.key.toLowerCase()) : void 0;
|
|
603
|
+
if (byKbd) {
|
|
604
|
+
e.preventDefault();
|
|
605
|
+
pick(byKbd);
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
609
|
+
/* @__PURE__ */ jsx(
|
|
610
|
+
"button",
|
|
611
|
+
{
|
|
612
|
+
ref: btn,
|
|
613
|
+
type: "button",
|
|
614
|
+
class: "bas-item__more" + (open ? " is-open" : ""),
|
|
615
|
+
"data-testid": `sidebar-item-${id}-more`,
|
|
616
|
+
"aria-label": `${t.moreFor} ${props.item.label}`,
|
|
617
|
+
"aria-haspopup": "menu",
|
|
618
|
+
"aria-expanded": open,
|
|
619
|
+
onClick: () => open ? close() : show({ kind: "list", actions: props.item.actions }),
|
|
620
|
+
children: /* @__PURE__ */ jsx(IconMore, {})
|
|
621
|
+
}
|
|
622
|
+
),
|
|
623
|
+
view ? /* @__PURE__ */ jsxs(
|
|
624
|
+
"div",
|
|
625
|
+
{
|
|
626
|
+
ref: menu,
|
|
627
|
+
class: "bas-rowmenu",
|
|
628
|
+
role: "menu",
|
|
629
|
+
tabIndex: -1,
|
|
630
|
+
"aria-label": view.kind === "list" && view.title ? view.title : props.item.label,
|
|
631
|
+
"data-testid": `sidebar-item-${id}-menu`,
|
|
632
|
+
style: pos ?? { position: "fixed", visibility: "hidden" },
|
|
633
|
+
onKeyDown,
|
|
634
|
+
children: [
|
|
635
|
+
stack.length > 1 ? /* @__PURE__ */ jsxs("button", { type: "button", class: "bas-rowmenu__back", "data-testid": `sidebar-item-${id}-back`, "aria-label": t.back, onClick: back, children: [
|
|
636
|
+
/* @__PURE__ */ jsx(IconChevronLeft, {}),
|
|
637
|
+
/* @__PURE__ */ jsx("span", { children: view.kind === "list" ? view.title : view.action.label })
|
|
638
|
+
] }) : null,
|
|
639
|
+
view.kind === "list" ? view.actions.map((a, i) => /* @__PURE__ */ jsxs(
|
|
640
|
+
"button",
|
|
641
|
+
{
|
|
642
|
+
type: "button",
|
|
643
|
+
role: "menuitem",
|
|
644
|
+
class: "bas-rowmenu__item" + (i === hi ? " is-active" : "") + (a.danger ? " is-danger" : ""),
|
|
645
|
+
"data-testid": `sidebar-item-${id}-action-${a.id}`,
|
|
646
|
+
onMouseEnter: () => setHi(i),
|
|
647
|
+
onClick: () => pick(a),
|
|
648
|
+
children: [
|
|
649
|
+
a.icon ? /* @__PURE__ */ jsx("span", { class: "bas-rowmenu__icon", children: a.icon }) : null,
|
|
650
|
+
/* @__PURE__ */ jsx("span", { class: "bas-rowmenu__label", children: a.label }),
|
|
651
|
+
a.submenu?.length ? /* @__PURE__ */ jsx(IconChevronRight, {}) : a.kbd ? /* @__PURE__ */ jsx("kbd", { class: "bas-rowmenu__kbd", children: a.kbd.toUpperCase() }) : null
|
|
652
|
+
]
|
|
653
|
+
},
|
|
654
|
+
a.id
|
|
655
|
+
)) : /* @__PURE__ */ jsxs(
|
|
656
|
+
"form",
|
|
657
|
+
{
|
|
658
|
+
class: "bas-rowmenu__form",
|
|
659
|
+
"data-testid": `sidebar-item-${id}-form`,
|
|
660
|
+
onSubmit: (e) => {
|
|
661
|
+
e.preventDefault();
|
|
662
|
+
save(view.action);
|
|
663
|
+
},
|
|
664
|
+
children: [
|
|
665
|
+
/* @__PURE__ */ jsx(
|
|
666
|
+
"input",
|
|
667
|
+
{
|
|
668
|
+
class: "bas-rowmenu__input",
|
|
669
|
+
"data-testid": `sidebar-item-${id}-input`,
|
|
670
|
+
"aria-label": view.action.label,
|
|
671
|
+
value,
|
|
672
|
+
placeholder: view.action.input.placeholder,
|
|
673
|
+
onInput: (e) => setValue(e.currentTarget.value)
|
|
674
|
+
}
|
|
675
|
+
),
|
|
676
|
+
/* @__PURE__ */ jsx("button", { type: "submit", class: "bas-rowmenu__save", "data-testid": `sidebar-item-${id}-save`, children: view.action.input.saveLabel ?? t.save })
|
|
677
|
+
]
|
|
678
|
+
}
|
|
679
|
+
)
|
|
680
|
+
]
|
|
681
|
+
}
|
|
682
|
+
) : null
|
|
683
|
+
] });
|
|
684
|
+
}
|
|
685
|
+
var IconMore = () => svg(/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
686
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1" }),
|
|
687
|
+
/* @__PURE__ */ jsx("circle", { cx: "19", cy: "12", r: "1" }),
|
|
688
|
+
/* @__PURE__ */ jsx("circle", { cx: "5", cy: "12", r: "1" })
|
|
689
|
+
] }), 16);
|
|
690
|
+
var IconChevronLeft = () => svg(/* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" }), 14);
|
|
691
|
+
var IconChevronRight = () => svg(/* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }), 14);
|
|
508
692
|
function Sidebar(p) {
|
|
509
693
|
const key = p.groupsKey ?? "broberg-app-shell.groups";
|
|
510
694
|
const itemsKey = p.itemsKey ?? "broberg-app-shell.items";
|
|
@@ -562,7 +746,7 @@ function Sidebar(p) {
|
|
|
562
746
|
const leaf = (it, sub = false) => {
|
|
563
747
|
const active = isActivePath(it.href, p.currentPath);
|
|
564
748
|
const badge = badgeLabel(it.badge);
|
|
565
|
-
|
|
749
|
+
const link = /* @__PURE__ */ jsxs(
|
|
566
750
|
NavLink,
|
|
567
751
|
{
|
|
568
752
|
href: it.href,
|
|
@@ -584,6 +768,11 @@ function Sidebar(p) {
|
|
|
584
768
|
},
|
|
585
769
|
it.id
|
|
586
770
|
);
|
|
771
|
+
if (!it.actions?.length || railed) return link;
|
|
772
|
+
return /* @__PURE__ */ jsxs("div", { class: "bas-itemrow", children: [
|
|
773
|
+
link,
|
|
774
|
+
/* @__PURE__ */ jsx(RowActions, { item: it, lang: p.lang, onAction: (a, v) => v === void 0 ? p.onItemAction?.(it.id, a) : p.onItemAction?.(it.id, a, v) })
|
|
775
|
+
] }, it.id);
|
|
587
776
|
};
|
|
588
777
|
const parent = (it) => {
|
|
589
778
|
const children = it.children;
|
|
@@ -1255,6 +1444,7 @@ function AppShell(p) {
|
|
|
1255
1444
|
{
|
|
1256
1445
|
groups: p.groups,
|
|
1257
1446
|
footer: p.footer,
|
|
1447
|
+
onItemAction: p.onItemAction,
|
|
1258
1448
|
currentPath: p.currentPath,
|
|
1259
1449
|
onNavigate: p.onNavigate,
|
|
1260
1450
|
collapsed,
|