@estiva-app/ui 0.50.4 → 0.52.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/CollapsibleSection.d.ts +7 -1
- package/dist/CollapsibleSection.d.ts.map +1 -1
- package/dist/ComposerTriggers.d.ts +169 -0
- package/dist/ComposerTriggers.d.ts.map +1 -0
- package/dist/NavItem.d.ts +23 -3
- package/dist/NavItem.d.ts.map +1 -1
- package/dist/NavTree.d.ts +49 -0
- package/dist/NavTree.d.ts.map +1 -0
- package/dist/SectionLabel.d.ts +7 -1
- package/dist/SectionLabel.d.ts.map +1 -1
- package/dist/editor.d.ts +1 -0
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +313 -12
- package/dist/editor.js.map +4 -4
- package/dist/eslint/index.js +1 -1
- package/dist/eslint/index.js.map +2 -2
- package/dist/eslint/no-native-title.d.ts +1 -1
- package/dist/eslint/no-native-title.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +332 -212
- package/dist/index.js.map +4 -4
- package/dist/looks.d.ts +7 -0
- package/dist/looks.d.ts.map +1 -1
- package/package.json +6 -1
- package/registry.json +426 -5
- package/src/CollapsibleSection.mdx +6 -0
- package/src/CollapsibleSection.stories.tsx +5 -0
- package/src/CollapsibleSection.tsx +12 -4
- package/src/ComposerTriggers.mdx +108 -0
- package/src/ComposerTriggers.stories.tsx +79 -0
- package/src/ComposerTriggers.test.tsx +207 -0
- package/src/ComposerTriggers.tsx +507 -0
- package/src/NavItem.mdx +30 -0
- package/src/NavItem.stories.tsx +34 -0
- package/src/NavItem.test.tsx +82 -0
- package/src/NavItem.tsx +123 -25
- package/src/NavTree.mdx +83 -0
- package/src/NavTree.stories.tsx +84 -0
- package/src/NavTree.test.tsx +54 -0
- package/src/NavTree.tsx +112 -0
- package/src/SectionHeader.tsx +1 -1
- package/src/SectionLabel.mdx +4 -1
- package/src/SectionLabel.stories.tsx +3 -0
- package/src/SectionLabel.tsx +10 -2
- package/src/editor.ts +29 -0
- package/src/eslint/no-native-title.ts +1 -1
- package/src/index.ts +1 -0
- package/src/looks.ts +8 -0
- package/src/registry/registry.test.ts +9 -8
- package/stories/Choosing.mdx +2 -0
package/dist/index.js
CHANGED
|
@@ -321,6 +321,7 @@ var CHIP_TEXT_CLASSES = "text-chip signal:font-mono signal:text-small signal:fon
|
|
|
321
321
|
var BARE_INPUT_CLASSES = "bg-transparent text-text-primary placeholder:text-text-muted outline-none";
|
|
322
322
|
var SIDEBAR_ROW_CLASSES = "rounded-md transition-colors";
|
|
323
323
|
var SIDEBAR_ROW_TEXT_CLASSES = "text-text-secondary hover:text-text-primary";
|
|
324
|
+
var COLLAPSIBLE_PANEL_CLASSES = "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0";
|
|
324
325
|
|
|
325
326
|
// src/Tooltip.tsx
|
|
326
327
|
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -1100,6 +1101,7 @@ function SectionLabel({
|
|
|
1100
1101
|
children,
|
|
1101
1102
|
tone = "primary",
|
|
1102
1103
|
truncate = false,
|
|
1104
|
+
folds = false,
|
|
1103
1105
|
className
|
|
1104
1106
|
}) {
|
|
1105
1107
|
return /* @__PURE__ */ jsx19(
|
|
@@ -1107,8 +1109,9 @@ function SectionLabel({
|
|
|
1107
1109
|
{
|
|
1108
1110
|
className: cn(
|
|
1109
1111
|
"text-h5 leading-3 signal:font-mono signal:text-small signal:uppercase signal:tracking-widest",
|
|
1110
|
-
// Leaf's section labels are Signal's type (Katerina, 28 September)
|
|
1111
|
-
|
|
1112
|
+
// Leaf's section labels are Signal's type (Katerina, 28 September),
|
|
1113
|
+
// but a group that folds keeps Ship's (Katerina, 2 October).
|
|
1114
|
+
!folds && "leaf:font-mono leaf:text-small leaf:uppercase leaf:tracking-widest",
|
|
1112
1115
|
tone === "secondary" ? "text-text-secondary" : tone === "muted" ? "text-text-muted" : "text-text-primary",
|
|
1113
1116
|
truncate && "min-w-0 truncate",
|
|
1114
1117
|
className
|
|
@@ -2794,9 +2797,36 @@ function Breadcrumb({ items, className }) {
|
|
|
2794
2797
|
}
|
|
2795
2798
|
|
|
2796
2799
|
// src/NavItem.tsx
|
|
2797
|
-
import {
|
|
2800
|
+
import { useId, useState as useState7 } from "react";
|
|
2801
|
+
import { Collapsible } from "@base-ui/react/collapsible";
|
|
2802
|
+
import { IconChevronRight as IconChevronRight2, IconDotsVertical } from "@tabler/icons-react";
|
|
2798
2803
|
import { jsx as jsx43, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2799
|
-
function NavItem({
|
|
2804
|
+
function NavItem({
|
|
2805
|
+
label,
|
|
2806
|
+
href,
|
|
2807
|
+
count,
|
|
2808
|
+
countLabel,
|
|
2809
|
+
active = false,
|
|
2810
|
+
icon,
|
|
2811
|
+
menu,
|
|
2812
|
+
menuLabel,
|
|
2813
|
+
hint,
|
|
2814
|
+
children,
|
|
2815
|
+
defaultOpen = true,
|
|
2816
|
+
open: openProp,
|
|
2817
|
+
onOpenChange,
|
|
2818
|
+
className,
|
|
2819
|
+
...props
|
|
2820
|
+
}) {
|
|
2821
|
+
const [openState, setOpenState] = useState7(defaultOpen);
|
|
2822
|
+
const panelId = useId();
|
|
2823
|
+
const hasRows = children != null && children !== false;
|
|
2824
|
+
const open = openProp ?? openState;
|
|
2825
|
+
const setOpen = (next) => {
|
|
2826
|
+
setOpenState(next);
|
|
2827
|
+
onOpenChange?.(next);
|
|
2828
|
+
};
|
|
2829
|
+
const besides = menu != null || hasRows;
|
|
2800
2830
|
const row = /* @__PURE__ */ jsxs29(
|
|
2801
2831
|
"a",
|
|
2802
2832
|
{
|
|
@@ -2810,21 +2840,35 @@ function NavItem({ label, href, count, countLabel, active = false, icon, menu, m
|
|
|
2810
2840
|
SIDEBAR_ROW_CLASSES,
|
|
2811
2841
|
active ? "bg-bg-active text-text-primary" : cn(SIDEBAR_ROW_TEXT_CLASSES, "hover:bg-bg-hover"),
|
|
2812
2842
|
// With a menu the ⋮ sits beside the link, so the row keeps its hover
|
|
2813
|
-
// look while the ⋮ is pointed at and while its menu is open.
|
|
2814
|
-
|
|
2843
|
+
// look while the ⋮ is pointed at and while its menu is open. The same
|
|
2844
|
+
// for the arrow.
|
|
2845
|
+
besides && !active && "group-hover/nav:bg-bg-hover group-hover/nav:text-text-primary",
|
|
2846
|
+
menu != null && !active && "group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:bg-bg-hover group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:text-text-primary",
|
|
2815
2847
|
className
|
|
2816
2848
|
),
|
|
2817
2849
|
...props,
|
|
2818
2850
|
children: [
|
|
2819
|
-
icon && /* @__PURE__ */ jsx43(
|
|
2851
|
+
(icon || hasRows) && /* @__PURE__ */ jsx43(
|
|
2852
|
+
"span",
|
|
2853
|
+
{
|
|
2854
|
+
className: cn(
|
|
2855
|
+
// With rows under it the slot is kept even with no icon: the arrow lands in it.
|
|
2856
|
+
"flex min-w-4 shrink-0 items-center",
|
|
2857
|
+
hasRows && "transition-opacity group-hover/nav:opacity-0 group-focus-within/nav:opacity-0"
|
|
2858
|
+
),
|
|
2859
|
+
children: icon
|
|
2860
|
+
}
|
|
2861
|
+
),
|
|
2820
2862
|
/* @__PURE__ */ jsx43("span", { className: "flex-1 truncate", children: label }),
|
|
2863
|
+
hint != null && // Takes room only while it shows, so the label gives way to it.
|
|
2864
|
+
/* @__PURE__ */ jsx43("span", { className: "hidden shrink-0 items-center group-hover/nav:flex group-focus-within/nav:flex", children: hint }),
|
|
2821
2865
|
count ? /* @__PURE__ */ jsx43(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx43(
|
|
2822
2866
|
"span",
|
|
2823
2867
|
{
|
|
2824
2868
|
className: cn(
|
|
2825
2869
|
"min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted",
|
|
2826
2870
|
// With a menu, the ⋮ takes this place while it shows.
|
|
2827
|
-
menu != null && "transition-opacity group-hover/nav:opacity-0 group-focus-within/nav:opacity-0 group-has-[[aria-expanded=true]]/nav:opacity-0"
|
|
2871
|
+
menu != null && "transition-opacity group-hover/nav:opacity-0 group-focus-within/nav:opacity-0 group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:opacity-0"
|
|
2828
2872
|
),
|
|
2829
2873
|
children: count
|
|
2830
2874
|
}
|
|
@@ -2836,11 +2880,26 @@ function NavItem({ label, href, count, countLabel, active = false, icon, menu, m
|
|
|
2836
2880
|
]
|
|
2837
2881
|
}
|
|
2838
2882
|
);
|
|
2839
|
-
if (
|
|
2883
|
+
if (!besides && hint == null) return row;
|
|
2840
2884
|
const name = menuLabel ?? `More options for ${label}`;
|
|
2841
|
-
|
|
2885
|
+
const line = /* @__PURE__ */ jsxs29("div", { className: "group/nav relative shrink-0", children: [
|
|
2842
2886
|
row,
|
|
2843
|
-
|
|
2887
|
+
hasRows && // `left-1`: the 24px button's 16px arrow then sits where the icon
|
|
2888
|
+
// sits (the row's px-2), so the icon turns into the arrow in place.
|
|
2889
|
+
/* @__PURE__ */ jsx43("div", { className: "absolute inset-y-0 left-1 flex items-center opacity-0 transition-opacity focus-within:opacity-100 group-hover/nav:opacity-100", children: /* @__PURE__ */ jsx43(
|
|
2890
|
+
IconButton,
|
|
2891
|
+
{
|
|
2892
|
+
tooltip: open ? "Collapse" : "Expand",
|
|
2893
|
+
"aria-label": open ? `Hide what is under ${label}` : `Show what is under ${label}`,
|
|
2894
|
+
"aria-expanded": open,
|
|
2895
|
+
"aria-controls": panelId,
|
|
2896
|
+
onClick: () => setOpen(!open),
|
|
2897
|
+
children: /* @__PURE__ */ jsx43(IconChevronRight2, { size: 16, stroke: 1.5, className: cn("transition-transform duration-150", open && "rotate-90") })
|
|
2898
|
+
}
|
|
2899
|
+
) }),
|
|
2900
|
+
menu != null && // `right-1`: the 24px button's 16px icon then ends 8px from the row's
|
|
2901
|
+
// edge, where the count ends (px-2), so the ⋮ lands on the number.
|
|
2902
|
+
/* @__PURE__ */ jsx43("div", { "data-nav-menu": true, className: "absolute inset-y-0 right-1 flex items-center opacity-0 transition-opacity focus-within:opacity-100 group-hover/nav:opacity-100 has-[[aria-expanded=true]]:opacity-100", children: /* @__PURE__ */ jsx43(
|
|
2844
2903
|
Menu,
|
|
2845
2904
|
{
|
|
2846
2905
|
align: "right",
|
|
@@ -2849,12 +2908,177 @@ function NavItem({ label, href, count, countLabel, active = false, icon, menu, m
|
|
|
2849
2908
|
}
|
|
2850
2909
|
) })
|
|
2851
2910
|
] });
|
|
2911
|
+
if (!hasRows) return line;
|
|
2912
|
+
return /* @__PURE__ */ jsxs29(Collapsible.Root, { open, onOpenChange: setOpen, className: "flex shrink-0 flex-col", children: [
|
|
2913
|
+
line,
|
|
2914
|
+
/* @__PURE__ */ jsx43(
|
|
2915
|
+
Collapsible.Panel,
|
|
2916
|
+
{
|
|
2917
|
+
id: panelId,
|
|
2918
|
+
hiddenUntilFound: true,
|
|
2919
|
+
className: COLLAPSIBLE_PANEL_CLASSES,
|
|
2920
|
+
children: /* @__PURE__ */ jsx43("div", { className: "flex flex-col gap-px pl-6", children })
|
|
2921
|
+
}
|
|
2922
|
+
)
|
|
2923
|
+
] });
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
// src/CollapsibleSection.tsx
|
|
2927
|
+
import { useState as useState8 } from "react";
|
|
2928
|
+
import { Collapsible as Collapsible2 } from "@base-ui/react/collapsible";
|
|
2929
|
+
|
|
2930
|
+
// src/SectionHeader.tsx
|
|
2931
|
+
import { IconChevronRight as IconChevronRight3 } from "@tabler/icons-react";
|
|
2932
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
2933
|
+
import { Fragment as Fragment11, jsx as jsx44, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2934
|
+
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", hover = "fill", look = "heading", render, className }) {
|
|
2935
|
+
const row = look === "row";
|
|
2936
|
+
const titleElement = useRender({
|
|
2937
|
+
render: render ?? (chevron ? /* @__PURE__ */ jsx44("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx44("span", {})),
|
|
2938
|
+
props: {
|
|
2939
|
+
// `text-left`: a button centres its text. `h-full` and `flex-1`: the
|
|
2940
|
+
// whole row up to the actions is the hit target, as it was when the
|
|
2941
|
+
// row itself carried the click.
|
|
2942
|
+
className: cn("flex h-full min-w-0 flex-1 items-center text-left", row ? "gap-2" : "gap-1"),
|
|
2943
|
+
children: /* @__PURE__ */ jsxs30(Fragment11, { children: [
|
|
2944
|
+
chevron && /* @__PURE__ */ jsx44(
|
|
2945
|
+
IconChevronRight3,
|
|
2946
|
+
{
|
|
2947
|
+
size: row ? 16 : 12,
|
|
2948
|
+
stroke: 1.5,
|
|
2949
|
+
className: cn("shrink-0 transition-transform duration-150", !row && "text-text-secondary", isExpanded && "rotate-90")
|
|
2950
|
+
}
|
|
2951
|
+
),
|
|
2952
|
+
look === "quiet" ? /* @__PURE__ */ jsx44("span", { className: "min-w-0 truncate text-caption text-text-muted", children: title }) : row ? (
|
|
2953
|
+
// A row's words: NavItem's size and colour, brightening under the pointer with the row.
|
|
2954
|
+
/* @__PURE__ */ jsx44("span", { className: "min-w-0 flex-1 truncate text-body-2", children: title })
|
|
2955
|
+
) : /* @__PURE__ */ jsx44(SectionLabel, { folds: chevron, children: title })
|
|
2956
|
+
] })
|
|
2957
|
+
}
|
|
2958
|
+
});
|
|
2959
|
+
return /* @__PURE__ */ jsxs30(
|
|
2960
|
+
"div",
|
|
2961
|
+
{
|
|
2962
|
+
className: cn(
|
|
2963
|
+
"group flex h-[32px] shrink-0 items-center gap-1 px-2",
|
|
2964
|
+
!row && "transition-colors",
|
|
2965
|
+
// A row is NavItem's shape and colour: 6px corners, secondary words that brighten on hover.
|
|
2966
|
+
row ? cn(SIDEBAR_ROW_CLASSES, SIDEBAR_ROW_TEXT_CLASSES) : "rounded-lg",
|
|
2967
|
+
// The fill says "this does something": a row with a toggle or actions
|
|
2968
|
+
// lights up, a fixed heading over rows does not (2026-09-09, the
|
|
2969
|
+
// Sidebar's fixed group).
|
|
2970
|
+
// A quiet label never lights up: it is a label; its button does.
|
|
2971
|
+
hover === "fill" && look !== "quiet" && (chevron || actions && actions.length > 0) && "hover:bg-bg-hover",
|
|
2972
|
+
className
|
|
2973
|
+
),
|
|
2974
|
+
children: [
|
|
2975
|
+
titleElement,
|
|
2976
|
+
trailing != null && /* @__PURE__ */ jsx44("div", { className: "flex shrink-0 items-center", children: trailing }),
|
|
2977
|
+
actions && actions.length > 0 && /* @__PURE__ */ jsx44(
|
|
2978
|
+
"div",
|
|
2979
|
+
{
|
|
2980
|
+
className: cn(
|
|
2981
|
+
"-mr-1 flex shrink-0 items-center gap-1",
|
|
2982
|
+
showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
|
|
2983
|
+
),
|
|
2984
|
+
children: actions.map((action) => /* @__PURE__ */ jsx44(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
|
|
2985
|
+
}
|
|
2986
|
+
)
|
|
2987
|
+
]
|
|
2988
|
+
}
|
|
2989
|
+
);
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
// src/CollapsibleSection.tsx
|
|
2993
|
+
import { jsx as jsx45, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2994
|
+
var OPEN = "open";
|
|
2995
|
+
var CLOSED = "closed";
|
|
2996
|
+
function readStored(key) {
|
|
2997
|
+
if (!key) return void 0;
|
|
2998
|
+
try {
|
|
2999
|
+
const value = window.localStorage.getItem(key);
|
|
3000
|
+
return value === OPEN ? true : value === CLOSED ? false : void 0;
|
|
3001
|
+
} catch {
|
|
3002
|
+
return void 0;
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
function writeStored(key, open) {
|
|
3006
|
+
if (!key) return;
|
|
3007
|
+
try {
|
|
3008
|
+
window.localStorage.setItem(key, open ? OPEN : CLOSED);
|
|
3009
|
+
} catch {
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, trailing, actions, showActions, look = "heading", indent = false, children, className, contentClassName }) {
|
|
3013
|
+
const [openState, setOpenState] = useState8(() => readStored(storageKey) ?? defaultOpen);
|
|
3014
|
+
const open = openProp ?? openState;
|
|
3015
|
+
const setOpen = (next) => {
|
|
3016
|
+
setOpenState(next);
|
|
3017
|
+
writeStored(storageKey, next);
|
|
3018
|
+
onOpenChange?.(next);
|
|
3019
|
+
};
|
|
3020
|
+
return /* @__PURE__ */ jsxs31(Collapsible2.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
|
|
3021
|
+
/* @__PURE__ */ jsx45(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, look, className: "shrink-0", render: /* @__PURE__ */ jsx45(Collapsible2.Trigger, {}) }),
|
|
3022
|
+
/* @__PURE__ */ jsx45(
|
|
3023
|
+
Collapsible2.Panel,
|
|
3024
|
+
{
|
|
3025
|
+
hiddenUntilFound: true,
|
|
3026
|
+
className: COLLAPSIBLE_PANEL_CLASSES,
|
|
3027
|
+
children: /* @__PURE__ */ jsx45("div", { className: cn("flex flex-col", look === "row" ? "pl-6" : indent && "pl-4", contentClassName), children })
|
|
3028
|
+
}
|
|
3029
|
+
)
|
|
3030
|
+
] });
|
|
3031
|
+
}
|
|
3032
|
+
|
|
3033
|
+
// src/NavTree.tsx
|
|
3034
|
+
import { Fragment as Fragment12, jsx as jsx46, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3035
|
+
function holds(nodes, id) {
|
|
3036
|
+
return id !== void 0 && nodes.some((node) => node.id === id || holds(node.children ?? [], id));
|
|
3037
|
+
}
|
|
3038
|
+
function Row({ node, selected, onSelect }) {
|
|
3039
|
+
return /* @__PURE__ */ jsx46(
|
|
3040
|
+
NavItem,
|
|
3041
|
+
{
|
|
3042
|
+
href: node.href,
|
|
3043
|
+
label: node.label,
|
|
3044
|
+
icon: node.icon,
|
|
3045
|
+
count: node.count,
|
|
3046
|
+
countLabel: node.countLabel,
|
|
3047
|
+
hint: node.hint,
|
|
3048
|
+
menu: node.menu,
|
|
3049
|
+
active: node.id === selected,
|
|
3050
|
+
defaultOpen: node.defaultOpen ?? true,
|
|
3051
|
+
onClick: onSelect ? (event) => onSelect(node, event) : void 0,
|
|
3052
|
+
children: node.children?.length ? node.children.map((child) => /* @__PURE__ */ jsx46(Row, { node: child, selected, onSelect }, child.id)) : void 0
|
|
3053
|
+
}
|
|
3054
|
+
);
|
|
3055
|
+
}
|
|
3056
|
+
function NavTree({ title, groups, selected, onSelect, emptyMessage, storageKey }) {
|
|
3057
|
+
return /* @__PURE__ */ jsxs32(Fragment12, { children: [
|
|
3058
|
+
title && /* @__PURE__ */ jsx46(SectionHeader, { title, look: "quiet", className: "mt-4 shrink-0" }),
|
|
3059
|
+
groups === null ? /* @__PURE__ */ jsx46(SkeletonList, { rows: 5 }) : groups.length === 0 ? (
|
|
3060
|
+
// Level with the rows: a row pads itself, so the line takes a row's inset (Katerina, 14 September).
|
|
3061
|
+
/* @__PURE__ */ jsx46("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx46(EmptyState, { scope: "section", message: emptyMessage }) })
|
|
3062
|
+
) : groups.map((group) => /* @__PURE__ */ jsx46(
|
|
3063
|
+
CollapsibleSection,
|
|
3064
|
+
{
|
|
3065
|
+
title: group.title,
|
|
3066
|
+
indent: true,
|
|
3067
|
+
defaultOpen: holds(group.nodes, selected),
|
|
3068
|
+
storageKey: storageKey ? `${storageKey}.${group.id}` : void 0,
|
|
3069
|
+
className: "mt-2 shrink-0",
|
|
3070
|
+
contentClassName: "gap-px",
|
|
3071
|
+
children: group.nodes.map((node) => /* @__PURE__ */ jsx46(Row, { node, selected, onSelect }, node.id))
|
|
3072
|
+
},
|
|
3073
|
+
group.id
|
|
3074
|
+
))
|
|
3075
|
+
] });
|
|
2852
3076
|
}
|
|
2853
3077
|
|
|
2854
3078
|
// src/Popover.tsx
|
|
2855
3079
|
import { useMemo as useMemo3 } from "react";
|
|
2856
3080
|
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
2857
|
-
import { jsx as
|
|
3081
|
+
import { jsx as jsx47, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2858
3082
|
var GAP5 = 4;
|
|
2859
3083
|
var VIEWPORT_PAD5 = 8;
|
|
2860
3084
|
function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
|
|
@@ -2863,7 +3087,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2863
3087
|
if (anchor instanceof Element) return anchor;
|
|
2864
3088
|
return { getBoundingClientRect: () => anchor };
|
|
2865
3089
|
}, [anchor]);
|
|
2866
|
-
return /* @__PURE__ */
|
|
3090
|
+
return /* @__PURE__ */ jsxs33(
|
|
2867
3091
|
BasePopover.Root,
|
|
2868
3092
|
{
|
|
2869
3093
|
open,
|
|
@@ -2871,8 +3095,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2871
3095
|
actionsRef,
|
|
2872
3096
|
modal: false,
|
|
2873
3097
|
children: [
|
|
2874
|
-
trigger && /* @__PURE__ */
|
|
2875
|
-
/* @__PURE__ */
|
|
3098
|
+
trigger && /* @__PURE__ */ jsx47(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
|
|
3099
|
+
/* @__PURE__ */ jsx47(BasePopover.Portal, { children: /* @__PURE__ */ jsx47(
|
|
2876
3100
|
BasePopover.Positioner,
|
|
2877
3101
|
{
|
|
2878
3102
|
anchor: anchorTarget,
|
|
@@ -2881,20 +3105,20 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2881
3105
|
sideOffset: GAP5,
|
|
2882
3106
|
collisionPadding: VIEWPORT_PAD5,
|
|
2883
3107
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
2884
|
-
children: /* @__PURE__ */
|
|
3108
|
+
children: /* @__PURE__ */ jsx47(
|
|
2885
3109
|
BasePopover.Popup,
|
|
2886
3110
|
{
|
|
2887
3111
|
"aria-label": ariaLabel,
|
|
2888
3112
|
initialFocus: trigger ? void 0 : false,
|
|
2889
3113
|
finalFocus,
|
|
2890
3114
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
2891
|
-
render: /* @__PURE__ */
|
|
2892
|
-
children: /* @__PURE__ */
|
|
3115
|
+
render: /* @__PURE__ */ jsx47(MenuPanel, {}),
|
|
3116
|
+
children: /* @__PURE__ */ jsx47(
|
|
2893
3117
|
ScrollArea,
|
|
2894
3118
|
{
|
|
2895
3119
|
viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
|
|
2896
3120
|
contentClassName: cn("flex flex-col p-2", contentClassName),
|
|
2897
|
-
children: /* @__PURE__ */
|
|
3121
|
+
children: /* @__PURE__ */ jsx47(DividerInPanel.Provider, { value: true, children })
|
|
2898
3122
|
}
|
|
2899
3123
|
)
|
|
2900
3124
|
}
|
|
@@ -2907,14 +3131,14 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
2907
3131
|
}
|
|
2908
3132
|
|
|
2909
3133
|
// src/SuggestionMenu.tsx
|
|
2910
|
-
import { useCallback as useCallback3, useEffect as useEffect4, useId, useImperativeHandle, useMemo as useMemo4, useState as
|
|
2911
|
-
import { jsx as
|
|
3134
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useId as useId2, useImperativeHandle, useMemo as useMemo4, useState as useState9 } from "react";
|
|
3135
|
+
import { jsx as jsx48, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2912
3136
|
function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sections, itemKey, row, onSelect, handle }) {
|
|
2913
3137
|
const shown = useMemo4(() => sections.filter((section) => section.items.length > 0), [sections]);
|
|
2914
3138
|
const items = useMemo4(() => shown.flatMap((section) => section.items), [shown]);
|
|
2915
3139
|
const keys = items.map(itemKey).join("\n");
|
|
2916
|
-
const [highlight, setHighlight] =
|
|
2917
|
-
const base =
|
|
3140
|
+
const [highlight, setHighlight] = useState9(0);
|
|
3141
|
+
const base = useId2();
|
|
2918
3142
|
const listboxId = `${base}-list`;
|
|
2919
3143
|
useEffect4(() => setHighlight(0), [keys]);
|
|
2920
3144
|
useImperativeHandle(handle, () => ({
|
|
@@ -2961,7 +3185,7 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
|
|
|
2961
3185
|
const { label, description, leading, shortcut, hint, size } = row(item);
|
|
2962
3186
|
return (
|
|
2963
3187
|
// A row of a list the editor drives from its caret: focus stays in the text, so the row is no Tab stop.
|
|
2964
|
-
/* @__PURE__ */
|
|
3188
|
+
/* @__PURE__ */ jsx48(
|
|
2965
3189
|
MenuItem,
|
|
2966
3190
|
{
|
|
2967
3191
|
role: "option",
|
|
@@ -2986,17 +3210,17 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
|
|
|
2986
3210
|
)
|
|
2987
3211
|
);
|
|
2988
3212
|
};
|
|
2989
|
-
return /* @__PURE__ */
|
|
2990
|
-
i > 0 && /* @__PURE__ */
|
|
2991
|
-
section.label ? /* @__PURE__ */
|
|
3213
|
+
return /* @__PURE__ */ jsx48(Popover, { anchor: rect, open: rect !== null, side: "top", align: "left", className: width, maxHeight, ariaLabel, children: /* @__PURE__ */ jsx48("div", { id: listboxId, role: "listbox", "aria-label": ariaLabel, className: "flex flex-col", children: shown.map((section, i) => /* @__PURE__ */ jsxs34("div", { className: "contents", children: [
|
|
3214
|
+
i > 0 && /* @__PURE__ */ jsx48(MenuSeparator, {}),
|
|
3215
|
+
section.label ? /* @__PURE__ */ jsx48("div", { role: "group", "aria-label": section.label, children: /* @__PURE__ */ jsx48(MenuSection, { label: section.label, className: section.className, children: section.items.map(drawRow) }) }) : section.items.map(drawRow)
|
|
2992
3216
|
] }, section.label ?? i)) }) });
|
|
2993
3217
|
}
|
|
2994
3218
|
|
|
2995
3219
|
// src/Toolbar.tsx
|
|
2996
3220
|
import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
|
|
2997
|
-
import { jsx as
|
|
3221
|
+
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
2998
3222
|
function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
|
|
2999
|
-
const strip = /* @__PURE__ */
|
|
3223
|
+
const strip = /* @__PURE__ */ jsx49(
|
|
3000
3224
|
BaseToolbar.Root,
|
|
3001
3225
|
{
|
|
3002
3226
|
"aria-label": ariaLabel,
|
|
@@ -3007,27 +3231,27 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
|
|
|
3007
3231
|
}
|
|
3008
3232
|
);
|
|
3009
3233
|
if (!surface) return strip;
|
|
3010
|
-
return /* @__PURE__ */
|
|
3234
|
+
return /* @__PURE__ */ jsx49(MenuPanel, { className: "w-fit p-1", children: strip });
|
|
3011
3235
|
}
|
|
3012
3236
|
function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
|
|
3013
|
-
return /* @__PURE__ */
|
|
3237
|
+
return /* @__PURE__ */ jsx49(
|
|
3014
3238
|
BaseToolbar.Button,
|
|
3015
3239
|
{
|
|
3016
3240
|
ref,
|
|
3017
3241
|
disabled: disabled || !!disabledReason,
|
|
3018
3242
|
focusableWhenDisabled: true,
|
|
3019
|
-
render: /* @__PURE__ */
|
|
3243
|
+
render: /* @__PURE__ */ jsx49(IconButton, { disabled, disabledReason, ...props })
|
|
3020
3244
|
}
|
|
3021
3245
|
);
|
|
3022
3246
|
}
|
|
3023
3247
|
function ToolbarLink({ ref, href, ...props }) {
|
|
3024
|
-
return /* @__PURE__ */
|
|
3248
|
+
return /* @__PURE__ */ jsx49(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx49(IconButton, { href, ...props }) });
|
|
3025
3249
|
}
|
|
3026
3250
|
function ToolbarInput({ size, ...props }) {
|
|
3027
|
-
return /* @__PURE__ */
|
|
3251
|
+
return /* @__PURE__ */ jsx49(BaseToolbar.Input, { render: /* @__PURE__ */ jsx49(TextInput, { size }), ...props });
|
|
3028
3252
|
}
|
|
3029
3253
|
function ToolbarSeparator({ className }) {
|
|
3030
|
-
return /* @__PURE__ */
|
|
3254
|
+
return /* @__PURE__ */ jsx49(
|
|
3031
3255
|
BaseToolbar.Separator,
|
|
3032
3256
|
{
|
|
3033
3257
|
orientation: "vertical",
|
|
@@ -3037,9 +3261,9 @@ function ToolbarSeparator({ className }) {
|
|
|
3037
3261
|
}
|
|
3038
3262
|
|
|
3039
3263
|
// src/ReactionPicker.tsx
|
|
3040
|
-
import { jsx as
|
|
3264
|
+
import { jsx as jsx50 } from "react/jsx-runtime";
|
|
3041
3265
|
function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
|
|
3042
|
-
return /* @__PURE__ */
|
|
3266
|
+
return /* @__PURE__ */ jsx50(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
|
|
3043
3267
|
/*
|
|
3044
3268
|
A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
|
|
3045
3269
|
would become the toolbar's item and the button inside it would never
|
|
@@ -3049,14 +3273,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
3049
3273
|
The tooltip names it for a pointer, `aria-label` for everything else,
|
|
3050
3274
|
and both say the meaning rather than the glyph.
|
|
3051
3275
|
*/
|
|
3052
|
-
/* @__PURE__ */
|
|
3276
|
+
/* @__PURE__ */ jsx50(
|
|
3053
3277
|
ToolbarButton,
|
|
3054
3278
|
{
|
|
3055
3279
|
"aria-label": option.label,
|
|
3056
3280
|
tooltip: option.label,
|
|
3057
3281
|
onClick: () => onSelect(option.emoji),
|
|
3058
3282
|
className: "size-7",
|
|
3059
|
-
children: /* @__PURE__ */
|
|
3283
|
+
children: /* @__PURE__ */ jsx50("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
|
|
3060
3284
|
},
|
|
3061
3285
|
option.emoji
|
|
3062
3286
|
)
|
|
@@ -3065,23 +3289,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
3065
3289
|
|
|
3066
3290
|
// src/PreviewCard.tsx
|
|
3067
3291
|
import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
|
|
3068
|
-
import { jsx as
|
|
3292
|
+
import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
3069
3293
|
var GAP6 = 12;
|
|
3070
3294
|
var VIEWPORT_PAD6 = 8;
|
|
3071
3295
|
var OPEN_DELAY2 = 350;
|
|
3072
3296
|
var CLOSE_DELAY = 200;
|
|
3073
3297
|
function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, contentClassName, wrapperClassName }) {
|
|
3074
|
-
return /* @__PURE__ */
|
|
3075
|
-
/* @__PURE__ */
|
|
3298
|
+
return /* @__PURE__ */ jsxs35(BasePreviewCard.Root, { children: [
|
|
3299
|
+
/* @__PURE__ */ jsx51(
|
|
3076
3300
|
BasePreviewCard.Trigger,
|
|
3077
3301
|
{
|
|
3078
3302
|
delay,
|
|
3079
3303
|
closeDelay,
|
|
3080
|
-
render: /* @__PURE__ */
|
|
3304
|
+
render: /* @__PURE__ */ jsx51("span", { className: cn("inline-flex", wrapperClassName) }),
|
|
3081
3305
|
children
|
|
3082
3306
|
}
|
|
3083
3307
|
),
|
|
3084
|
-
/* @__PURE__ */
|
|
3308
|
+
/* @__PURE__ */ jsx51(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx51(
|
|
3085
3309
|
BasePreviewCard.Positioner,
|
|
3086
3310
|
{
|
|
3087
3311
|
side,
|
|
@@ -3089,12 +3313,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
3089
3313
|
sideOffset: GAP6,
|
|
3090
3314
|
collisionPadding: VIEWPORT_PAD6,
|
|
3091
3315
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
3092
|
-
children: /* @__PURE__ */
|
|
3316
|
+
children: /* @__PURE__ */ jsx51(
|
|
3093
3317
|
BasePreviewCard.Popup,
|
|
3094
3318
|
{
|
|
3095
3319
|
className: cn("w-[360px] p-0 outline-none", className),
|
|
3096
|
-
render: /* @__PURE__ */
|
|
3097
|
-
children: /* @__PURE__ */
|
|
3320
|
+
render: /* @__PURE__ */ jsx51(MenuPanel, {}),
|
|
3321
|
+
children: /* @__PURE__ */ jsx51(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
|
|
3098
3322
|
}
|
|
3099
3323
|
)
|
|
3100
3324
|
}
|
|
@@ -3103,15 +3327,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
3103
3327
|
}
|
|
3104
3328
|
|
|
3105
3329
|
// src/Rail.tsx
|
|
3106
|
-
import { jsx as
|
|
3330
|
+
import { jsx as jsx52 } from "react/jsx-runtime";
|
|
3107
3331
|
function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
|
|
3108
|
-
return /* @__PURE__ */
|
|
3332
|
+
return /* @__PURE__ */ jsx52("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
|
|
3109
3333
|
}
|
|
3110
3334
|
|
|
3111
3335
|
// src/RailItem.tsx
|
|
3112
|
-
import { jsx as
|
|
3336
|
+
import { jsx as jsx53, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
3113
3337
|
function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
3114
|
-
return /* @__PURE__ */
|
|
3338
|
+
return /* @__PURE__ */ jsxs36(
|
|
3115
3339
|
"a",
|
|
3116
3340
|
{
|
|
3117
3341
|
href,
|
|
@@ -3119,14 +3343,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
3119
3343
|
className: cn("group flex h-12 w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
|
|
3120
3344
|
...props,
|
|
3121
3345
|
children: [
|
|
3122
|
-
/* @__PURE__ */
|
|
3346
|
+
/* @__PURE__ */ jsx53(
|
|
3123
3347
|
"div",
|
|
3124
3348
|
{
|
|
3125
3349
|
className: cn(
|
|
3126
3350
|
"flex items-center justify-center rounded-lg p-2 transition-colors",
|
|
3127
3351
|
active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
|
|
3128
3352
|
),
|
|
3129
|
-
children: /* @__PURE__ */
|
|
3353
|
+
children: /* @__PURE__ */ jsx53(
|
|
3130
3354
|
"span",
|
|
3131
3355
|
{
|
|
3132
3356
|
className: cn(
|
|
@@ -3138,14 +3362,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
3138
3362
|
)
|
|
3139
3363
|
}
|
|
3140
3364
|
),
|
|
3141
|
-
/* @__PURE__ */
|
|
3365
|
+
/* @__PURE__ */ jsx53("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
|
|
3142
3366
|
]
|
|
3143
3367
|
}
|
|
3144
3368
|
);
|
|
3145
3369
|
}
|
|
3146
3370
|
|
|
3147
3371
|
// src/Property.tsx
|
|
3148
|
-
import { jsx as
|
|
3372
|
+
import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
3149
3373
|
var VALUE_CLASSES = "contents";
|
|
3150
3374
|
function Property({ label, layout = "row", children, className }) {
|
|
3151
3375
|
if (layout === "stacked") {
|
|
@@ -3153,25 +3377,25 @@ function Property({ label, layout = "row", children, className }) {
|
|
|
3153
3377
|
// gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
|
|
3154
3378
|
// Peek's topic-details sections already sit at 12px, Ship's rail was
|
|
3155
3379
|
// 6px, and unifying means the bigger, calmer one.
|
|
3156
|
-
/* @__PURE__ */
|
|
3157
|
-
/* @__PURE__ */
|
|
3158
|
-
/* @__PURE__ */
|
|
3380
|
+
/* @__PURE__ */ jsxs37("dl", { className: cn("flex flex-col gap-3", className), children: [
|
|
3381
|
+
/* @__PURE__ */ jsx54("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
|
|
3382
|
+
/* @__PURE__ */ jsx54("dd", { className: VALUE_CLASSES, children })
|
|
3159
3383
|
] })
|
|
3160
3384
|
);
|
|
3161
3385
|
}
|
|
3162
|
-
return /* @__PURE__ */
|
|
3163
|
-
/* @__PURE__ */
|
|
3164
|
-
/* @__PURE__ */
|
|
3386
|
+
return /* @__PURE__ */ jsxs37("dl", { className: cn("flex items-center gap-2", className), children: [
|
|
3387
|
+
/* @__PURE__ */ jsx54("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
|
|
3388
|
+
/* @__PURE__ */ jsx54("dd", { className: VALUE_CLASSES, children })
|
|
3165
3389
|
] });
|
|
3166
3390
|
}
|
|
3167
3391
|
|
|
3168
3392
|
// src/Reaction.tsx
|
|
3169
3393
|
import { Toggle } from "@base-ui/react/toggle";
|
|
3170
|
-
import { jsx as
|
|
3394
|
+
import { jsx as jsx55, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
3171
3395
|
function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
3172
3396
|
return (
|
|
3173
3397
|
// @estiva-escape(no-copied-look): W1 (Katerina, 24 September: leave alone): a reaction pill shares four words with a field's box by coincidence
|
|
3174
|
-
/* @__PURE__ */
|
|
3398
|
+
/* @__PURE__ */ jsxs38(
|
|
3175
3399
|
Toggle,
|
|
3176
3400
|
{
|
|
3177
3401
|
pressed,
|
|
@@ -3193,8 +3417,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
3193
3417
|
),
|
|
3194
3418
|
...props,
|
|
3195
3419
|
children: [
|
|
3196
|
-
/* @__PURE__ */
|
|
3197
|
-
/* @__PURE__ */
|
|
3420
|
+
/* @__PURE__ */ jsx55("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
|
|
3421
|
+
/* @__PURE__ */ jsx55("span", { className: CHIP_TEXT_CLASSES, children: count })
|
|
3198
3422
|
]
|
|
3199
3423
|
}
|
|
3200
3424
|
)
|
|
@@ -3204,9 +3428,9 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
3204
3428
|
// src/SearchInput.tsx
|
|
3205
3429
|
import "react";
|
|
3206
3430
|
import { Input as Input3 } from "@base-ui/react/input";
|
|
3207
|
-
import { jsx as
|
|
3431
|
+
import { jsx as jsx56, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3208
3432
|
function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
|
|
3209
|
-
return /* @__PURE__ */
|
|
3433
|
+
return /* @__PURE__ */ jsxs39(
|
|
3210
3434
|
"div",
|
|
3211
3435
|
{
|
|
3212
3436
|
className: cn(
|
|
@@ -3218,7 +3442,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
3218
3442
|
className
|
|
3219
3443
|
),
|
|
3220
3444
|
children: [
|
|
3221
|
-
/* @__PURE__ */
|
|
3445
|
+
/* @__PURE__ */ jsx56(
|
|
3222
3446
|
Input3,
|
|
3223
3447
|
{
|
|
3224
3448
|
className: cn("flex-1 min-w-0 text-input-value", BARE_INPUT_CLASSES),
|
|
@@ -3226,104 +3450,42 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
3226
3450
|
...props
|
|
3227
3451
|
}
|
|
3228
3452
|
),
|
|
3229
|
-
shortcut && /* @__PURE__ */
|
|
3230
|
-
]
|
|
3231
|
-
}
|
|
3232
|
-
);
|
|
3233
|
-
}
|
|
3234
|
-
|
|
3235
|
-
// src/SectionHeader.tsx
|
|
3236
|
-
import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
|
|
3237
|
-
import { useRender } from "@base-ui/react/use-render";
|
|
3238
|
-
import { Fragment as Fragment11, jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
3239
|
-
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", hover = "fill", look = "heading", render, className }) {
|
|
3240
|
-
const row = look === "row";
|
|
3241
|
-
const titleElement = useRender({
|
|
3242
|
-
render: render ?? (chevron ? /* @__PURE__ */ jsx54("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx54("span", {})),
|
|
3243
|
-
props: {
|
|
3244
|
-
// `text-left`: a button centres its text. `h-full` and `flex-1`: the
|
|
3245
|
-
// whole row up to the actions is the hit target, as it was when the
|
|
3246
|
-
// row itself carried the click.
|
|
3247
|
-
className: cn("flex h-full min-w-0 flex-1 items-center text-left", row ? "gap-2" : "gap-1"),
|
|
3248
|
-
children: /* @__PURE__ */ jsxs37(Fragment11, { children: [
|
|
3249
|
-
chevron && /* @__PURE__ */ jsx54(
|
|
3250
|
-
IconChevronRight2,
|
|
3251
|
-
{
|
|
3252
|
-
size: row ? 16 : 12,
|
|
3253
|
-
stroke: 1.5,
|
|
3254
|
-
className: cn("shrink-0 transition-transform duration-150", !row && "text-text-secondary", isExpanded && "rotate-90")
|
|
3255
|
-
}
|
|
3256
|
-
),
|
|
3257
|
-
look === "quiet" ? /* @__PURE__ */ jsx54("span", { className: "min-w-0 truncate text-caption text-text-muted", children: title }) : row ? (
|
|
3258
|
-
// A row's words: NavItem's size and colour, brightening under the pointer with the row.
|
|
3259
|
-
/* @__PURE__ */ jsx54("span", { className: "min-w-0 flex-1 truncate text-body-2", children: title })
|
|
3260
|
-
) : /* @__PURE__ */ jsx54(SectionLabel, { children: title })
|
|
3261
|
-
] })
|
|
3262
|
-
}
|
|
3263
|
-
});
|
|
3264
|
-
return /* @__PURE__ */ jsxs37(
|
|
3265
|
-
"div",
|
|
3266
|
-
{
|
|
3267
|
-
className: cn(
|
|
3268
|
-
"group flex h-[32px] shrink-0 items-center gap-1 px-2",
|
|
3269
|
-
!row && "transition-colors",
|
|
3270
|
-
// A row is NavItem's shape and colour: 6px corners, secondary words that brighten on hover.
|
|
3271
|
-
row ? cn(SIDEBAR_ROW_CLASSES, SIDEBAR_ROW_TEXT_CLASSES) : "rounded-lg",
|
|
3272
|
-
// The fill says "this does something": a row with a toggle or actions
|
|
3273
|
-
// lights up, a fixed heading over rows does not (2026-09-09, the
|
|
3274
|
-
// Sidebar's fixed group).
|
|
3275
|
-
// A quiet label never lights up: it is a label; its button does.
|
|
3276
|
-
hover === "fill" && look !== "quiet" && (chevron || actions && actions.length > 0) && "hover:bg-bg-hover",
|
|
3277
|
-
className
|
|
3278
|
-
),
|
|
3279
|
-
children: [
|
|
3280
|
-
titleElement,
|
|
3281
|
-
trailing != null && /* @__PURE__ */ jsx54("div", { className: "flex shrink-0 items-center", children: trailing }),
|
|
3282
|
-
actions && actions.length > 0 && /* @__PURE__ */ jsx54(
|
|
3283
|
-
"div",
|
|
3284
|
-
{
|
|
3285
|
-
className: cn(
|
|
3286
|
-
"-mr-1 flex shrink-0 items-center gap-1",
|
|
3287
|
-
showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
|
|
3288
|
-
),
|
|
3289
|
-
children: actions.map((action) => /* @__PURE__ */ jsx54(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
|
|
3290
|
-
}
|
|
3291
|
-
)
|
|
3453
|
+
shortcut && /* @__PURE__ */ jsx56(Kbd, { children: shortcut })
|
|
3292
3454
|
]
|
|
3293
3455
|
}
|
|
3294
3456
|
);
|
|
3295
3457
|
}
|
|
3296
3458
|
|
|
3297
3459
|
// src/Panel.tsx
|
|
3298
|
-
import { jsx as
|
|
3460
|
+
import { jsx as jsx57, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3299
3461
|
function Frame({ title, chevron = false, actions, children, footer, bodyClassName, bodyRef, onBodyScroll, className, broken = false }) {
|
|
3300
|
-
return /* @__PURE__ */
|
|
3301
|
-
/* @__PURE__ */
|
|
3462
|
+
return /* @__PURE__ */ jsxs40("div", { className: cn("flex h-full min-h-0 flex-1 flex-col", className), children: [
|
|
3463
|
+
/* @__PURE__ */ jsx57(ContainerHeader, { title, chevron, actions }),
|
|
3302
3464
|
broken ? (
|
|
3303
3465
|
// The message takes the room the body had and centres itself in it.
|
|
3304
|
-
/* @__PURE__ */
|
|
3305
|
-
) : /* @__PURE__ */
|
|
3306
|
-
!broken && footer && /* @__PURE__ */
|
|
3466
|
+
/* @__PURE__ */ jsx57("div", { className: "flex min-h-0 flex-1 flex-col px-4", children })
|
|
3467
|
+
) : /* @__PURE__ */ jsx57(ScrollArea, { className: "min-h-0 flex-1", contentClassName: bodyClassName, viewportRef: bodyRef, onScroll: onBodyScroll, children }),
|
|
3468
|
+
!broken && footer && /* @__PURE__ */ jsx57("div", { className: "shrink-0", children: footer })
|
|
3307
3469
|
] });
|
|
3308
3470
|
}
|
|
3309
3471
|
function Panel(props) {
|
|
3310
|
-
return /* @__PURE__ */
|
|
3472
|
+
return /* @__PURE__ */ jsx57(
|
|
3311
3473
|
ErrorBoundary,
|
|
3312
3474
|
{
|
|
3313
3475
|
label: "panel",
|
|
3314
3476
|
frame: (message) => (
|
|
3315
3477
|
// Only the name comes back with the message: the actions and the footer may be what threw.
|
|
3316
|
-
/* @__PURE__ */
|
|
3478
|
+
/* @__PURE__ */ jsx57(Frame, { title: props.title, chevron: props.chevron, className: props.className, broken: true, children: message })
|
|
3317
3479
|
),
|
|
3318
|
-
children: /* @__PURE__ */
|
|
3480
|
+
children: /* @__PURE__ */ jsx57(Frame, { ...props })
|
|
3319
3481
|
}
|
|
3320
3482
|
);
|
|
3321
3483
|
}
|
|
3322
3484
|
|
|
3323
3485
|
// src/ListColumn.tsx
|
|
3324
|
-
import { jsx as
|
|
3486
|
+
import { jsx as jsx58, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
3325
3487
|
function Column({ title, chevron = false, actions, above, collapsed = false, children, className, broken = false }) {
|
|
3326
|
-
return /* @__PURE__ */
|
|
3488
|
+
return /* @__PURE__ */ jsxs41(
|
|
3327
3489
|
"div",
|
|
3328
3490
|
{
|
|
3329
3491
|
className: cn(
|
|
@@ -3334,78 +3496,35 @@ function Column({ title, chevron = false, actions, above, collapsed = false, chi
|
|
|
3334
3496
|
),
|
|
3335
3497
|
"data-collapsed": collapsed || void 0,
|
|
3336
3498
|
children: [
|
|
3337
|
-
/* @__PURE__ */
|
|
3499
|
+
/* @__PURE__ */ jsx58(ContainerHeader, { title, chevron, actions }),
|
|
3338
3500
|
above,
|
|
3339
3501
|
broken ? (
|
|
3340
3502
|
// The message takes the room the list had and centres itself in it (Katerina, 19 September).
|
|
3341
|
-
/* @__PURE__ */
|
|
3342
|
-
) : /* @__PURE__ */
|
|
3503
|
+
/* @__PURE__ */ jsx58("div", { className: "flex min-h-0 flex-1 flex-col px-3", children })
|
|
3504
|
+
) : /* @__PURE__ */ jsx58(ScrollArea, { className: "flex-1", contentClassName: "flex flex-col gap-0.5 px-3 pt-4 pb-3", children })
|
|
3343
3505
|
]
|
|
3344
3506
|
}
|
|
3345
3507
|
);
|
|
3346
3508
|
}
|
|
3347
3509
|
function ListColumn(props) {
|
|
3348
|
-
return /* @__PURE__ */
|
|
3510
|
+
return /* @__PURE__ */ jsx58(
|
|
3349
3511
|
ErrorBoundary,
|
|
3350
3512
|
{
|
|
3351
3513
|
label: "list panel",
|
|
3352
3514
|
frame: (message) => (
|
|
3353
3515
|
// Only the name comes back with the message: the actions and the row above may be what threw.
|
|
3354
|
-
/* @__PURE__ */
|
|
3516
|
+
/* @__PURE__ */ jsx58(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
|
|
3355
3517
|
),
|
|
3356
|
-
children: /* @__PURE__ */
|
|
3518
|
+
children: /* @__PURE__ */ jsx58(Column, { ...props })
|
|
3357
3519
|
}
|
|
3358
3520
|
);
|
|
3359
3521
|
}
|
|
3360
3522
|
|
|
3361
|
-
// src/CollapsibleSection.tsx
|
|
3362
|
-
import { useState as useState8 } from "react";
|
|
3363
|
-
import { Collapsible } from "@base-ui/react/collapsible";
|
|
3364
|
-
import { jsx as jsx57, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3365
|
-
var OPEN = "open";
|
|
3366
|
-
var CLOSED = "closed";
|
|
3367
|
-
function readStored(key) {
|
|
3368
|
-
if (!key) return void 0;
|
|
3369
|
-
try {
|
|
3370
|
-
const value = window.localStorage.getItem(key);
|
|
3371
|
-
return value === OPEN ? true : value === CLOSED ? false : void 0;
|
|
3372
|
-
} catch {
|
|
3373
|
-
return void 0;
|
|
3374
|
-
}
|
|
3375
|
-
}
|
|
3376
|
-
function writeStored(key, open) {
|
|
3377
|
-
if (!key) return;
|
|
3378
|
-
try {
|
|
3379
|
-
window.localStorage.setItem(key, open ? OPEN : CLOSED);
|
|
3380
|
-
} catch {
|
|
3381
|
-
}
|
|
3382
|
-
}
|
|
3383
|
-
function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, trailing, actions, showActions, look = "heading", children, className, contentClassName }) {
|
|
3384
|
-
const [openState, setOpenState] = useState8(() => readStored(storageKey) ?? defaultOpen);
|
|
3385
|
-
const open = openProp ?? openState;
|
|
3386
|
-
const setOpen = (next) => {
|
|
3387
|
-
setOpenState(next);
|
|
3388
|
-
writeStored(storageKey, next);
|
|
3389
|
-
onOpenChange?.(next);
|
|
3390
|
-
};
|
|
3391
|
-
return /* @__PURE__ */ jsxs40(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
|
|
3392
|
-
/* @__PURE__ */ jsx57(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, look, className: "shrink-0", render: /* @__PURE__ */ jsx57(Collapsible.Trigger, {}) }),
|
|
3393
|
-
/* @__PURE__ */ jsx57(
|
|
3394
|
-
Collapsible.Panel,
|
|
3395
|
-
{
|
|
3396
|
-
hiddenUntilFound: true,
|
|
3397
|
-
className: "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0",
|
|
3398
|
-
children: /* @__PURE__ */ jsx57("div", { className: cn("flex flex-col", look === "row" && "pl-6", contentClassName), children })
|
|
3399
|
-
}
|
|
3400
|
-
)
|
|
3401
|
-
] });
|
|
3402
|
-
}
|
|
3403
|
-
|
|
3404
3523
|
// src/Tabs.tsx
|
|
3405
3524
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
3406
|
-
import { jsx as
|
|
3525
|
+
import { jsx as jsx59, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
3407
3526
|
function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
|
|
3408
|
-
return /* @__PURE__ */
|
|
3527
|
+
return /* @__PURE__ */ jsx59(
|
|
3409
3528
|
BaseTabs.Root,
|
|
3410
3529
|
{
|
|
3411
3530
|
value: active,
|
|
@@ -3413,14 +3532,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
3413
3532
|
if (details.reason === "none") onChange(value);
|
|
3414
3533
|
},
|
|
3415
3534
|
className,
|
|
3416
|
-
children: /* @__PURE__ */
|
|
3535
|
+
children: /* @__PURE__ */ jsx59(
|
|
3417
3536
|
BaseTabs.List,
|
|
3418
3537
|
{
|
|
3419
3538
|
activateOnFocus: true,
|
|
3420
3539
|
"aria-label": aria["aria-label"],
|
|
3421
3540
|
"aria-labelledby": aria["aria-labelledby"],
|
|
3422
3541
|
className: "flex items-center gap-2",
|
|
3423
|
-
children: tabs.map((tab) => /* @__PURE__ */
|
|
3542
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs42(
|
|
3424
3543
|
BaseTabs.Tab,
|
|
3425
3544
|
{
|
|
3426
3545
|
value: tab.id,
|
|
@@ -3433,9 +3552,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
3433
3552
|
),
|
|
3434
3553
|
children: [
|
|
3435
3554
|
tab.icon,
|
|
3436
|
-
/* @__PURE__ */
|
|
3555
|
+
/* @__PURE__ */ jsxs42("span", { className: "flex items-baseline", children: [
|
|
3437
3556
|
tab.label,
|
|
3438
|
-
tab.count !== void 0 ? /* @__PURE__ */
|
|
3557
|
+
tab.count !== void 0 ? /* @__PURE__ */ jsx59("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
|
|
3439
3558
|
] })
|
|
3440
3559
|
]
|
|
3441
3560
|
},
|
|
@@ -3451,7 +3570,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
3451
3570
|
import { createContext as createContext6, useContext as useContext6, useMemo as useMemo5 } from "react";
|
|
3452
3571
|
import { Toast as BaseToast } from "@base-ui/react/toast";
|
|
3453
3572
|
import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
|
|
3454
|
-
import { jsx as
|
|
3573
|
+
import { jsx as jsx60, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3455
3574
|
var SURFACE_STYLES = {
|
|
3456
3575
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
|
|
3457
3576
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
|
|
@@ -3487,16 +3606,16 @@ var pillClassName = (type, hasAction, className) => cn(
|
|
|
3487
3606
|
);
|
|
3488
3607
|
function LeadingIcon({ type }) {
|
|
3489
3608
|
const Icon = ICONS[type];
|
|
3490
|
-
return /* @__PURE__ */
|
|
3609
|
+
return /* @__PURE__ */ jsx60(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
|
|
3491
3610
|
}
|
|
3492
3611
|
function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
|
|
3493
3612
|
const hasAction = !!(actionLabel && onAction);
|
|
3494
|
-
return /* @__PURE__ */
|
|
3495
|
-
/* @__PURE__ */
|
|
3496
|
-
leadingIcon && /* @__PURE__ */
|
|
3497
|
-
/* @__PURE__ */
|
|
3613
|
+
return /* @__PURE__ */ jsxs43("div", { className: pillClassName(type, hasAction, className), children: [
|
|
3614
|
+
/* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
3615
|
+
leadingIcon && /* @__PURE__ */ jsx60(LeadingIcon, { type }),
|
|
3616
|
+
/* @__PURE__ */ jsx60("span", { className: LABEL_CLASSES, children: label })
|
|
3498
3617
|
] }),
|
|
3499
|
-
hasAction && /* @__PURE__ */
|
|
3618
|
+
hasAction && /* @__PURE__ */ jsx60(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
|
|
3500
3619
|
] });
|
|
3501
3620
|
}
|
|
3502
3621
|
var ToastContext = createContext6(null);
|
|
@@ -3517,9 +3636,9 @@ function ToastProvider({ children }) {
|
|
|
3517
3636
|
}),
|
|
3518
3637
|
[manager]
|
|
3519
3638
|
);
|
|
3520
|
-
return /* @__PURE__ */
|
|
3639
|
+
return /* @__PURE__ */ jsx60(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs43(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
|
|
3521
3640
|
children,
|
|
3522
|
-
/* @__PURE__ */
|
|
3641
|
+
/* @__PURE__ */ jsx60(BaseToast.Portal, { children: /* @__PURE__ */ jsx60(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx60(ToastList, {}) }) })
|
|
3523
3642
|
] }) });
|
|
3524
3643
|
}
|
|
3525
3644
|
function ToastList() {
|
|
@@ -3527,25 +3646,25 @@ function ToastList() {
|
|
|
3527
3646
|
return toasts.map((toast) => {
|
|
3528
3647
|
const type = toast.type ?? "neutral";
|
|
3529
3648
|
const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
|
|
3530
|
-
return /* @__PURE__ */
|
|
3649
|
+
return /* @__PURE__ */ jsxs43(
|
|
3531
3650
|
BaseToast.Root,
|
|
3532
3651
|
{
|
|
3533
3652
|
toast,
|
|
3534
3653
|
swipeDirection: ["left", "down"],
|
|
3535
3654
|
className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
|
|
3536
3655
|
children: [
|
|
3537
|
-
/* @__PURE__ */
|
|
3538
|
-
leadingIcon && /* @__PURE__ */
|
|
3539
|
-
/* @__PURE__ */
|
|
3656
|
+
/* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
3657
|
+
leadingIcon && /* @__PURE__ */ jsx60(LeadingIcon, { type }),
|
|
3658
|
+
/* @__PURE__ */ jsx60(BaseToast.Title, { render: /* @__PURE__ */ jsx60("span", {}), className: LABEL_CLASSES })
|
|
3540
3659
|
] }),
|
|
3541
|
-
actionLabel && /* @__PURE__ */
|
|
3660
|
+
actionLabel && /* @__PURE__ */ jsx60(
|
|
3542
3661
|
BaseToast.Action,
|
|
3543
3662
|
{
|
|
3544
3663
|
onClick: () => {
|
|
3545
3664
|
onAction?.();
|
|
3546
3665
|
close(toast.id);
|
|
3547
3666
|
},
|
|
3548
|
-
render: /* @__PURE__ */
|
|
3667
|
+
render: /* @__PURE__ */ jsx60(Button, { variant: "outlined", size: "small", children: actionLabel })
|
|
3549
3668
|
}
|
|
3550
3669
|
)
|
|
3551
3670
|
]
|
|
@@ -3623,6 +3742,7 @@ export {
|
|
|
3623
3742
|
MenuSeparator,
|
|
3624
3743
|
MenuSub,
|
|
3625
3744
|
NavItem,
|
|
3745
|
+
NavTree,
|
|
3626
3746
|
Panel,
|
|
3627
3747
|
Person,
|
|
3628
3748
|
PersonTrigger,
|