@orangecheck/app-design 1.4.1 → 1.5.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/dist/chrome.d.mts CHANGED
@@ -3,8 +3,8 @@ import { ReactNode } from 'react';
3
3
  import { e as FooterColumn, N as NavItem, d as FamilySlug, j as ProtocolSlug } from './index-DmfyPYe5.mjs';
4
4
  import { T as TocItem } from './hero-Dn37il-9.mjs';
5
5
  import { a as Status } from './status-badge-BJ9Sdsx8.mjs';
6
- export { A as AccountMenu, a as AccountMenuItem, b as AppShell, O as OCHK_APP_ACCOUNT, S as SessionAccountView, c as SessionState, d as ShellNavGroup, e as ShellNavItem, f as ShellSection, T as ThemeToggle, g as ToolShell, h as ToolShellProps, u as useSignInHref } from './tool-shell-D8Q8XX11.mjs';
7
- import './tools-DFIxIj5p.mjs';
6
+ export { A as AccountMenu, a as AccountMenuItem, b as AppShell, c as AppShellProps, O as OCHK_APP_ACCOUNT, S as SessionAccountView, d as SessionState, e as ShellNavGroup, f as ShellNavItem, g as ShellSection, T as ThemeToggle, h as ToolShell, i as ToolShellProps, u as useSignInHref } from './tool-shell-CQZNRUgH.mjs';
7
+ import './tools-Bg1gi2HO.mjs';
8
8
  import './format.mjs';
9
9
 
10
10
  interface SiteHeaderProps {
package/dist/chrome.d.ts CHANGED
@@ -3,8 +3,8 @@ import { ReactNode } from 'react';
3
3
  import { e as FooterColumn, N as NavItem, d as FamilySlug, j as ProtocolSlug } from './index-DmfyPYe5.js';
4
4
  import { T as TocItem } from './hero-Dn37il-9.js';
5
5
  import { a as Status } from './status-badge-Bt8x3RhO.js';
6
- export { A as AccountMenu, a as AccountMenuItem, b as AppShell, O as OCHK_APP_ACCOUNT, S as SessionAccountView, c as SessionState, d as ShellNavGroup, e as ShellNavItem, f as ShellSection, T as ThemeToggle, g as ToolShell, h as ToolShellProps, u as useSignInHref } from './tool-shell-gmlj47Ie.js';
7
- import './tools-BggNN5DV.js';
6
+ export { A as AccountMenu, a as AccountMenuItem, b as AppShell, c as AppShellProps, O as OCHK_APP_ACCOUNT, S as SessionAccountView, d as SessionState, e as ShellNavGroup, f as ShellNavItem, g as ShellSection, T as ThemeToggle, h as ToolShell, i as ToolShellProps, u as useSignInHref } from './tool-shell-CRmceGrV.js';
7
+ import './tools-Bw7RhO92.js';
8
8
  import './format.js';
9
9
 
10
10
  interface SiteHeaderProps {
package/dist/chrome.js CHANGED
@@ -378,7 +378,10 @@ var PopoverContent = react.forwardRef(function PopoverContent2({ className, alig
378
378
  }
379
379
  ) });
380
380
  });
381
- react.forwardRef(function TooltipContent2({ className, sideOffset = 6, ...props }, ref) {
381
+ var TooltipProvider = TooltipPrimitive__namespace.Provider;
382
+ var Tooltip = TooltipPrimitive__namespace.Root;
383
+ var TooltipTrigger = TooltipPrimitive__namespace.Trigger;
384
+ var TooltipContent = react.forwardRef(function TooltipContent2({ className, sideOffset = 6, ...props }, ref) {
382
385
  return /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
383
386
  TooltipPrimitive__namespace.Content,
384
387
  {
@@ -629,48 +632,106 @@ function SectionSwitch({
629
632
  }
630
633
  );
631
634
  }
635
+ function NavBadge({ badge, className }) {
636
+ if (typeof badge === "number") {
637
+ return /* @__PURE__ */ jsxRuntime.jsx(
638
+ "span",
639
+ {
640
+ "aria-hidden": true,
641
+ className: cn(
642
+ "absolute flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[0.625rem] font-medium leading-none text-primary-foreground ring-2 ring-background oca-tabular",
643
+ className
644
+ ),
645
+ children: badge > 99 ? "99+" : badge
646
+ }
647
+ );
648
+ }
649
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: cn("absolute size-2 rounded-full bg-oca-orange-deep ring-2 ring-background", className) });
650
+ }
651
+ var TAB = "flex min-w-0 flex-col items-center justify-center gap-1 rounded-2xl text-[0.6875rem] leading-none outline-none transition-colors [-webkit-tap-highlight-color:transparent] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring";
652
+ function TabFace({ icon, label, badge, active }) {
653
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
654
+ /* @__PURE__ */ jsxRuntime.jsxs(
655
+ "span",
656
+ {
657
+ className: cn(
658
+ "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
659
+ "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
660
+ active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
661
+ ),
662
+ children: [
663
+ icon,
664
+ badge ? /* @__PURE__ */ jsxRuntime.jsx(NavBadge, { badge, className: typeof badge === "number" ? "-top-1 right-0.5" : "right-2.5 top-0.5" }) : null
665
+ ]
666
+ }
667
+ ),
668
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate px-0.5", children: label }),
669
+ badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: badge }) : null
670
+ ] });
671
+ }
632
672
  function TabBar({ items }) {
673
+ const [more, setMore] = react.useState(false);
674
+ const overflow = items.length > 5;
675
+ const shown = overflow ? items.slice(0, 4) : items;
676
+ const rest = overflow ? items.slice(4) : [];
677
+ const restBadge = rest.find((it) => it.badge)?.badge;
633
678
  return /* @__PURE__ */ jsxRuntime.jsx(
634
679
  "nav",
635
680
  {
636
681
  "aria-label": "Pages",
637
682
  "data-oca-tabbar": "",
638
683
  className: "fixed inset-x-0 bottom-0 z-40 border-t border-border bg-background/90 pb-[env(safe-area-inset-bottom)] backdrop-blur-md md:hidden",
639
- children: /* @__PURE__ */ jsxRuntime.jsx(
684
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
640
685
  "div",
641
686
  {
642
687
  className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
643
- style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
644
- children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
645
- Link__default.default,
646
- {
647
- href: it.href,
648
- "aria-current": it.active ? "page" : void 0,
649
- className: cn(
650
- "flex min-w-0 flex-col items-center justify-center gap-1 rounded-2xl text-[0.6875rem] leading-none outline-none transition-colors [-webkit-tap-highlight-color:transparent] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
651
- it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"
688
+ style: { gridTemplateColumns: `repeat(${shown.length + (overflow ? 1 : 0)}, minmax(0, 1fr))` },
689
+ children: [
690
+ shown.map((it) => /* @__PURE__ */ jsxRuntime.jsx(
691
+ Link__default.default,
692
+ {
693
+ href: it.href,
694
+ "aria-current": it.active ? "page" : void 0,
695
+ className: cn(TAB, it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"),
696
+ children: /* @__PURE__ */ jsxRuntime.jsx(TabFace, { icon: it.icon, label: it.label, badge: it.badge, active: it.active })
697
+ },
698
+ it.href
699
+ )),
700
+ overflow ? /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open: more, onOpenChange: setMore, children: [
701
+ /* @__PURE__ */ jsxRuntime.jsx(
702
+ SheetTrigger,
703
+ {
704
+ className: cn(TAB, rest.some((it) => it.active) ? "text-foreground" : "text-muted-foreground hover:text-foreground"),
705
+ children: /* @__PURE__ */ jsxRuntime.jsx(TabFace, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ellipsis, {}), label: "More", badge: restBadge ? true : void 0, active: rest.some((it) => it.active) })
706
+ }
652
707
  ),
653
- children: [
654
- /* @__PURE__ */ jsxRuntime.jsxs(
655
- "span",
708
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "bottom", className: "pb-[calc(1.5rem+env(safe-area-inset-bottom))]", children: [
709
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "px-1 text-[1.0625rem] font-medium", children: "More" }),
710
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 grid grid-cols-3 gap-2", children: rest.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
711
+ Link__default.default,
656
712
  {
713
+ href: it.href,
714
+ onClick: () => setMore(false),
715
+ "aria-current": it.active ? "page" : void 0,
657
716
  className: cn(
658
- "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
659
- "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
660
- it.active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
717
+ "flex min-h-20 flex-col items-center justify-center gap-2 rounded-2xl border px-2 text-center text-[0.8125rem] transition-colors",
718
+ "[&_svg]:size-5",
719
+ it.active ? "border-foreground bg-card text-foreground" : "border-border text-muted-foreground hover:text-foreground"
661
720
  ),
662
721
  children: [
663
- it.icon,
664
- it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute right-2.5 top-0.5 size-2 rounded-full bg-oca-orange ring-2 ring-background" }) : null
722
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative", children: [
723
+ it.icon,
724
+ it.badge ? /* @__PURE__ */ jsxRuntime.jsx(NavBadge, { badge: it.badge, className: typeof it.badge === "number" ? "-right-3 -top-2" : "-right-1 -top-0.5" }) : null
725
+ ] }),
726
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate", children: it.label }),
727
+ it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: it.badge }) : null
665
728
  ]
666
- }
667
- ),
668
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate px-0.5", children: it.label }),
669
- it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: it.badge }) : null
670
- ]
671
- },
672
- it.href
673
- ))
729
+ },
730
+ it.href
731
+ )) })
732
+ ] })
733
+ ] }) : null
734
+ ]
674
735
  }
675
736
  )
676
737
  }
@@ -678,7 +739,11 @@ function TabBar({ items }) {
678
739
  }
679
740
  function tabsFor(groups) {
680
741
  const items = groups.flatMap((g) => g.items);
681
- return items.length >= 2 && items.length <= 5 && items.every((it) => it.icon) ? items : null;
742
+ return items.length >= 2 && items.every((it) => it.icon) ? items : null;
743
+ }
744
+ function sectionTabs(sections, current) {
745
+ if (!sections || !current || sections.length < 2 || !sections.every((sec) => sec.icon)) return null;
746
+ return sections.map((sec) => ({ href: sec.href, label: sec.label, icon: sec.icon, active: sec.id === current.id }));
682
747
  }
683
748
  var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
684
749
  var warned = /* @__PURE__ */ new Set();
@@ -693,7 +758,10 @@ function warnDuplicateLabels(groups) {
693
758
  seen.add(it.label);
694
759
  }
695
760
  }
696
- function AppShell({
761
+ function AppShell(props) {
762
+ return props.variant === "rail" ? /* @__PURE__ */ jsxRuntime.jsx(RailShell, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(SidebarShell, { ...props });
763
+ }
764
+ function SidebarShell({
697
765
  nav,
698
766
  sections,
699
767
  activeSection,
@@ -711,7 +779,8 @@ function AppShell({
711
779
  const current = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
712
780
  const groups = current ? [...current.groups, ...persistent] : [...nav ?? [], ...persistent];
713
781
  warnDuplicateLabels(groups);
714
- const tabs = current ? null : tabsFor(groups);
782
+ const sectionTabsFor = sectionTabs(sections, current);
783
+ const tabs = current ? sectionTabsFor : tabsFor(groups);
715
784
  const page = activeItem(groups);
716
785
  const place = react.useMemo(
717
786
  () => ({
@@ -739,8 +808,8 @@ function AppShell({
739
808
  {
740
809
  className: cn(
741
810
  "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
742
- // The tab bar holds every page; the sheet is left for a footer.
743
- tabs && !footer && "max-md:hidden"
811
+ // The tab bar holds every page; the sheet is left for a footer. Section tabs leave the pages here.
812
+ tabs && !sectionTabsFor && !footer && "max-md:hidden"
744
813
  ),
745
814
  "aria-label": "Open navigation",
746
815
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
@@ -748,8 +817,8 @@ function AppShell({
748
817
  ),
749
818
  /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
750
819
  /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
751
- switcher,
752
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: tabs ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
820
+ switcher ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: sectionTabsFor ? "max-md:hidden" : void 0, children: switcher }) : null,
821
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: tabs && !sectionTabsFor ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
753
822
  footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
754
823
  ] })
755
824
  ] }),
@@ -763,7 +832,7 @@ function AppShell({
763
832
  className: cn(
764
833
  "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]",
765
834
  // The active tab already names the page.
766
- tabs && !pageOverride && "max-md:hidden"
835
+ tabs && !sectionTabsFor && !pageOverride && "max-md:hidden"
767
836
  ),
768
837
  children: [
769
838
  place.section ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -796,6 +865,64 @@ function AppShell({
796
865
  }
797
866
  ) });
798
867
  }
868
+ function RailItem({ item }) {
869
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
870
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
871
+ Link__default.default,
872
+ {
873
+ href: item.href,
874
+ "aria-current": item.active ? "page" : void 0,
875
+ className: cn(
876
+ "relative flex size-10 items-center justify-center rounded-xl outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring",
877
+ "[&_svg]:size-5 [&_svg]:shrink-0",
878
+ item.active ? "bg-card text-foreground shadow-sm ring-1 ring-border" : "text-muted-foreground hover:bg-accent hover:text-foreground"
879
+ ),
880
+ children: [
881
+ item.icon,
882
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
883
+ item.label,
884
+ item.badge ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
885
+ ", ",
886
+ item.badge
887
+ ] }) : null
888
+ ] }),
889
+ item.badge ? /* @__PURE__ */ jsxRuntime.jsx(NavBadge, { badge: item.badge, className: typeof item.badge === "number" ? "-right-1 -top-1" : "right-1 top-1" }) : null
890
+ ]
891
+ }
892
+ ) }),
893
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "right", children: item.label })
894
+ ] });
895
+ }
896
+ function RailShell({ nav = [], persistent = [], page: pageOverride, header, account, banner, children, className }) {
897
+ const main = nav.flatMap((g) => g.items);
898
+ const foot = persistent.flatMap((g) => g.items);
899
+ warnDuplicateLabels([...nav, ...persistent]);
900
+ const tabs = tabsFor([{ items: [...main, ...foot] }]);
901
+ const active = activeItem([...nav, ...persistent]);
902
+ const place = react.useMemo(() => ({ page: pageOverride ?? active?.label }), [pageOverride, active?.label]);
903
+ return /* @__PURE__ */ jsxRuntime.jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex h-dvh flex-col overflow-hidden bg-background", className), children: [
904
+ header,
905
+ banner,
906
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1", children: [
907
+ /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-label": "Pages", className: "hidden w-14 shrink-0 flex-col items-center gap-1 border-r border-border py-3 md:flex", children: [
908
+ main.map((it) => /* @__PURE__ */ jsxRuntime.jsx(RailItem, { item: it }, it.href)),
909
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-auto flex flex-col items-center gap-1", children: [
910
+ foot.map((it) => /* @__PURE__ */ jsxRuntime.jsx(RailItem, { item: it }, it.href)),
911
+ account
912
+ ] })
913
+ ] }),
914
+ /* @__PURE__ */ jsxRuntime.jsx(
915
+ "main",
916
+ {
917
+ id: "main-content",
918
+ className: cn("flex min-h-0 min-w-0 flex-1 flex-col", tabs && "max-md:pb-[calc(3.5rem_+_env(safe-area-inset-bottom))]"),
919
+ children
920
+ }
921
+ )
922
+ ] }),
923
+ tabs ? /* @__PURE__ */ jsxRuntime.jsx(TabBar, { items: tabs }) : null
924
+ ] }) }) });
925
+ }
799
926
  function AccountMenu({
800
927
  name,
801
928
  detail,