@geomak/ui 3.0.0 → 4.0.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/index.cjs +231 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -15
- package/dist/index.d.ts +59 -15
- package/dist/index.js +231 -86
- package/dist/index.js.map +1 -1
- package/dist/styles.css +14 -4
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1812,40 +1812,84 @@ interface AutoCompleteProps {
|
|
|
1812
1812
|
*/
|
|
1813
1813
|
declare function AutoComplete({ disabled, label, placeholder, name, inputStyle, style, layout, items, onItemClick, emptyText, }: AutoCompleteProps): react_jsx_runtime.JSX.Element;
|
|
1814
1814
|
|
|
1815
|
-
interface
|
|
1815
|
+
interface TreeSelectNode {
|
|
1816
1816
|
key: string | number;
|
|
1817
1817
|
label: React$1.ReactNode;
|
|
1818
1818
|
icon?: React$1.ReactNode;
|
|
1819
|
+
/** Nested children. If present, this node is treated as a parent (branch). */
|
|
1820
|
+
children?: TreeSelectNode[];
|
|
1821
|
+
/** Render the node disabled — visible but not selectable. */
|
|
1822
|
+
disabled?: boolean;
|
|
1819
1823
|
}
|
|
1820
1824
|
interface TreeSelectProps {
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
value?:
|
|
1825
|
+
/** Tree data. Each node may optionally carry `children` for sub-branches. */
|
|
1826
|
+
items: TreeSelectNode[];
|
|
1827
|
+
/** Currently selected key (single-select). Pass `undefined`/`null` for unset. */
|
|
1828
|
+
value?: string | number | null;
|
|
1829
|
+
/** Fires with the next selected key (and the corresponding event-like target). */
|
|
1825
1830
|
onChange?: (e: {
|
|
1826
1831
|
target: {
|
|
1827
|
-
value:
|
|
1832
|
+
value: string | number;
|
|
1828
1833
|
id?: string;
|
|
1829
1834
|
name?: string;
|
|
1830
1835
|
};
|
|
1831
1836
|
}) => void;
|
|
1832
|
-
|
|
1837
|
+
label?: React$1.ReactNode;
|
|
1838
|
+
placeholder?: string;
|
|
1839
|
+
/** Form control id linkage. */
|
|
1840
|
+
htmlFor?: string;
|
|
1841
|
+
name?: string;
|
|
1842
|
+
/** Label/trigger orientation. Defaults to `'horizontal'`. */
|
|
1843
|
+
layout?: 'horizontal' | 'vertical';
|
|
1833
1844
|
disabled?: boolean;
|
|
1834
|
-
/** 'horizontal' | 'vertical' */
|
|
1835
|
-
layout?: string;
|
|
1836
1845
|
errorMessage?: React$1.ReactNode;
|
|
1837
1846
|
style?: React$1.CSSProperties;
|
|
1838
|
-
|
|
1839
|
-
|
|
1847
|
+
/**
|
|
1848
|
+
* Whether parent (branch) nodes can be selected. When `false`, parents
|
|
1849
|
+
* only expand/collapse and only leaves are picked. Default `true`.
|
|
1850
|
+
*/
|
|
1851
|
+
parentsSelectable?: boolean;
|
|
1852
|
+
/** Keys of nodes that should start expanded. */
|
|
1853
|
+
defaultExpandedKeys?: (string | number)[];
|
|
1840
1854
|
}
|
|
1841
1855
|
/**
|
|
1842
|
-
*
|
|
1843
|
-
*
|
|
1856
|
+
* Hierarchical single-select with expandable branches.
|
|
1857
|
+
*
|
|
1858
|
+
* Built on `@radix-ui/react-popover` for portal positioning and click-outside.
|
|
1859
|
+
* Tree state (expanded keys) is local; selected value is controlled by the
|
|
1860
|
+
* parent.
|
|
1861
|
+
*
|
|
1862
|
+
* **Keyboard model** (focus is on the trigger or any item):
|
|
1863
|
+
* - `Enter` / `Space` / `↓` / `↑` on the trigger — open the popover
|
|
1864
|
+
* - `↓` / `↑` — move active item through the visible (un-collapsed) list
|
|
1865
|
+
* - `→` — expand a branch (or move into it if already expanded)
|
|
1866
|
+
* - `←` — collapse a branch (or move to its parent if already collapsed)
|
|
1867
|
+
* - `Enter` / `Space` — select the active item (if selectable)
|
|
1868
|
+
* - `Esc` — close the popover, return focus to the trigger
|
|
1844
1869
|
*
|
|
1845
1870
|
* @example
|
|
1846
|
-
*
|
|
1871
|
+
* ```tsx
|
|
1872
|
+
* type FleetKey = number
|
|
1873
|
+
* const [fleet, setFleet] = useState<FleetKey | null>(null)
|
|
1874
|
+
*
|
|
1875
|
+
* const tree: TreeSelectNode[] = [
|
|
1876
|
+
* { key: 'eu', label: 'Europe', children: [
|
|
1877
|
+
* { key: 1, label: 'Aegean Fleet' },
|
|
1878
|
+
* { key: 2, label: 'Adriatic Fleet' },
|
|
1879
|
+
* ]},
|
|
1880
|
+
* { key: 'asia', label: 'Asia', children: [{ key: 3, label: 'Pacific Fleet' }] },
|
|
1881
|
+
* ]
|
|
1882
|
+
*
|
|
1883
|
+
* <TreeSelect
|
|
1884
|
+
* label="Fleet"
|
|
1885
|
+
* items={tree}
|
|
1886
|
+
* value={fleet}
|
|
1887
|
+
* onChange={({ target }) => setFleet(target.value as FleetKey)}
|
|
1888
|
+
* parentsSelectable={false}
|
|
1889
|
+
* />
|
|
1890
|
+
* ```
|
|
1847
1891
|
*/
|
|
1848
|
-
declare function TreeSelect({ label, name, value, onChange, disabled, layout, errorMessage, style, htmlFor, items, }: TreeSelectProps): react_jsx_runtime.JSX.Element;
|
|
1892
|
+
declare function TreeSelect({ label, name, value, onChange, disabled, layout, errorMessage, style, htmlFor, items, placeholder, parentsSelectable, defaultExpandedKeys, }: TreeSelectProps): react_jsx_runtime.JSX.Element;
|
|
1849
1893
|
|
|
1850
1894
|
interface FileInputProps {
|
|
1851
1895
|
allowMultiple?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -1812,40 +1812,84 @@ interface AutoCompleteProps {
|
|
|
1812
1812
|
*/
|
|
1813
1813
|
declare function AutoComplete({ disabled, label, placeholder, name, inputStyle, style, layout, items, onItemClick, emptyText, }: AutoCompleteProps): react_jsx_runtime.JSX.Element;
|
|
1814
1814
|
|
|
1815
|
-
interface
|
|
1815
|
+
interface TreeSelectNode {
|
|
1816
1816
|
key: string | number;
|
|
1817
1817
|
label: React$1.ReactNode;
|
|
1818
1818
|
icon?: React$1.ReactNode;
|
|
1819
|
+
/** Nested children. If present, this node is treated as a parent (branch). */
|
|
1820
|
+
children?: TreeSelectNode[];
|
|
1821
|
+
/** Render the node disabled — visible but not selectable. */
|
|
1822
|
+
disabled?: boolean;
|
|
1819
1823
|
}
|
|
1820
1824
|
interface TreeSelectProps {
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
value?:
|
|
1825
|
+
/** Tree data. Each node may optionally carry `children` for sub-branches. */
|
|
1826
|
+
items: TreeSelectNode[];
|
|
1827
|
+
/** Currently selected key (single-select). Pass `undefined`/`null` for unset. */
|
|
1828
|
+
value?: string | number | null;
|
|
1829
|
+
/** Fires with the next selected key (and the corresponding event-like target). */
|
|
1825
1830
|
onChange?: (e: {
|
|
1826
1831
|
target: {
|
|
1827
|
-
value:
|
|
1832
|
+
value: string | number;
|
|
1828
1833
|
id?: string;
|
|
1829
1834
|
name?: string;
|
|
1830
1835
|
};
|
|
1831
1836
|
}) => void;
|
|
1832
|
-
|
|
1837
|
+
label?: React$1.ReactNode;
|
|
1838
|
+
placeholder?: string;
|
|
1839
|
+
/** Form control id linkage. */
|
|
1840
|
+
htmlFor?: string;
|
|
1841
|
+
name?: string;
|
|
1842
|
+
/** Label/trigger orientation. Defaults to `'horizontal'`. */
|
|
1843
|
+
layout?: 'horizontal' | 'vertical';
|
|
1833
1844
|
disabled?: boolean;
|
|
1834
|
-
/** 'horizontal' | 'vertical' */
|
|
1835
|
-
layout?: string;
|
|
1836
1845
|
errorMessage?: React$1.ReactNode;
|
|
1837
1846
|
style?: React$1.CSSProperties;
|
|
1838
|
-
|
|
1839
|
-
|
|
1847
|
+
/**
|
|
1848
|
+
* Whether parent (branch) nodes can be selected. When `false`, parents
|
|
1849
|
+
* only expand/collapse and only leaves are picked. Default `true`.
|
|
1850
|
+
*/
|
|
1851
|
+
parentsSelectable?: boolean;
|
|
1852
|
+
/** Keys of nodes that should start expanded. */
|
|
1853
|
+
defaultExpandedKeys?: (string | number)[];
|
|
1840
1854
|
}
|
|
1841
1855
|
/**
|
|
1842
|
-
*
|
|
1843
|
-
*
|
|
1856
|
+
* Hierarchical single-select with expandable branches.
|
|
1857
|
+
*
|
|
1858
|
+
* Built on `@radix-ui/react-popover` for portal positioning and click-outside.
|
|
1859
|
+
* Tree state (expanded keys) is local; selected value is controlled by the
|
|
1860
|
+
* parent.
|
|
1861
|
+
*
|
|
1862
|
+
* **Keyboard model** (focus is on the trigger or any item):
|
|
1863
|
+
* - `Enter` / `Space` / `↓` / `↑` on the trigger — open the popover
|
|
1864
|
+
* - `↓` / `↑` — move active item through the visible (un-collapsed) list
|
|
1865
|
+
* - `→` — expand a branch (or move into it if already expanded)
|
|
1866
|
+
* - `←` — collapse a branch (or move to its parent if already collapsed)
|
|
1867
|
+
* - `Enter` / `Space` — select the active item (if selectable)
|
|
1868
|
+
* - `Esc` — close the popover, return focus to the trigger
|
|
1844
1869
|
*
|
|
1845
1870
|
* @example
|
|
1846
|
-
*
|
|
1871
|
+
* ```tsx
|
|
1872
|
+
* type FleetKey = number
|
|
1873
|
+
* const [fleet, setFleet] = useState<FleetKey | null>(null)
|
|
1874
|
+
*
|
|
1875
|
+
* const tree: TreeSelectNode[] = [
|
|
1876
|
+
* { key: 'eu', label: 'Europe', children: [
|
|
1877
|
+
* { key: 1, label: 'Aegean Fleet' },
|
|
1878
|
+
* { key: 2, label: 'Adriatic Fleet' },
|
|
1879
|
+
* ]},
|
|
1880
|
+
* { key: 'asia', label: 'Asia', children: [{ key: 3, label: 'Pacific Fleet' }] },
|
|
1881
|
+
* ]
|
|
1882
|
+
*
|
|
1883
|
+
* <TreeSelect
|
|
1884
|
+
* label="Fleet"
|
|
1885
|
+
* items={tree}
|
|
1886
|
+
* value={fleet}
|
|
1887
|
+
* onChange={({ target }) => setFleet(target.value as FleetKey)}
|
|
1888
|
+
* parentsSelectable={false}
|
|
1889
|
+
* />
|
|
1890
|
+
* ```
|
|
1847
1891
|
*/
|
|
1848
|
-
declare function TreeSelect({ label, name, value, onChange, disabled, layout, errorMessage, style, htmlFor, items, }: TreeSelectProps): react_jsx_runtime.JSX.Element;
|
|
1892
|
+
declare function TreeSelect({ label, name, value, onChange, disabled, layout, errorMessage, style, htmlFor, items, placeholder, parentsSelectable, defaultExpandedKeys, }: TreeSelectProps): react_jsx_runtime.JSX.Element;
|
|
1849
1893
|
|
|
1850
1894
|
interface FileInputProps {
|
|
1851
1895
|
allowMultiple?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -3143,6 +3143,26 @@ function AutoComplete({
|
|
|
3143
3143
|
}
|
|
3144
3144
|
) });
|
|
3145
3145
|
}
|
|
3146
|
+
function flattenVisible(items, expanded, depth = 0, out = []) {
|
|
3147
|
+
for (const node of items) {
|
|
3148
|
+
const isParent2 = !!node.children && node.children.length > 0;
|
|
3149
|
+
out.push({ node, depth, isParent: isParent2 });
|
|
3150
|
+
if (isParent2 && expanded.has(node.key)) {
|
|
3151
|
+
flattenVisible(node.children, expanded, depth + 1, out);
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
return out;
|
|
3155
|
+
}
|
|
3156
|
+
function findNodeByKey(items, key) {
|
|
3157
|
+
for (const n of items) {
|
|
3158
|
+
if (n.key === key) return n;
|
|
3159
|
+
if (n.children) {
|
|
3160
|
+
const found = findNodeByKey(n.children, key);
|
|
3161
|
+
if (found) return found;
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
return null;
|
|
3165
|
+
}
|
|
3146
3166
|
function TreeSelect({
|
|
3147
3167
|
label,
|
|
3148
3168
|
name,
|
|
@@ -3151,106 +3171,231 @@ function TreeSelect({
|
|
|
3151
3171
|
disabled,
|
|
3152
3172
|
layout = "horizontal",
|
|
3153
3173
|
errorMessage,
|
|
3154
|
-
style
|
|
3174
|
+
style,
|
|
3155
3175
|
htmlFor,
|
|
3156
|
-
items = []
|
|
3176
|
+
items = [],
|
|
3177
|
+
placeholder = "Select\u2026",
|
|
3178
|
+
parentsSelectable = true,
|
|
3179
|
+
defaultExpandedKeys = []
|
|
3157
3180
|
}) {
|
|
3181
|
+
const errorId = useId();
|
|
3182
|
+
const hasError = errorMessage != null;
|
|
3158
3183
|
const [open, setOpen] = useState(false);
|
|
3159
|
-
const [
|
|
3160
|
-
const [
|
|
3184
|
+
const [expanded, setExpanded] = useState(() => new Set(defaultExpandedKeys));
|
|
3185
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
3186
|
+
const listRef = useRef(null);
|
|
3187
|
+
const visible = useMemo(() => flattenVisible(items, expanded), [items, expanded]);
|
|
3161
3188
|
useEffect(() => {
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3189
|
+
if (!open) return;
|
|
3190
|
+
const selectedIdx = visible.findIndex((v) => v.node.key === value);
|
|
3191
|
+
setActiveIndex(selectedIdx >= 0 ? selectedIdx : 0);
|
|
3192
|
+
}, [open, visible, value]);
|
|
3193
|
+
const selectedNode = useMemo(
|
|
3194
|
+
() => value != null ? findNodeByKey(items, value) : null,
|
|
3195
|
+
[items, value]
|
|
3196
|
+
);
|
|
3197
|
+
const toggleExpand = (key) => {
|
|
3198
|
+
setExpanded((prev) => {
|
|
3199
|
+
const next = new Set(prev);
|
|
3200
|
+
if (next.has(key)) next.delete(key);
|
|
3201
|
+
else next.add(key);
|
|
3202
|
+
return next;
|
|
3203
|
+
});
|
|
3204
|
+
};
|
|
3205
|
+
const selectKey = (key) => {
|
|
3165
3206
|
onChange?.({ target: { value: key, id: htmlFor, name } });
|
|
3166
3207
|
setOpen(false);
|
|
3167
3208
|
};
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3209
|
+
const onListKey = (e) => {
|
|
3210
|
+
if (visible.length === 0) return;
|
|
3211
|
+
const cur = visible[activeIndex];
|
|
3212
|
+
if (e.key === "ArrowDown") {
|
|
3213
|
+
e.preventDefault();
|
|
3214
|
+
setActiveIndex((i) => Math.min(i + 1, visible.length - 1));
|
|
3215
|
+
} else if (e.key === "ArrowUp") {
|
|
3216
|
+
e.preventDefault();
|
|
3217
|
+
setActiveIndex((i) => Math.max(i - 1, 0));
|
|
3218
|
+
} else if (e.key === "ArrowRight") {
|
|
3219
|
+
e.preventDefault();
|
|
3220
|
+
if (cur.isParent) {
|
|
3221
|
+
if (!expanded.has(cur.node.key)) toggleExpand(cur.node.key);
|
|
3222
|
+
else setActiveIndex((i) => Math.min(i + 1, visible.length - 1));
|
|
3223
|
+
}
|
|
3224
|
+
} else if (e.key === "ArrowLeft") {
|
|
3225
|
+
e.preventDefault();
|
|
3226
|
+
if (cur.isParent && expanded.has(cur.node.key)) {
|
|
3227
|
+
toggleExpand(cur.node.key);
|
|
3228
|
+
} else if (cur.depth > 0) {
|
|
3229
|
+
for (let i = activeIndex - 1; i >= 0; i--) {
|
|
3230
|
+
if (visible[i].depth < cur.depth) {
|
|
3231
|
+
setActiveIndex(i);
|
|
3232
|
+
break;
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
} else if (e.key === "Enter" || e.key === " ") {
|
|
3237
|
+
e.preventDefault();
|
|
3238
|
+
if (cur.node.disabled) return;
|
|
3239
|
+
if (cur.isParent && !parentsSelectable) {
|
|
3240
|
+
toggleExpand(cur.node.key);
|
|
3241
|
+
} else {
|
|
3242
|
+
selectKey(cur.node.key);
|
|
3243
|
+
}
|
|
3244
|
+
} else if (e.key === "Escape") {
|
|
3245
|
+
e.preventDefault();
|
|
3246
|
+
setOpen(false);
|
|
3247
|
+
}
|
|
3248
|
+
};
|
|
3249
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3250
|
+
/* @__PURE__ */ jsxs("div", { className: `flex ${layout === "vertical" ? "flex-col gap-1" : "flex-row items-center gap-2"}`, children: [
|
|
3251
|
+
label && /* @__PURE__ */ jsx(
|
|
3252
|
+
"label",
|
|
3253
|
+
{
|
|
3254
|
+
className: "text-sm font-medium ml-1 max-content select-none text-foreground",
|
|
3255
|
+
htmlFor,
|
|
3256
|
+
children: label
|
|
3257
|
+
}
|
|
3258
|
+
),
|
|
3259
|
+
/* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
|
|
3260
|
+
/* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
3261
|
+
"button",
|
|
3262
|
+
{
|
|
3263
|
+
id: htmlFor,
|
|
3264
|
+
type: "button",
|
|
3265
|
+
style,
|
|
3266
|
+
role: "combobox",
|
|
3267
|
+
"aria-expanded": open,
|
|
3268
|
+
"aria-haspopup": "listbox",
|
|
3269
|
+
"aria-invalid": hasError || void 0,
|
|
3270
|
+
"aria-describedby": hasError ? errorId : void 0,
|
|
3271
|
+
disabled,
|
|
3272
|
+
className: `flex items-center justify-between h-9 rounded-lg border ${hasError ? "border-status-error" : "border-border"} px-3 cursor-pointer select-none focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${disabled ? "cursor-not-allowed bg-surface-raised text-foreground-muted" : "bg-surface text-foreground"} ${!style?.width ? "min-w-[240px]" : ""}`,
|
|
3273
|
+
children: [
|
|
3274
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm truncate text-left", children: selectedNode ? selectedNode.label : /* @__PURE__ */ jsx("span", { className: "text-foreground-muted", children: placeholder }) }),
|
|
3275
|
+
/* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: `h-4 w-4 flex-shrink-0 transition-transform duration-200 ${open ? "rotate-180" : ""}`, "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })
|
|
3276
|
+
]
|
|
3277
|
+
}
|
|
3278
|
+
) }),
|
|
3279
|
+
/* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
|
|
3280
|
+
Popover.Content,
|
|
3281
|
+
{
|
|
3282
|
+
align: "start",
|
|
3283
|
+
sideOffset: 4,
|
|
3284
|
+
style: { width: style?.width || 280 },
|
|
3285
|
+
className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-1 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
3286
|
+
onOpenAutoFocus: (e) => {
|
|
3287
|
+
e.preventDefault();
|
|
3288
|
+
listRef.current?.focus();
|
|
3289
|
+
},
|
|
3290
|
+
children: /* @__PURE__ */ jsx(
|
|
3184
3291
|
"div",
|
|
3185
3292
|
{
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
"aria-
|
|
3190
|
-
|
|
3191
|
-
className:
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
/* @__PURE__ */ jsx("div", { className: `h-7 ${!style?.width ? "min-w-[240px]" : ""} focus:outline-none text-prussian-blue flex items-center gap-1`, children: Array.isArray(value) ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3195
|
-
value.slice(0, 1).map((val, id) => /* @__PURE__ */ jsx(
|
|
3196
|
-
DropdownPill,
|
|
3197
|
-
{
|
|
3198
|
-
hasSiblings: value.length > 1,
|
|
3199
|
-
value: innerItems.find((it) => it.key === val)?.label
|
|
3200
|
-
},
|
|
3201
|
-
id
|
|
3202
|
-
)),
|
|
3203
|
-
value.length > 1 && /* @__PURE__ */ jsx(DropdownPill, { value: `+${value.length - 1} more` })
|
|
3204
|
-
] }) : value != null ? /* @__PURE__ */ jsx(DropdownPill, { value: innerItems.find((it) => it.key === value)?.label }) : null }),
|
|
3205
|
-
/* @__PURE__ */ jsx("div", { className: `transition-transform duration-300 ml-2 ${open ? "rotate-180" : "rotate-0"}`, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: colors_default.PALETTE["prussian-blue"], strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
|
|
3206
|
-
]
|
|
3207
|
-
}
|
|
3208
|
-
) }),
|
|
3209
|
-
/* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
|
|
3210
|
-
Popover.Content,
|
|
3211
|
-
{
|
|
3212
|
-
align: "start",
|
|
3213
|
-
sideOffset: 4,
|
|
3214
|
-
style: { width: style?.width || 240 },
|
|
3215
|
-
className: "bg-ice rounded-lg shadow-md z-50 p-2 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
3216
|
-
children: /* @__PURE__ */ jsx("div", { role: "listbox", className: "max-h-40 overflow-y-auto", children: innerItems.map((item, idx) => /* @__PURE__ */ jsxs(
|
|
3217
|
-
"div",
|
|
3293
|
+
ref: listRef,
|
|
3294
|
+
role: "tree",
|
|
3295
|
+
tabIndex: -1,
|
|
3296
|
+
"aria-activedescendant": visible[activeIndex] ? `tree-opt-${visible[activeIndex].node.key}` : void 0,
|
|
3297
|
+
onKeyDown: onListKey,
|
|
3298
|
+
className: "max-h-72 overflow-y-auto outline-none",
|
|
3299
|
+
children: visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-4 text-sm text-foreground-secondary text-center", children: "No items" }) : visible.map((v, idx) => /* @__PURE__ */ jsx(
|
|
3300
|
+
TreeNodeRow,
|
|
3218
3301
|
{
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
{
|
|
3234
|
-
d: "M4 10l4.5 4.5L16 6",
|
|
3235
|
-
stroke: hoveredItem === item.key ? "#fff" : colors_default.PALETTE["prussian-blue"],
|
|
3236
|
-
strokeWidth: "2",
|
|
3237
|
-
strokeLinecap: "round",
|
|
3238
|
-
strokeLinejoin: "round"
|
|
3239
|
-
}
|
|
3240
|
-
) })
|
|
3241
|
-
]
|
|
3302
|
+
node: v.node,
|
|
3303
|
+
depth: v.depth,
|
|
3304
|
+
isParent: v.isParent,
|
|
3305
|
+
isExpanded: expanded.has(v.node.key),
|
|
3306
|
+
isActive: idx === activeIndex,
|
|
3307
|
+
isSelected: value === v.node.key,
|
|
3308
|
+
parentsSelectable,
|
|
3309
|
+
onActivate: () => {
|
|
3310
|
+
if (v.node.disabled) return;
|
|
3311
|
+
if (v.isParent && !parentsSelectable) toggleExpand(v.node.key);
|
|
3312
|
+
else selectKey(v.node.key);
|
|
3313
|
+
},
|
|
3314
|
+
onToggle: () => toggleExpand(v.node.key),
|
|
3315
|
+
onHover: () => setActiveIndex(idx)
|
|
3242
3316
|
},
|
|
3243
|
-
|
|
3244
|
-
))
|
|
3317
|
+
v.node.key
|
|
3318
|
+
))
|
|
3245
3319
|
}
|
|
3246
|
-
)
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
}
|
|
3250
|
-
),
|
|
3251
|
-
/* @__PURE__ */ jsx("div", { className: "text-
|
|
3320
|
+
)
|
|
3321
|
+
}
|
|
3322
|
+
) })
|
|
3323
|
+
] })
|
|
3324
|
+
] }),
|
|
3325
|
+
hasError && /* @__PURE__ */ jsx("div", { id: errorId, className: "text-xs text-status-error ml-1", children: errorMessage })
|
|
3252
3326
|
] });
|
|
3253
3327
|
}
|
|
3328
|
+
function TreeNodeRow({
|
|
3329
|
+
node,
|
|
3330
|
+
depth,
|
|
3331
|
+
isParent: isParent2,
|
|
3332
|
+
isExpanded,
|
|
3333
|
+
isActive,
|
|
3334
|
+
isSelected,
|
|
3335
|
+
parentsSelectable,
|
|
3336
|
+
onActivate,
|
|
3337
|
+
onToggle,
|
|
3338
|
+
onHover
|
|
3339
|
+
}) {
|
|
3340
|
+
const disabled = node.disabled;
|
|
3341
|
+
return /* @__PURE__ */ jsxs(
|
|
3342
|
+
"div",
|
|
3343
|
+
{
|
|
3344
|
+
id: `tree-opt-${node.key}`,
|
|
3345
|
+
role: "treeitem",
|
|
3346
|
+
"aria-selected": isSelected,
|
|
3347
|
+
"aria-expanded": isParent2 ? isExpanded : void 0,
|
|
3348
|
+
"aria-disabled": disabled || void 0,
|
|
3349
|
+
"data-active": isActive ? "" : void 0,
|
|
3350
|
+
onMouseEnter: onHover,
|
|
3351
|
+
className: `flex items-center gap-1 rounded-md px-1 py-1.5 select-none cursor-pointer transition-colors duration-100 ${disabled ? "opacity-40 cursor-not-allowed" : isActive ? "bg-accent text-accent-fg" : isSelected ? "bg-surface-raised" : "hover:bg-surface-raised"}`,
|
|
3352
|
+
style: { paddingLeft: depth * 16 + 4 },
|
|
3353
|
+
children: [
|
|
3354
|
+
isParent2 ? /* @__PURE__ */ jsx(
|
|
3355
|
+
"button",
|
|
3356
|
+
{
|
|
3357
|
+
type: "button",
|
|
3358
|
+
onClick: (e) => {
|
|
3359
|
+
e.stopPropagation();
|
|
3360
|
+
onToggle();
|
|
3361
|
+
},
|
|
3362
|
+
"aria-label": isExpanded ? "Collapse" : "Expand",
|
|
3363
|
+
tabIndex: -1,
|
|
3364
|
+
className: "w-5 h-5 inline-flex items-center justify-center rounded hover:bg-black/10 focus:outline-none",
|
|
3365
|
+
children: /* @__PURE__ */ jsx(
|
|
3366
|
+
"svg",
|
|
3367
|
+
{
|
|
3368
|
+
viewBox: "0 0 24 24",
|
|
3369
|
+
fill: "none",
|
|
3370
|
+
stroke: "currentColor",
|
|
3371
|
+
strokeWidth: 2.5,
|
|
3372
|
+
className: `h-3 w-3 transition-transform duration-150 ${isExpanded ? "rotate-0" : "-rotate-90"}`,
|
|
3373
|
+
"aria-hidden": "true",
|
|
3374
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" })
|
|
3375
|
+
}
|
|
3376
|
+
)
|
|
3377
|
+
}
|
|
3378
|
+
) : /* @__PURE__ */ jsx("span", { className: "w-5 h-5 inline-block", "aria-hidden": "true" }),
|
|
3379
|
+
/* @__PURE__ */ jsxs(
|
|
3380
|
+
"button",
|
|
3381
|
+
{
|
|
3382
|
+
type: "button",
|
|
3383
|
+
onClick: onActivate,
|
|
3384
|
+
disabled,
|
|
3385
|
+
tabIndex: -1,
|
|
3386
|
+
className: "flex-1 flex items-center gap-2 text-sm text-left focus:outline-none disabled:cursor-not-allowed",
|
|
3387
|
+
children: [
|
|
3388
|
+
node.icon,
|
|
3389
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: node.label }),
|
|
3390
|
+
isParent2 && !parentsSelectable && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-foreground-muted", children: "parent" })
|
|
3391
|
+
]
|
|
3392
|
+
}
|
|
3393
|
+
),
|
|
3394
|
+
isSelected && /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", className: "ml-1", children: /* @__PURE__ */ jsx("path", { d: "M4 10l4.5 4.5L16 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
3395
|
+
]
|
|
3396
|
+
}
|
|
3397
|
+
);
|
|
3398
|
+
}
|
|
3254
3399
|
function FileInput({
|
|
3255
3400
|
allowMultiple = false,
|
|
3256
3401
|
onChange,
|