@px-ui/ui 1.0.11 → 1.2.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/{avatar-cLlUF5Lz.d.ts → avatar-BHChvx39.d.ts} +6 -6
- package/dist/{avatar-cLlUF5Lz.d.ts.map → avatar-BHChvx39.d.ts.map} +1 -1
- package/dist/{avatar-a40DzPi3.js → avatar-DnDnGmSj.js} +4 -4
- package/dist/{avatar-a40DzPi3.js.map → avatar-DnDnGmSj.js.map} +1 -1
- package/dist/{button-BJ727apo.d.ts → button-BhyEUVw7.d.ts} +6 -6
- package/dist/{button-BJ727apo.d.ts.map → button-BhyEUVw7.d.ts.map} +1 -1
- package/dist/{button-Cp2S1spE.js → button-DnHwqwy0.js} +2 -2
- package/dist/{button-Cp2S1spE.js.map → button-DnHwqwy0.js.map} +1 -1
- package/dist/checkbox-CwkX29tL.js +22 -0
- package/dist/checkbox-CwkX29tL.js.map +1 -0
- package/dist/collapsible-DsrYXIW5.js +28 -0
- package/dist/collapsible-DsrYXIW5.js.map +1 -0
- package/dist/{combobox-Di5naqIR.js → combobox-5IAivvXw.js} +9 -9
- package/dist/{combobox-Di5naqIR.js.map → combobox-5IAivvXw.js.map} +1 -1
- package/dist/{combobox-B73nb6Tq.d.ts → combobox-BMr1s-el.d.ts} +19 -19
- package/dist/combobox-BMr1s-el.d.ts.map +1 -0
- package/dist/components/accordion.d.ts +5 -5
- package/dist/components/accordion.d.ts.map +1 -1
- package/dist/components/accordion.js +2 -2
- package/dist/components/alert-dialog.d.ts +14 -14
- package/dist/components/alert-dialog.d.ts.map +1 -1
- package/dist/components/alert-dialog.js +3 -3
- package/dist/components/alert.d.ts +7 -7
- package/dist/components/alert.d.ts.map +1 -1
- package/dist/components/alert.js +2 -2
- package/dist/components/aspect-ratio.d.ts +2 -2
- package/dist/components/aspect-ratio.d.ts.map +1 -1
- package/dist/components/aspect-ratio.js +1 -1
- package/dist/components/attachment.d.ts +14 -14
- package/dist/components/attachment.d.ts.map +1 -1
- package/dist/components/attachment.js +3 -3
- package/dist/components/avatar-group.d.ts +4 -4
- package/dist/components/avatar-group.js +5 -5
- package/dist/components/avatar.d.ts +1 -1
- package/dist/components/avatar.js +3 -3
- package/dist/components/badge.d.ts +3 -3
- package/dist/components/badge.js +1 -1
- package/dist/components/breadcrumb.d.ts +7 -7
- package/dist/components/breadcrumb.js +2 -2
- package/dist/components/bubble.d.ts +7 -7
- package/dist/components/bubble.js +2 -2
- package/dist/components/button-group.d.ts +7 -7
- package/dist/components/button-group.d.ts.map +1 -1
- package/dist/components/button-group.js +2 -2
- package/dist/components/button.d.ts +1 -1
- package/dist/components/button.js +2 -2
- package/dist/components/calendar.d.ts +4 -4
- package/dist/components/calendar.d.ts.map +1 -1
- package/dist/components/calendar.js +3 -3
- package/dist/components/card.d.ts +8 -8
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +2 -2
- package/dist/components/carousel.d.ts +7 -7
- package/dist/components/carousel.js +3 -3
- package/dist/components/chart.d.ts +5 -5
- package/dist/components/chart.js +2 -2
- package/dist/components/checkbox.d.ts +2 -2
- package/dist/components/checkbox.js +3 -21
- package/dist/components/collapsible.d.ts +4 -4
- package/dist/components/collapsible.js +3 -27
- package/dist/components/combobox.d.ts +2 -2
- package/dist/components/combobox.js +11 -11
- package/dist/components/command.d.ts +11 -11
- package/dist/components/command.d.ts.map +1 -1
- package/dist/components/command.js +7 -7
- package/dist/components/context-menu.d.ts +16 -16
- package/dist/components/context-menu.d.ts.map +1 -1
- package/dist/components/context-menu.js +2 -2
- package/dist/components/currency-select-field.d.ts +4 -4
- package/dist/components/currency-select-field.js +12 -12
- package/dist/components/dialog.d.ts +11 -11
- package/dist/components/dialog.js +3 -3
- package/dist/components/direction.js +1 -1
- package/dist/components/drawer.d.ts +11 -11
- package/dist/components/drawer.js +2 -2
- package/dist/components/dropdown-menu.d.ts +1 -1
- package/dist/components/dropdown-menu.js +2 -2
- package/dist/components/editor-output.d.ts +87 -0
- package/dist/components/editor-output.d.ts.map +1 -0
- package/dist/components/editor-output.js +158 -0
- package/dist/components/editor-output.js.map +1 -0
- package/dist/components/empty.d.ts +9 -9
- package/dist/components/empty.d.ts.map +1 -1
- package/dist/components/empty.js +3 -61
- package/dist/components/field.d.ts +16 -16
- package/dist/components/field.d.ts.map +1 -1
- package/dist/components/field.js +4 -4
- package/dist/components/file-upload-field.d.ts +3 -3
- package/dist/components/file-upload-field.js +6 -6
- package/dist/components/file-upload.d.ts +3 -3
- package/dist/components/file-upload.js +4 -4
- package/dist/components/hover-card.d.ts +4 -4
- package/dist/components/hover-card.d.ts.map +1 -1
- package/dist/components/hover-card.js +1 -1
- package/dist/components/icon.d.ts +83 -0
- package/dist/components/icon.d.ts.map +1 -0
- package/dist/components/icon.js +188 -0
- package/dist/components/icon.js.map +1 -0
- package/dist/components/input-group.d.ts +11 -11
- package/dist/components/input-group.d.ts.map +1 -1
- package/dist/components/input-group.js +5 -5
- package/dist/components/input-otp.d.ts +6 -6
- package/dist/components/input-otp.d.ts.map +1 -1
- package/dist/components/input-otp.js +6 -6
- package/dist/components/input-otp.js.map +1 -1
- package/dist/components/input.d.ts +1 -1
- package/dist/components/input.js +2 -2
- package/dist/components/item.d.ts +15 -15
- package/dist/components/item.d.ts.map +1 -1
- package/dist/components/item.js +3 -3
- package/dist/components/kbd.d.ts +3 -3
- package/dist/components/kbd.d.ts.map +1 -1
- package/dist/components/kbd.js +1 -1
- package/dist/components/label.d.ts +1 -1
- package/dist/components/label.js +2 -2
- package/dist/components/marker.d.ts +4 -4
- package/dist/components/marker.js +2 -2
- package/dist/components/menubar.d.ts +18 -18
- package/dist/components/menubar.js +8 -8
- package/dist/components/menubar.js.map +1 -1
- package/dist/components/message-scroller.d.ts +8 -8
- package/dist/components/message-scroller.d.ts.map +1 -1
- package/dist/components/message-scroller.js +3 -3
- package/dist/components/message.d.ts +7 -7
- package/dist/components/message.d.ts.map +1 -1
- package/dist/components/message.js +2 -2
- package/dist/components/native-select.d.ts +4 -4
- package/dist/components/native-select.d.ts.map +1 -1
- package/dist/components/native-select.js +2 -2
- package/dist/components/navigation-menu.d.ts +11 -11
- package/dist/components/navigation-menu.d.ts.map +1 -1
- package/dist/components/navigation-menu.js +1 -1
- package/dist/components/pagination.d.ts +9 -9
- package/dist/components/pagination.js +3 -3
- package/dist/components/phone-input.d.ts +2 -2
- package/dist/components/phone-input.d.ts.map +1 -1
- package/dist/components/phone-input.js +2 -2
- package/dist/components/popover.d.ts +7 -7
- package/dist/components/popover.d.ts.map +1 -1
- package/dist/components/popover.js +2 -2
- package/dist/components/progress.d.ts +6 -6
- package/dist/components/progress.d.ts.map +1 -1
- package/dist/components/progress.js +1 -1
- package/dist/components/radio-group.d.ts +3 -3
- package/dist/components/radio-group.js +1 -1
- package/dist/components/resizable.d.ts +4 -4
- package/dist/components/resizable.js +1 -1
- package/dist/components/rich-text-editor.d.ts +204 -0
- package/dist/components/rich-text-editor.d.ts.map +1 -0
- package/dist/components/rich-text-editor.js +359 -0
- package/dist/components/rich-text-editor.js.map +1 -0
- package/dist/components/scroll-area.d.ts +13 -3
- package/dist/components/scroll-area.d.ts.map +1 -1
- package/dist/components/scroll-area.js +3 -38
- package/dist/components/select.d.ts +10 -10
- package/dist/components/select.js +2 -2
- package/dist/components/separator.d.ts +1 -1
- package/dist/components/separator.js +2 -2
- package/dist/components/sheet.d.ts +9 -9
- package/dist/components/sheet.js +3 -3
- package/dist/components/sidebar.d.ts +24 -24
- package/dist/components/sidebar.js +9 -9
- package/dist/components/skeleton.d.ts +2 -2
- package/dist/components/skeleton.js +2 -2
- package/dist/components/slider.d.ts +2 -2
- package/dist/components/slider.js +1 -1
- package/dist/components/sortable-list.d.ts +153 -0
- package/dist/components/sortable-list.d.ts.map +1 -0
- package/dist/components/sortable-list.js +191 -0
- package/dist/components/sortable-list.js.map +1 -0
- package/dist/components/spinner.d.ts +2 -2
- package/dist/components/spinner.js +2 -2
- package/dist/components/stepper.d.ts +171 -0
- package/dist/components/stepper.d.ts.map +1 -0
- package/dist/components/stepper.js +281 -0
- package/dist/components/stepper.js.map +1 -0
- package/dist/components/switch.d.ts +2 -2
- package/dist/components/switch.js +1 -1
- package/dist/components/table.d.ts +9 -9
- package/dist/components/table.js +2 -2
- package/dist/components/tabs.d.ts +8 -8
- package/dist/components/tabs.js +1 -1
- package/dist/components/textarea.d.ts +2 -2
- package/dist/components/textarea.js +2 -2
- package/dist/components/toast.d.ts +1 -1
- package/dist/components/toast.js +2 -2
- package/dist/components/toggle-group.d.ts +4 -4
- package/dist/components/toggle-group.js +3 -3
- package/dist/components/toggle.d.ts +1 -1
- package/dist/components/toggle.js +2 -2
- package/dist/components/tooltip.d.ts +1 -1
- package/dist/components/tooltip.js +2 -2
- package/dist/components/tree-select.d.ts +192 -0
- package/dist/components/tree-select.d.ts.map +1 -0
- package/dist/components/tree-select.js +421 -0
- package/dist/components/tree-select.js.map +1 -0
- package/dist/{dialog-B3HhbIdv.js → dialog-DuGJUPQl.js} +4 -4
- package/dist/{dialog-B3HhbIdv.js.map → dialog-DuGJUPQl.js.map} +1 -1
- package/dist/{dropdown-menu-vwX--mgm.js → dropdown-menu-BWEfcvmP.js} +20 -20
- package/dist/{dropdown-menu-vwX--mgm.js.map → dropdown-menu-BWEfcvmP.js.map} +1 -1
- package/dist/{dropdown-menu-C6n_oYre.d.ts → dropdown-menu-DGMTllRk.d.ts} +17 -17
- package/dist/{dropdown-menu-C6n_oYre.d.ts.map → dropdown-menu-DGMTllRk.d.ts.map} +1 -1
- package/dist/empty-U4zrLmFU.js +62 -0
- package/dist/empty-U4zrLmFU.js.map +1 -0
- package/dist/{file-upload-CGfXHKPZ.d.ts → file-upload-C4i5tbut.d.ts} +13 -13
- package/dist/{file-upload-CGfXHKPZ.d.ts.map → file-upload-C4i5tbut.d.ts.map} +1 -1
- package/dist/{file-upload-B0fHdUBL.js → file-upload-DU5FAkHm.js} +5 -5
- package/dist/{file-upload-B0fHdUBL.js.map → file-upload-DU5FAkHm.js.map} +1 -1
- package/dist/hooks/use-async-options.d.ts +1 -1
- package/dist/hooks/use-async-options.js +1 -1
- package/dist/hooks/use-debounce.js +1 -1
- package/dist/hooks/use-file-upload.d.ts +1 -1
- package/dist/hooks/use-file-upload.js +1 -1
- package/dist/hooks/use-infinite-scroll.d.ts +1 -1
- package/dist/hooks/use-infinite-scroll.js +2 -2
- package/dist/hooks/use-intersection-observer.d.ts +1 -1
- package/dist/hooks/use-intersection-observer.js +1 -1
- package/dist/hooks/use-mobile.js +1 -1
- package/dist/{input-group-C78_1dEy.js → input-group-B5PMRYld.js} +6 -6
- package/dist/{input-group-C78_1dEy.js.map → input-group-B5PMRYld.js.map} +1 -1
- package/dist/{input-B-RCmrtR.js → input-jIoNIdLQ.js} +3 -3
- package/dist/{input-B-RCmrtR.js.map → input-jIoNIdLQ.js.map} +1 -1
- package/dist/{input-BtI3FvrB.d.ts → input-zxE3Qo1O.d.ts} +3 -3
- package/dist/input-zxE3Qo1O.d.ts.map +1 -0
- package/dist/{label-Cmlhz-uF.js → label-DsRhOKY_.js} +3 -3
- package/dist/{label-Cmlhz-uF.js.map → label-DsRhOKY_.js.map} +1 -1
- package/dist/label-wB7C6-hQ.d.ts +11 -0
- package/dist/label-wB7C6-hQ.d.ts.map +1 -0
- package/dist/lib/utils.js +1 -1
- package/dist/{popover-CsTnnBvx.js → popover-BGkU46G7.js} +3 -3
- package/dist/{popover-CsTnnBvx.js.map → popover-BGkU46G7.js.map} +1 -1
- package/dist/providers/px-ui-provider.d.ts +4 -4
- package/dist/providers/px-ui-provider.d.ts.map +1 -1
- package/dist/providers/px-ui-provider.js +4 -4
- package/dist/scroll-area-mNVMQ0Of.js +40 -0
- package/dist/scroll-area-mNVMQ0Of.js.map +1 -0
- package/dist/{separator-BQBOLUMc.js → separator-D0bew2D_.js} +2 -2
- package/dist/{separator-BQBOLUMc.js.map → separator-D0bew2D_.js.map} +1 -1
- package/dist/{separator-pyhTqgkN.d.ts → separator-DMTEE-qR.d.ts} +3 -3
- package/dist/{separator-pyhTqgkN.d.ts.map → separator-DMTEE-qR.d.ts.map} +1 -1
- package/dist/{sheet-Chg_afex.js → sheet-BB23q6wd.js} +4 -4
- package/dist/{sheet-Chg_afex.js.map → sheet-BB23q6wd.js.map} +1 -1
- package/dist/{skeleton-J879XBBA.js → skeleton-knxLhbA5.js} +2 -2
- package/dist/{skeleton-J879XBBA.js.map → skeleton-knxLhbA5.js.map} +1 -1
- package/dist/{spinner-C7yzrK_s.js → spinner-9MdgLDTZ.js} +2 -2
- package/dist/{spinner-C7yzrK_s.js.map → spinner-9MdgLDTZ.js.map} +1 -1
- package/dist/{textarea-CaHmr0re.js → textarea-hZg0gA8u.js} +3 -3
- package/dist/{textarea-CaHmr0re.js.map → textarea-hZg0gA8u.js.map} +1 -1
- package/dist/{toast-CSU7vJkV.d.ts → toast-011e8XdI.d.ts} +5 -5
- package/dist/{toast-CSU7vJkV.d.ts.map → toast-011e8XdI.d.ts.map} +1 -1
- package/dist/{toast-BrPEQywl.js → toast-BdxoP8vz.js} +4 -4
- package/dist/{toast-BrPEQywl.js.map → toast-BdxoP8vz.js.map} +1 -1
- package/dist/{toggle-gjMAPmkg.d.ts → toggle-0BxcVVwi.d.ts} +5 -5
- package/dist/toggle-0BxcVVwi.d.ts.map +1 -0
- package/dist/{toggle-CA4KsgWs.js → toggle-BZXrLBLK.js} +2 -2
- package/dist/{toggle-CA4KsgWs.js.map → toggle-BZXrLBLK.js.map} +1 -1
- package/dist/{tooltip-7bptiThf.d.ts → tooltip-DWoVF4fx.d.ts} +6 -6
- package/dist/{tooltip-7bptiThf.d.ts.map → tooltip-DWoVF4fx.d.ts.map} +1 -1
- package/dist/{tooltip-BhxGE3Gb.js → tooltip-Dsfn_zZD.js} +2 -2
- package/dist/{tooltip-BhxGE3Gb.js.map → tooltip-Dsfn_zZD.js.map} +1 -1
- package/dist/{use-async-options-rNdyxIrQ.d.ts → use-async-options-DdyHJxHh.d.ts} +1 -1
- package/dist/{use-async-options-rNdyxIrQ.d.ts.map → use-async-options-DdyHJxHh.d.ts.map} +1 -1
- package/dist/{use-async-options-CtB4wZrr.js → use-async-options-tueAuVs_.js} +1 -1
- package/dist/{use-async-options-CtB4wZrr.js.map → use-async-options-tueAuVs_.js.map} +1 -1
- package/dist/{use-debounce--Lv1ABSa.js → use-debounce-7gIeOwla.js} +1 -1
- package/dist/{use-debounce--Lv1ABSa.js.map → use-debounce-7gIeOwla.js.map} +1 -1
- package/dist/{use-file-upload-Cbb_9kTw.d.ts → use-file-upload-Bc7CyQ7O.d.ts} +1 -1
- package/dist/{use-file-upload-Cbb_9kTw.d.ts.map → use-file-upload-Bc7CyQ7O.d.ts.map} +1 -1
- package/dist/{use-file-upload-BbERd3Nw.js → use-file-upload-DQD1vY_Z.js} +1 -1
- package/dist/{use-file-upload-BbERd3Nw.js.map → use-file-upload-DQD1vY_Z.js.map} +1 -1
- package/dist/{use-infinite-scroll-CC_Guyvn.js → use-infinite-scroll-HpeMA2MK.js} +2 -2
- package/dist/{use-infinite-scroll-CC_Guyvn.js.map → use-infinite-scroll-HpeMA2MK.js.map} +1 -1
- package/dist/{use-intersection-observer-CgAaXczI.d.ts → use-intersection-observer-DNPextJs.d.ts} +1 -1
- package/dist/{use-intersection-observer-CgAaXczI.d.ts.map → use-intersection-observer-DNPextJs.d.ts.map} +1 -1
- package/dist/{use-intersection-observer-S0wsPmhF.js → use-intersection-observer-rlKEjyL1.js} +1 -1
- package/dist/{use-intersection-observer-S0wsPmhF.js.map → use-intersection-observer-rlKEjyL1.js.map} +1 -1
- package/dist/{use-mobile--NaMWuCj.js → use-mobile-DUqQzj2D.js} +1 -1
- package/dist/{use-mobile--NaMWuCj.js.map → use-mobile-DUqQzj2D.js.map} +1 -1
- package/dist/{utils-DeIaBj75.js → utils-DUlptRpf.js} +1 -1
- package/dist/{utils-DeIaBj75.js.map → utils-DUlptRpf.js.map} +1 -1
- package/package.json +52 -2
- package/dist/combobox-B73nb6Tq.d.ts.map +0 -1
- package/dist/components/checkbox.js.map +0 -1
- package/dist/components/collapsible.js.map +0 -1
- package/dist/components/empty.js.map +0 -1
- package/dist/components/scroll-area.js.map +0 -1
- package/dist/input-BtI3FvrB.d.ts.map +0 -1
- package/dist/label-BnSHwOyi.d.ts +0 -11
- package/dist/label-BnSHwOyi.d.ts.map +0 -1
- package/dist/toggle-gjMAPmkg.d.ts.map +0 -1
- /package/dist/{direction-ZS2Hta3v.js → direction-DFPbwDSF.js} +0 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { t as cn } from "../utils-DUlptRpf.js";
|
|
4
|
+
import { t as Button } from "../button-DnHwqwy0.js";
|
|
5
|
+
import { t as Checkbox } from "../checkbox-CwkX29tL.js";
|
|
6
|
+
import { n as CollapsibleContent, r as CollapsibleTrigger, t as Collapsible } from "../collapsible-DsrYXIW5.js";
|
|
7
|
+
import "../input-jIoNIdLQ.js";
|
|
8
|
+
import "../textarea-hZg0gA8u.js";
|
|
9
|
+
import { i as InputGroupInput, n as InputGroupAddon, t as InputGroup } from "../input-group-B5PMRYld.js";
|
|
10
|
+
import { i as EmptyHeader, o as EmptyTitle, t as Empty } from "../empty-U4zrLmFU.js";
|
|
11
|
+
import { t as ScrollArea } from "../scroll-area-mNVMQ0Of.js";
|
|
12
|
+
import { ChevronRightIcon, SearchIcon } from "lucide-react";
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
import * as React$1 from "react";
|
|
15
|
+
import { cva } from "class-variance-authority";
|
|
16
|
+
|
|
17
|
+
//#region src/components/tree-select.tsx
|
|
18
|
+
/** Walk the tree honoring `maxDepth`, invoking `visit` with node + depth. */
|
|
19
|
+
function walk(nodes, maxDepth, visit, depth = 0) {
|
|
20
|
+
if (maxDepth !== void 0 && depth > maxDepth) return;
|
|
21
|
+
for (const node of nodes) {
|
|
22
|
+
visit(node, depth);
|
|
23
|
+
if (node.children?.length) walk(node.children, maxDepth, visit, depth + 1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** True when a node renders an expand/collapse affordance at the given depth. */
|
|
27
|
+
function isExpandable(node, depth, maxDepth) {
|
|
28
|
+
return Boolean(node.children?.length) && (maxDepth === void 0 || depth < maxDepth);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns the set of selectable (enabled) ids within the depth budget. In
|
|
32
|
+
* `"leaf"` mode only rendered-leaf rows are selectable; otherwise every enabled
|
|
33
|
+
* node is.
|
|
34
|
+
*/
|
|
35
|
+
function collectSelectableIds(nodes, maxDepth, mode) {
|
|
36
|
+
const ids = /* @__PURE__ */ new Set();
|
|
37
|
+
walk(nodes, maxDepth, (node, depth) => {
|
|
38
|
+
if (node.disabled) return;
|
|
39
|
+
if (mode === "leaf" && isExpandable(node, depth, maxDepth)) return;
|
|
40
|
+
ids.add(node.id);
|
|
41
|
+
});
|
|
42
|
+
return ids;
|
|
43
|
+
}
|
|
44
|
+
/** Enabled rendered-leaf descendant ids of a node within the depth budget. */
|
|
45
|
+
function descendantLeafIds(node, depth, maxDepth) {
|
|
46
|
+
const out = [];
|
|
47
|
+
if (node.children?.length) walk(node.children, maxDepth, (n, d) => {
|
|
48
|
+
if (!n.disabled && !isExpandable(n, d, maxDepth)) out.push(n.id);
|
|
49
|
+
}, depth + 1);
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
/** Returns the ids of every expandable branch within the depth budget. */
|
|
53
|
+
function collectBranchIds(nodes, maxDepth) {
|
|
54
|
+
const ids = [];
|
|
55
|
+
walk(nodes, maxDepth, (node, depth) => {
|
|
56
|
+
if (isExpandable(node, depth, maxDepth)) ids.push(node.id);
|
|
57
|
+
});
|
|
58
|
+
return ids;
|
|
59
|
+
}
|
|
60
|
+
/** Enabled descendant ids of a node (excluding itself) within the depth budget. */
|
|
61
|
+
function descendantIds(node, depth, maxDepth) {
|
|
62
|
+
const out = [];
|
|
63
|
+
if (node.children?.length) walk(node.children, maxDepth, (n) => {
|
|
64
|
+
if (!n.disabled) out.push(n.id);
|
|
65
|
+
}, depth + 1);
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
function buildNodeIndex(nodes, maxDepth) {
|
|
69
|
+
const index = /* @__PURE__ */ new Map();
|
|
70
|
+
walk(nodes, maxDepth, (node, depth) => {
|
|
71
|
+
index.set(node.id, {
|
|
72
|
+
node,
|
|
73
|
+
depth
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
return index;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Compute the tri-state of every node in ONE bottom-up pass over the ORIGINAL
|
|
80
|
+
* (unfiltered) tree, keyed by id. Rows then look up their state in O(1), so a
|
|
81
|
+
* large tree no longer re-walks each branch's subtree on every render.
|
|
82
|
+
*
|
|
83
|
+
* Semantics depend on `mode`:
|
|
84
|
+
* - `"cascade"`: a branch is `checked` when every enabled descendant is
|
|
85
|
+
* selected (and the branch itself, when selectable, is selected),
|
|
86
|
+
* `unchecked` when none are, `indeterminate` otherwise. Disabled descendants
|
|
87
|
+
* are ignored, so a branch whose only unselected children are disabled still
|
|
88
|
+
* reads as checked.
|
|
89
|
+
* - `"leaf"`: a branch's state rolls up from its enabled leaf descendants only;
|
|
90
|
+
* the branch's own id is never considered selected.
|
|
91
|
+
* - `"independent"`: every node simply reflects its own selected state.
|
|
92
|
+
*/
|
|
93
|
+
function buildCheckedStates(nodes, maxDepth, selected, mode) {
|
|
94
|
+
const states = /* @__PURE__ */ new Map();
|
|
95
|
+
const visit = (node, depth) => {
|
|
96
|
+
const selfIsLeaf = !isExpandable(node, depth, maxDepth);
|
|
97
|
+
let descEnabled = 0;
|
|
98
|
+
let descSelected = 0;
|
|
99
|
+
let descLeafEnabled = 0;
|
|
100
|
+
let descLeafSelected = 0;
|
|
101
|
+
if ((maxDepth === void 0 || depth < maxDepth) && node.children?.length) for (const child of node.children) {
|
|
102
|
+
const a = visit(child, depth + 1);
|
|
103
|
+
descEnabled += a.selfEnabled + a.descEnabled;
|
|
104
|
+
descSelected += a.selfSelected + a.descSelected;
|
|
105
|
+
descLeafEnabled += (a.selfIsLeaf ? a.selfEnabled : 0) + a.descLeafEnabled;
|
|
106
|
+
descLeafSelected += (a.selfIsLeaf ? a.selfSelected : 0) + a.descLeafSelected;
|
|
107
|
+
}
|
|
108
|
+
let state;
|
|
109
|
+
if (mode === "independent") state = selected.has(node.id) ? "checked" : "unchecked";
|
|
110
|
+
else if (mode === "leaf") if (selfIsLeaf) state = selected.has(node.id) ? "checked" : "unchecked";
|
|
111
|
+
else if (descLeafEnabled === 0 || descLeafSelected === 0) state = "unchecked";
|
|
112
|
+
else if (descLeafSelected === descLeafEnabled) state = "checked";
|
|
113
|
+
else state = "indeterminate";
|
|
114
|
+
else if (descEnabled === 0) state = selected.has(node.id) ? "checked" : "unchecked";
|
|
115
|
+
else {
|
|
116
|
+
const selfChecked = node.disabled ? true : selected.has(node.id);
|
|
117
|
+
if (descSelected === descEnabled && selfChecked) state = "checked";
|
|
118
|
+
else if (descSelected === 0 && !selected.has(node.id)) state = "unchecked";
|
|
119
|
+
else state = "indeterminate";
|
|
120
|
+
}
|
|
121
|
+
states.set(node.id, state);
|
|
122
|
+
return {
|
|
123
|
+
selfEnabled: node.disabled ? 0 : 1,
|
|
124
|
+
selfSelected: !node.disabled && selected.has(node.id) ? 1 : 0,
|
|
125
|
+
selfIsLeaf,
|
|
126
|
+
descEnabled,
|
|
127
|
+
descSelected,
|
|
128
|
+
descLeafEnabled,
|
|
129
|
+
descLeafSelected
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
for (const root of nodes) visit(root, 0);
|
|
133
|
+
return states;
|
|
134
|
+
}
|
|
135
|
+
function nodeSearchText(node) {
|
|
136
|
+
if (node.searchText) return node.searchText;
|
|
137
|
+
if (typeof node.label === "string") return node.label;
|
|
138
|
+
return "";
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Filter the tree to nodes matching `query` plus their ancestors. A node is
|
|
142
|
+
* kept when it matches directly (in which case its original children are kept)
|
|
143
|
+
* or when any descendant matches.
|
|
144
|
+
*/
|
|
145
|
+
function filterTree(nodes, query) {
|
|
146
|
+
if (!query.trim()) return nodes;
|
|
147
|
+
const q = query.trim().toLowerCase();
|
|
148
|
+
const recurse = (list) => {
|
|
149
|
+
const result = [];
|
|
150
|
+
for (const node of list) {
|
|
151
|
+
const selfMatch = nodeSearchText(node).toLowerCase().includes(q);
|
|
152
|
+
const keptChildren = node.children?.length ? recurse(node.children) : [];
|
|
153
|
+
if (selfMatch || keptChildren.length) result.push({
|
|
154
|
+
...node,
|
|
155
|
+
children: keptChildren.length ? keptChildren : node.children
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
};
|
|
160
|
+
return recurse(nodes);
|
|
161
|
+
}
|
|
162
|
+
/** Shared row layout for both leaf and branch rows. */
|
|
163
|
+
const treeSelectRowVariants = cva("flex items-center gap-2 rounded-md py-1.5 pe-2 hover:bg-muted/50");
|
|
164
|
+
function TreeSelectRow({ node, depth, maxDepth, checkedStates, expanded, forceExpanded, disabled, onToggle, onExpandToggle, renderNode }) {
|
|
165
|
+
const labelId = React$1.useId();
|
|
166
|
+
const expandable = isExpandable(node, depth, maxDepth);
|
|
167
|
+
const state = checkedStates.get(node.id) ?? "unchecked";
|
|
168
|
+
const rowDisabled = disabled || Boolean(node.disabled);
|
|
169
|
+
const isOpen = expandable && (forceExpanded || expanded.has(node.id));
|
|
170
|
+
const accessibleName = nodeSearchText(node);
|
|
171
|
+
const meta = {
|
|
172
|
+
state,
|
|
173
|
+
depth,
|
|
174
|
+
expanded: isOpen,
|
|
175
|
+
disabled: rowDisabled,
|
|
176
|
+
labelId,
|
|
177
|
+
toggle: (next) => onToggle(node.id, next ?? state !== "checked")
|
|
178
|
+
};
|
|
179
|
+
const checkbox = /* @__PURE__ */ jsx(Checkbox, {
|
|
180
|
+
"data-slot": "tree-select-checkbox",
|
|
181
|
+
checked: state === "checked",
|
|
182
|
+
indeterminate: state === "indeterminate",
|
|
183
|
+
disabled: rowDisabled,
|
|
184
|
+
"aria-labelledby": labelId,
|
|
185
|
+
"aria-label": renderNode && accessibleName ? accessibleName : void 0,
|
|
186
|
+
onCheckedChange: (checked) => onToggle(node.id, checked)
|
|
187
|
+
});
|
|
188
|
+
const body = renderNode ? /* @__PURE__ */ jsx("div", {
|
|
189
|
+
className: "flex min-w-0 flex-1 items-center gap-2",
|
|
190
|
+
children: renderNode(node, meta)
|
|
191
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
192
|
+
id: labelId,
|
|
193
|
+
className: cn("min-w-0 flex-1 truncate text-sm", rowDisabled ? "opacity-50" : "cursor-pointer"),
|
|
194
|
+
onClick: rowDisabled ? void 0 : () => onToggle(node.id, state !== "checked"),
|
|
195
|
+
children: node.label
|
|
196
|
+
});
|
|
197
|
+
if (!expandable) return /* @__PURE__ */ jsxs("div", {
|
|
198
|
+
role: "treeitem",
|
|
199
|
+
"aria-selected": state === "checked",
|
|
200
|
+
"data-slot": "tree-select-item",
|
|
201
|
+
className: treeSelectRowVariants(),
|
|
202
|
+
style: { paddingInlineStart: `calc(${depth} * 1.5rem + 1.5rem)` },
|
|
203
|
+
children: [checkbox, body]
|
|
204
|
+
});
|
|
205
|
+
return /* @__PURE__ */ jsxs(Collapsible, {
|
|
206
|
+
open: isOpen,
|
|
207
|
+
onOpenChange: (open) => onExpandToggle(node.id, open),
|
|
208
|
+
"data-slot": "tree-select-branch",
|
|
209
|
+
render: /* @__PURE__ */ jsx("div", {
|
|
210
|
+
role: "treeitem",
|
|
211
|
+
"aria-selected": state === "checked",
|
|
212
|
+
"aria-expanded": isOpen
|
|
213
|
+
}),
|
|
214
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
215
|
+
className: treeSelectRowVariants(),
|
|
216
|
+
style: { paddingInlineStart: `calc(${depth} * 1.5rem)` },
|
|
217
|
+
children: [
|
|
218
|
+
/* @__PURE__ */ jsx(CollapsibleTrigger, {
|
|
219
|
+
"data-slot": "tree-select-trigger",
|
|
220
|
+
disabled: forceExpanded,
|
|
221
|
+
"aria-label": "Toggle",
|
|
222
|
+
render: /* @__PURE__ */ jsx(Button, {
|
|
223
|
+
variant: "ghost",
|
|
224
|
+
size: "icon",
|
|
225
|
+
className: "group size-6 shrink-0 text-muted-foreground"
|
|
226
|
+
}),
|
|
227
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "transition-transform duration-200 group-data-panel-open:rotate-90" })
|
|
228
|
+
}),
|
|
229
|
+
checkbox,
|
|
230
|
+
body
|
|
231
|
+
]
|
|
232
|
+
}), /* @__PURE__ */ jsx(CollapsibleContent, {
|
|
233
|
+
role: "group",
|
|
234
|
+
children: node.children.map((child) => /* @__PURE__ */ jsx(TreeSelectRow, {
|
|
235
|
+
node: child,
|
|
236
|
+
depth: depth + 1,
|
|
237
|
+
maxDepth,
|
|
238
|
+
checkedStates,
|
|
239
|
+
expanded,
|
|
240
|
+
forceExpanded,
|
|
241
|
+
disabled,
|
|
242
|
+
onToggle,
|
|
243
|
+
onExpandToggle,
|
|
244
|
+
renderNode
|
|
245
|
+
}, child.id))
|
|
246
|
+
})]
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* A hierarchical, searchable tree multi-select with tri-state checkboxes.
|
|
251
|
+
*
|
|
252
|
+
* Selecting a parent selects all of its (enabled) descendants; clearing a
|
|
253
|
+
* parent clears them. A branch with a mix of selected and unselected
|
|
254
|
+
* descendants shows the indeterminate state. The selection is a flat array of
|
|
255
|
+
* node ids and works controlled (`value` + `onValueChange`) or uncontrolled
|
|
256
|
+
* (`defaultValue`). Expansion is likewise controllable (`expandedIds` +
|
|
257
|
+
* `onExpandedChange`) so consumers can implement expand-all / collapse-all.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```tsx
|
|
261
|
+
* const nodes = [
|
|
262
|
+
* {
|
|
263
|
+
* id: "fe",
|
|
264
|
+
* label: "Frontend",
|
|
265
|
+
* children: [
|
|
266
|
+
* { id: "react", label: "React" },
|
|
267
|
+
* { id: "vue", label: "Vue" },
|
|
268
|
+
* ],
|
|
269
|
+
* },
|
|
270
|
+
* { id: "be", label: "Backend", children: [{ id: "rails", label: "Rails" }] },
|
|
271
|
+
* ]
|
|
272
|
+
*
|
|
273
|
+
* function Example() {
|
|
274
|
+
* const [value, setValue] = React.useState<string[]>(["react"])
|
|
275
|
+
* return (
|
|
276
|
+
* <TreeSelect
|
|
277
|
+
* nodes={nodes}
|
|
278
|
+
* value={value}
|
|
279
|
+
* onValueChange={setValue}
|
|
280
|
+
* searchable
|
|
281
|
+
* maxDepth={1}
|
|
282
|
+
* />
|
|
283
|
+
* )
|
|
284
|
+
* }
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
function TreeSelect({ nodes, value, defaultValue = [], onValueChange, searchable = false, searchPlaceholder = "Search…", search, defaultSearch = "", onSearchChange, maxDepth, selectionMode = "cascade", showSummary = true, renderSummary, renderNode, emptyMessage = "No items.", noResultsMessage = "No results found.", disabled = false, defaultExpanded = false, expandedIds, defaultExpandedIds, onExpandedChange, scrollHeight = "16rem", scrollClassName, className, ...props }) {
|
|
288
|
+
const isControlled = value !== void 0;
|
|
289
|
+
const [internalValue, setInternalValue] = React$1.useState(defaultValue);
|
|
290
|
+
const currentValue = isControlled ? value : internalValue;
|
|
291
|
+
const selected = React$1.useMemo(() => new Set(currentValue), [currentValue]);
|
|
292
|
+
const setValue = React$1.useCallback((next) => {
|
|
293
|
+
if (!isControlled) setInternalValue(next);
|
|
294
|
+
onValueChange?.(next);
|
|
295
|
+
}, [isControlled, onValueChange]);
|
|
296
|
+
const searchControlled = search !== void 0;
|
|
297
|
+
const [internalSearch, setInternalSearch] = React$1.useState(defaultSearch);
|
|
298
|
+
const currentSearch = searchControlled ? search : internalSearch;
|
|
299
|
+
const setSearch = React$1.useCallback((next) => {
|
|
300
|
+
if (!searchControlled) setInternalSearch(next);
|
|
301
|
+
onSearchChange?.(next);
|
|
302
|
+
}, [searchControlled, onSearchChange]);
|
|
303
|
+
const expansionControlled = expandedIds !== void 0;
|
|
304
|
+
const [internalExpanded, setInternalExpanded] = React$1.useState(() => {
|
|
305
|
+
if (defaultExpandedIds) return defaultExpandedIds;
|
|
306
|
+
if (defaultExpanded) return collectBranchIds(nodes, maxDepth);
|
|
307
|
+
return [];
|
|
308
|
+
});
|
|
309
|
+
const currentExpanded = expansionControlled ? expandedIds : internalExpanded;
|
|
310
|
+
const expanded = React$1.useMemo(() => new Set(currentExpanded), [currentExpanded]);
|
|
311
|
+
const setExpanded = React$1.useCallback((next) => {
|
|
312
|
+
if (!expansionControlled) setInternalExpanded(next);
|
|
313
|
+
onExpandedChange?.(next);
|
|
314
|
+
}, [expansionControlled, onExpandedChange]);
|
|
315
|
+
const handleExpandToggle = React$1.useCallback((id, open) => {
|
|
316
|
+
const next = new Set(expanded);
|
|
317
|
+
if (open) next.add(id);
|
|
318
|
+
else next.delete(id);
|
|
319
|
+
setExpanded(Array.from(next));
|
|
320
|
+
}, [expanded, setExpanded]);
|
|
321
|
+
const selectableIds = React$1.useMemo(() => collectSelectableIds(nodes, maxDepth, selectionMode), [
|
|
322
|
+
nodes,
|
|
323
|
+
maxDepth,
|
|
324
|
+
selectionMode
|
|
325
|
+
]);
|
|
326
|
+
const nodeIndex = React$1.useMemo(() => buildNodeIndex(nodes, maxDepth), [nodes, maxDepth]);
|
|
327
|
+
const checkedStates = React$1.useMemo(() => buildCheckedStates(nodes, maxDepth, selected, selectionMode), [
|
|
328
|
+
nodes,
|
|
329
|
+
maxDepth,
|
|
330
|
+
selected,
|
|
331
|
+
selectionMode
|
|
332
|
+
]);
|
|
333
|
+
const selectedCount = React$1.useMemo(() => currentValue.filter((id) => selectableIds.has(id)).length, [currentValue, selectableIds]);
|
|
334
|
+
const filteredNodes = React$1.useMemo(() => searchable ? filterTree(nodes, currentSearch) : nodes, [
|
|
335
|
+
searchable,
|
|
336
|
+
nodes,
|
|
337
|
+
currentSearch
|
|
338
|
+
]);
|
|
339
|
+
const hasQuery = searchable && currentSearch.trim().length > 0;
|
|
340
|
+
const handleToggle = React$1.useCallback((id, next) => {
|
|
341
|
+
const ids = new Set(selected);
|
|
342
|
+
const entry = nodeIndex.get(id);
|
|
343
|
+
let affected;
|
|
344
|
+
if (!entry || selectionMode === "independent") affected = [id];
|
|
345
|
+
else if (selectionMode === "leaf") affected = isExpandable(entry.node, entry.depth, maxDepth) ? descendantLeafIds(entry.node, entry.depth, maxDepth) : [entry.node.id];
|
|
346
|
+
else affected = [entry.node.id, ...descendantIds(entry.node, entry.depth, maxDepth)];
|
|
347
|
+
for (const target of affected) {
|
|
348
|
+
if (!selectableIds.has(target)) continue;
|
|
349
|
+
if (next) ids.add(target);
|
|
350
|
+
else ids.delete(target);
|
|
351
|
+
}
|
|
352
|
+
setValue(Array.from(ids));
|
|
353
|
+
}, [
|
|
354
|
+
selected,
|
|
355
|
+
maxDepth,
|
|
356
|
+
selectableIds,
|
|
357
|
+
nodeIndex,
|
|
358
|
+
setValue,
|
|
359
|
+
selectionMode
|
|
360
|
+
]);
|
|
361
|
+
const summaryNode = showSummary ? renderSummary ? renderSummary(selectedCount, selectableIds.size) : `${selectedCount} of ${selectableIds.size} selected` : null;
|
|
362
|
+
const isEmpty = filteredNodes.length === 0;
|
|
363
|
+
const emptyText = hasQuery ? noResultsMessage : emptyMessage;
|
|
364
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
365
|
+
"data-slot": "tree-select",
|
|
366
|
+
"data-disabled": disabled || void 0,
|
|
367
|
+
className: cn("flex flex-col gap-2", disabled && "pointer-events-none opacity-60", className),
|
|
368
|
+
...props,
|
|
369
|
+
children: [
|
|
370
|
+
searchable && /* @__PURE__ */ jsxs(InputGroup, {
|
|
371
|
+
"data-slot": "tree-select-search",
|
|
372
|
+
children: [/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(SearchIcon, { "data-icon": "inline-start" }) }), /* @__PURE__ */ jsx(InputGroupInput, {
|
|
373
|
+
type: "search",
|
|
374
|
+
value: currentSearch,
|
|
375
|
+
disabled,
|
|
376
|
+
placeholder: searchPlaceholder,
|
|
377
|
+
"aria-label": searchPlaceholder,
|
|
378
|
+
onChange: (event) => setSearch(event.target.value)
|
|
379
|
+
})]
|
|
380
|
+
}),
|
|
381
|
+
summaryNode != null && /* @__PURE__ */ jsx("div", {
|
|
382
|
+
"data-slot": "tree-select-summary",
|
|
383
|
+
className: "text-xs text-muted-foreground",
|
|
384
|
+
children: summaryNode
|
|
385
|
+
}),
|
|
386
|
+
/* @__PURE__ */ jsx(ScrollArea, {
|
|
387
|
+
"data-slot": "tree-select-scroll",
|
|
388
|
+
className: cn("rounded-md border border-input", scrollClassName),
|
|
389
|
+
viewportProps: { style: { maxHeight: scrollHeight } },
|
|
390
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
391
|
+
role: "tree",
|
|
392
|
+
"aria-multiselectable": true,
|
|
393
|
+
className: "p-1",
|
|
394
|
+
children: isEmpty ? /* @__PURE__ */ jsx(Empty, {
|
|
395
|
+
"data-slot": "tree-select-empty",
|
|
396
|
+
className: "border-0 p-6",
|
|
397
|
+
children: /* @__PURE__ */ jsx(EmptyHeader, { children: /* @__PURE__ */ jsx(EmptyTitle, {
|
|
398
|
+
className: "text-sm font-normal text-muted-foreground",
|
|
399
|
+
children: emptyText
|
|
400
|
+
}) })
|
|
401
|
+
}) : filteredNodes.map((node) => /* @__PURE__ */ jsx(TreeSelectRow, {
|
|
402
|
+
node,
|
|
403
|
+
depth: 0,
|
|
404
|
+
maxDepth,
|
|
405
|
+
checkedStates,
|
|
406
|
+
expanded,
|
|
407
|
+
forceExpanded: hasQuery,
|
|
408
|
+
disabled,
|
|
409
|
+
onToggle: handleToggle,
|
|
410
|
+
onExpandToggle: handleExpandToggle,
|
|
411
|
+
renderNode
|
|
412
|
+
}, node.id))
|
|
413
|
+
})
|
|
414
|
+
})
|
|
415
|
+
]
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
//#endregion
|
|
420
|
+
export { TreeSelect };
|
|
421
|
+
//# sourceMappingURL=tree-select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-select.js","names":["out: string[]","ids: string[]","state: CheckedState","result: TreeSelectNode[]","React","meta: TreeSelectNodeMeta","affected: string[]"],"sources":["../../src/components/tree-select.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cva } from \"class-variance-authority\"\nimport { ChevronRightIcon, SearchIcon } from \"lucide-react\"\n\nimport { cn } from \"@px-ui/ui/lib/utils\"\nimport { Button } from \"@px-ui/ui/components/button\"\nimport { Checkbox } from \"@px-ui/ui/components/checkbox\"\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@px-ui/ui/components/collapsible\"\nimport {\n Empty,\n EmptyHeader,\n EmptyTitle,\n} from \"@px-ui/ui/components/empty\"\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupInput,\n} from \"@px-ui/ui/components/input-group\"\nimport { ScrollArea } from \"@px-ui/ui/components/scroll-area\"\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A single node in the tree passed to {@link TreeSelect}.\n */\nexport interface TreeSelectNode {\n /** Stable, unique identifier. Used as the selection key in `value`. */\n id: string\n /** Human-readable label rendered on the row. */\n label: React.ReactNode\n /** Plain-text label used for search matching. Falls back to `label` when it is a string. */\n searchText?: string\n /** Optional child nodes. Presence of a non-empty array makes the row expandable. */\n children?: TreeSelectNode[]\n /** Disables the row's checkbox (and excludes it from parent propagation). */\n disabled?: boolean\n}\n\n/** Tri-state checked status for a node, per the active `selectionMode`. */\nexport type TreeSelectCheckedState = \"checked\" | \"unchecked\" | \"indeterminate\"\ntype CheckedState = TreeSelectCheckedState\n\n/** How selecting a node affects the others. See {@link TreeSelectProps.selectionMode}. */\nexport type TreeSelectSelectionMode = \"cascade\" | \"leaf\" | \"independent\"\n\n/** Per-row context passed to {@link TreeSelectProps.renderNode}. */\nexport interface TreeSelectNodeMeta {\n /** Tri-state of this row under the active `selectionMode`. */\n state: TreeSelectCheckedState\n /** 0-based depth (root rows are depth 0). */\n depth: number\n /** Whether this (expandable) row is currently open. Always false for leaves. */\n expanded: boolean\n /** Whether the row is disabled (the node itself, or the whole control). */\n disabled: boolean\n /** Put this on your label text (`id={meta.labelId}`) to name the checkbox. */\n labelId: string\n /** Toggle this row's selection; omit `next` to flip from the current state. */\n toggle: (next?: boolean) => void\n}\n\nexport interface TreeSelectProps\n extends Omit<React.ComponentProps<\"div\">, \"onChange\" | \"defaultValue\"> {\n /** The tree of nodes to render. */\n nodes: TreeSelectNode[]\n /** Controlled selection — array of selected node `id`s. Pair with `onValueChange`. */\n value?: string[]\n /** Initial selection for the uncontrolled case. @default [] */\n defaultValue?: string[]\n /** Called whenever the selection changes, with the next array of selected `id`s. */\n onValueChange?: (value: string[]) => void\n /**\n * Render a search box that filters the tree. Matching nodes and their\n * ancestors are kept; non-matching branches are hidden.\n * @default false\n */\n searchable?: boolean\n /** Placeholder for the search input. @default \"Search…\" */\n searchPlaceholder?: string\n /** Controlled search query. Pair with `onSearchChange`. */\n search?: string\n /** Default search query for the uncontrolled case. @default \"\" */\n defaultSearch?: string\n /** Called when the internal search query changes. */\n onSearchChange?: (search: string) => void\n /**\n * Maximum depth to render, 0-based (root nodes are depth 0). Nodes deeper\n * than this are not rendered and are excluded from propagation/counts.\n * Omit for unlimited depth.\n */\n maxDepth?: number\n /**\n * How selecting a node affects the others.\n * - `\"cascade\"` (default): selecting a parent selects all of its enabled\n * descendants; a branch with a mix shows the indeterminate state. The\n * selection includes both parent ids and leaf ids.\n * - `\"leaf\"`: only leaf rows are selectable. A parent checkbox toggles its\n * enabled leaves and reflects their tri-state, but parent ids never enter\n * `value`, and counts are based on leaves.\n * - `\"independent\"`: each node toggles only itself — no cascade and no\n * indeterminate roll-up.\n * @default \"cascade\"\n */\n selectionMode?: TreeSelectSelectionMode\n /**\n * Show a summary line above the tree with the selected count.\n * @default true\n */\n showSummary?: boolean\n /**\n * Render a custom summary given the selected ids and the total selectable\n * count. Overrides the default count text.\n */\n renderSummary?: (selectedCount: number, total: number) => React.ReactNode\n /**\n * Render the row body (everything after the checkbox) yourself. You own the\n * label markup — including click-to-toggle (call `meta.toggle()`) and naming\n * the managed checkbox (put `id={meta.labelId}` on your label text, or rely\n * on a string `label`/`searchText` as the fallback name). The chevron,\n * checkbox, indentation, and expansion stay managed by the component.\n */\n renderNode?: (node: TreeSelectNode, meta: TreeSelectNodeMeta) => React.ReactNode\n /** Message shown when the tree has no nodes at all. @default \"No items.\" */\n emptyMessage?: React.ReactNode\n /** Message shown when a search query yields no matches. @default \"No results found.\" */\n noResultsMessage?: React.ReactNode\n /** Disable the entire control. */\n disabled?: boolean\n /**\n * Whether all branches start expanded (uncontrolled). Ignored when\n * `expandedIds` or `defaultExpandedIds` is provided. @default false\n */\n defaultExpanded?: boolean\n /**\n * Controlled set of expanded branch `id`s. Pair with `onExpandedChange`.\n * Driving this lets a consumer implement expand-all / collapse-all or\n * persist which branches are open.\n */\n expandedIds?: string[]\n /** Initial expanded branch `id`s for the uncontrolled case. */\n defaultExpandedIds?: string[]\n /** Called when the set of expanded branch `id`s changes. */\n onExpandedChange?: (expandedIds: string[]) => void\n /** Max height of the scroll viewport (any CSS length). @default \"16rem\" */\n scrollHeight?: string | number\n /** Extra className for the scroll viewport wrapper. */\n scrollClassName?: string\n}\n\n// ============================================================================\n// Internals\n// ============================================================================\n\n/** Walk the tree honoring `maxDepth`, invoking `visit` with node + depth. */\nfunction walk(\n nodes: TreeSelectNode[],\n maxDepth: number | undefined,\n visit: (node: TreeSelectNode, depth: number) => void,\n depth = 0\n): void {\n if (maxDepth !== undefined && depth > maxDepth) return\n for (const node of nodes) {\n visit(node, depth)\n if (node.children?.length) {\n walk(node.children, maxDepth, visit, depth + 1)\n }\n }\n}\n\n/** True when a node renders an expand/collapse affordance at the given depth. */\nfunction isExpandable(\n node: TreeSelectNode,\n depth: number,\n maxDepth: number | undefined\n): boolean {\n return (\n Boolean(node.children?.length) &&\n (maxDepth === undefined || depth < maxDepth)\n )\n}\n\n/**\n * Returns the set of selectable (enabled) ids within the depth budget. In\n * `\"leaf\"` mode only rendered-leaf rows are selectable; otherwise every enabled\n * node is.\n */\nfunction collectSelectableIds(\n nodes: TreeSelectNode[],\n maxDepth: number | undefined,\n mode: TreeSelectSelectionMode\n): Set<string> {\n const ids = new Set<string>()\n walk(nodes, maxDepth, (node, depth) => {\n if (node.disabled) return\n if (mode === \"leaf\" && isExpandable(node, depth, maxDepth)) return\n ids.add(node.id)\n })\n return ids\n}\n\n/** Enabled rendered-leaf descendant ids of a node within the depth budget. */\nfunction descendantLeafIds(\n node: TreeSelectNode,\n depth: number,\n maxDepth: number | undefined\n): string[] {\n const out: string[] = []\n if (node.children?.length) {\n walk(\n node.children,\n maxDepth,\n (n, d) => {\n if (!n.disabled && !isExpandable(n, d, maxDepth)) out.push(n.id)\n },\n depth + 1\n )\n }\n return out\n}\n\n/** Returns the ids of every expandable branch within the depth budget. */\nfunction collectBranchIds(\n nodes: TreeSelectNode[],\n maxDepth: number | undefined\n): string[] {\n const ids: string[] = []\n walk(nodes, maxDepth, (node, depth) => {\n if (isExpandable(node, depth, maxDepth)) ids.push(node.id)\n })\n return ids\n}\n\n/** Enabled descendant ids of a node (excluding itself) within the depth budget. */\nfunction descendantIds(\n node: TreeSelectNode,\n depth: number,\n maxDepth: number | undefined\n): string[] {\n const out: string[] = []\n if (node.children?.length) {\n walk(\n node.children,\n maxDepth,\n (n) => {\n if (!n.disabled) out.push(n.id)\n },\n depth + 1\n )\n }\n return out\n}\n\n/**\n * Resolves a node id back to the ORIGINAL (unfiltered) node and its true depth.\n * Toggle math (the parent-toggle target set) must be computed from this graph so\n * that an active search filter only affects what is rendered, never which\n * descendants a parent owns.\n */\ninterface OriginalNodeEntry {\n node: TreeSelectNode\n depth: number\n}\n\nfunction buildNodeIndex(\n nodes: TreeSelectNode[],\n maxDepth: number | undefined\n): Map<string, OriginalNodeEntry> {\n const index = new Map<string, OriginalNodeEntry>()\n walk(nodes, maxDepth, (node, depth) => {\n index.set(node.id, { node, depth })\n })\n return index\n}\n\n/**\n * Compute the tri-state of every node in ONE bottom-up pass over the ORIGINAL\n * (unfiltered) tree, keyed by id. Rows then look up their state in O(1), so a\n * large tree no longer re-walks each branch's subtree on every render.\n *\n * Semantics depend on `mode`:\n * - `\"cascade\"`: a branch is `checked` when every enabled descendant is\n * selected (and the branch itself, when selectable, is selected),\n * `unchecked` when none are, `indeterminate` otherwise. Disabled descendants\n * are ignored, so a branch whose only unselected children are disabled still\n * reads as checked.\n * - `\"leaf\"`: a branch's state rolls up from its enabled leaf descendants only;\n * the branch's own id is never considered selected.\n * - `\"independent\"`: every node simply reflects its own selected state.\n */\nfunction buildCheckedStates(\n nodes: TreeSelectNode[],\n maxDepth: number | undefined,\n selected: Set<string>,\n mode: TreeSelectSelectionMode\n): Map<string, CheckedState> {\n const states = new Map<string, CheckedState>()\n\n // Aggregate over a node's subtree EXCLUDING the node: enabled descendants (all\n // kinds, for cascade) and enabled rendered-leaf descendants (for leaf), with\n // how many of each are selected.\n interface Aggregate {\n selfEnabled: number\n selfSelected: number\n selfIsLeaf: boolean\n descEnabled: number\n descSelected: number\n descLeafEnabled: number\n descLeafSelected: number\n }\n\n const visit = (node: TreeSelectNode, depth: number): Aggregate => {\n const selfIsLeaf = !isExpandable(node, depth, maxDepth)\n let descEnabled = 0\n let descSelected = 0\n let descLeafEnabled = 0\n let descLeafSelected = 0\n const childrenInBudget =\n (maxDepth === undefined || depth < maxDepth) && node.children?.length\n if (childrenInBudget) {\n for (const child of node.children!) {\n const a = visit(child, depth + 1)\n descEnabled += a.selfEnabled + a.descEnabled\n descSelected += a.selfSelected + a.descSelected\n descLeafEnabled += (a.selfIsLeaf ? a.selfEnabled : 0) + a.descLeafEnabled\n descLeafSelected +=\n (a.selfIsLeaf ? a.selfSelected : 0) + a.descLeafSelected\n }\n }\n\n let state: CheckedState\n if (mode === \"independent\") {\n state = selected.has(node.id) ? \"checked\" : \"unchecked\"\n } else if (mode === \"leaf\") {\n if (selfIsLeaf) {\n state = selected.has(node.id) ? \"checked\" : \"unchecked\"\n } else if (descLeafEnabled === 0 || descLeafSelected === 0) {\n state = \"unchecked\"\n } else if (descLeafSelected === descLeafEnabled) {\n state = \"checked\"\n } else {\n state = \"indeterminate\"\n }\n } else {\n // cascade\n if (descEnabled === 0) {\n state = selected.has(node.id) ? \"checked\" : \"unchecked\"\n } else {\n const selfChecked = node.disabled ? true : selected.has(node.id)\n if (descSelected === descEnabled && selfChecked) state = \"checked\"\n else if (descSelected === 0 && !selected.has(node.id)) state = \"unchecked\"\n else state = \"indeterminate\"\n }\n }\n states.set(node.id, state)\n\n return {\n selfEnabled: node.disabled ? 0 : 1,\n selfSelected: !node.disabled && selected.has(node.id) ? 1 : 0,\n selfIsLeaf,\n descEnabled,\n descSelected,\n descLeafEnabled,\n descLeafSelected,\n }\n }\n\n for (const root of nodes) visit(root, 0)\n return states\n}\n\nfunction nodeSearchText(node: TreeSelectNode): string {\n if (node.searchText) return node.searchText\n if (typeof node.label === \"string\") return node.label\n return \"\"\n}\n\n/**\n * Filter the tree to nodes matching `query` plus their ancestors. A node is\n * kept when it matches directly (in which case its original children are kept)\n * or when any descendant matches.\n */\nfunction filterTree(\n nodes: TreeSelectNode[],\n query: string\n): TreeSelectNode[] {\n if (!query.trim()) return nodes\n const q = query.trim().toLowerCase()\n const recurse = (list: TreeSelectNode[]): TreeSelectNode[] => {\n const result: TreeSelectNode[] = []\n for (const node of list) {\n const selfMatch = nodeSearchText(node).toLowerCase().includes(q)\n const keptChildren = node.children?.length ? recurse(node.children) : []\n if (selfMatch || keptChildren.length) {\n result.push({\n ...node,\n children: keptChildren.length ? keptChildren : node.children,\n })\n }\n }\n return result\n }\n return recurse(nodes)\n}\n\n/** Shared row layout for both leaf and branch rows. */\nconst treeSelectRowVariants = cva(\n \"flex items-center gap-2 rounded-md py-1.5 pe-2 hover:bg-muted/50\"\n)\n\ninterface TreeSelectRowProps {\n node: TreeSelectNode\n depth: number\n maxDepth: number | undefined\n checkedStates: Map<string, CheckedState>\n expanded: Set<string>\n forceExpanded: boolean\n disabled: boolean\n onToggle: (id: string, next: boolean) => void\n onExpandToggle: (id: string, open: boolean) => void\n renderNode?: (node: TreeSelectNode, meta: TreeSelectNodeMeta) => React.ReactNode\n}\n\nfunction TreeSelectRow({\n node,\n depth,\n maxDepth,\n checkedStates,\n expanded,\n forceExpanded,\n disabled,\n onToggle,\n onExpandToggle,\n renderNode,\n}: TreeSelectRowProps) {\n const labelId = React.useId()\n const expandable = isExpandable(node, depth, maxDepth)\n const state = checkedStates.get(node.id) ?? \"unchecked\"\n const rowDisabled = disabled || Boolean(node.disabled)\n const isOpen = expandable && (forceExpanded || expanded.has(node.id))\n const accessibleName = nodeSearchText(node)\n\n const meta: TreeSelectNodeMeta = {\n state,\n depth,\n expanded: isOpen,\n disabled: rowDisabled,\n labelId,\n toggle: (next) => onToggle(node.id, next ?? state !== \"checked\"),\n }\n\n const checkbox = (\n <Checkbox\n data-slot=\"tree-select-checkbox\"\n checked={state === \"checked\"}\n indeterminate={state === \"indeterminate\"}\n disabled={rowDisabled}\n aria-labelledby={labelId}\n // With a custom row body we can't see the consumer's markup, so fall back\n // to a string name; they can still wire `id={meta.labelId}` for a better one.\n aria-label={renderNode && accessibleName ? accessibleName : undefined}\n onCheckedChange={(checked) => onToggle(node.id, checked)}\n />\n )\n\n // The label doubles as a click target for the checkbox, so clicking the row\n // text toggles selection (and gives the checkbox its accessible name via\n // `aria-labelledby`). The chevron stays a separate target for expansion.\n const body = renderNode ? (\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n {renderNode(node, meta)}\n </div>\n ) : (\n <span\n id={labelId}\n className={cn(\n \"min-w-0 flex-1 truncate text-sm\",\n rowDisabled ? \"opacity-50\" : \"cursor-pointer\"\n )}\n onClick={\n rowDisabled ? undefined : () => onToggle(node.id, state !== \"checked\")\n }\n >\n {node.label}\n </span>\n )\n\n if (!expandable) {\n return (\n <div\n role=\"treeitem\"\n aria-selected={state === \"checked\"}\n data-slot=\"tree-select-item\"\n className={treeSelectRowVariants()}\n style={{ paddingInlineStart: `calc(${depth} * 1.5rem + 1.5rem)` }}\n >\n {checkbox}\n {body}\n </div>\n )\n }\n\n return (\n <Collapsible\n open={isOpen}\n onOpenChange={(open) => onExpandToggle(node.id, open)}\n data-slot=\"tree-select-branch\"\n render={\n <div role=\"treeitem\" aria-selected={state === \"checked\"} aria-expanded={isOpen} />\n }\n >\n <div\n className={treeSelectRowVariants()}\n style={{ paddingInlineStart: `calc(${depth} * 1.5rem)` }}\n >\n <CollapsibleTrigger\n data-slot=\"tree-select-trigger\"\n disabled={forceExpanded}\n aria-label=\"Toggle\"\n render={\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"group size-6 shrink-0 text-muted-foreground\"\n />\n }\n >\n <ChevronRightIcon className=\"transition-transform duration-200 group-data-panel-open:rotate-90\" />\n </CollapsibleTrigger>\n {checkbox}\n {body}\n </div>\n <CollapsibleContent role=\"group\">\n {node.children!.map((child) => (\n <TreeSelectRow\n key={child.id}\n node={child}\n depth={depth + 1}\n maxDepth={maxDepth}\n checkedStates={checkedStates}\n expanded={expanded}\n forceExpanded={forceExpanded}\n disabled={disabled}\n onToggle={onToggle}\n onExpandToggle={onExpandToggle}\n renderNode={renderNode}\n />\n ))}\n </CollapsibleContent>\n </Collapsible>\n )\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\n/**\n * A hierarchical, searchable tree multi-select with tri-state checkboxes.\n *\n * Selecting a parent selects all of its (enabled) descendants; clearing a\n * parent clears them. A branch with a mix of selected and unselected\n * descendants shows the indeterminate state. The selection is a flat array of\n * node ids and works controlled (`value` + `onValueChange`) or uncontrolled\n * (`defaultValue`). Expansion is likewise controllable (`expandedIds` +\n * `onExpandedChange`) so consumers can implement expand-all / collapse-all.\n *\n * @example\n * ```tsx\n * const nodes = [\n * {\n * id: \"fe\",\n * label: \"Frontend\",\n * children: [\n * { id: \"react\", label: \"React\" },\n * { id: \"vue\", label: \"Vue\" },\n * ],\n * },\n * { id: \"be\", label: \"Backend\", children: [{ id: \"rails\", label: \"Rails\" }] },\n * ]\n *\n * function Example() {\n * const [value, setValue] = React.useState<string[]>([\"react\"])\n * return (\n * <TreeSelect\n * nodes={nodes}\n * value={value}\n * onValueChange={setValue}\n * searchable\n * maxDepth={1}\n * />\n * )\n * }\n * ```\n */\nexport function TreeSelect({\n nodes,\n value,\n defaultValue = [],\n onValueChange,\n searchable = false,\n searchPlaceholder = \"Search…\",\n search,\n defaultSearch = \"\",\n onSearchChange,\n maxDepth,\n selectionMode = \"cascade\",\n showSummary = true,\n renderSummary,\n renderNode,\n emptyMessage = \"No items.\",\n noResultsMessage = \"No results found.\",\n disabled = false,\n defaultExpanded = false,\n expandedIds,\n defaultExpandedIds,\n onExpandedChange,\n scrollHeight = \"16rem\",\n scrollClassName,\n className,\n ...props\n}: TreeSelectProps) {\n // Controlled / uncontrolled selection.\n const isControlled = value !== undefined\n const [internalValue, setInternalValue] =\n React.useState<string[]>(defaultValue)\n const currentValue = isControlled ? value : internalValue\n\n const selected = React.useMemo(\n () => new Set(currentValue),\n [currentValue]\n )\n\n const setValue = React.useCallback(\n (next: string[]) => {\n if (!isControlled) setInternalValue(next)\n onValueChange?.(next)\n },\n [isControlled, onValueChange]\n )\n\n // Controlled / uncontrolled search.\n const searchControlled = search !== undefined\n const [internalSearch, setInternalSearch] =\n React.useState<string>(defaultSearch)\n const currentSearch = searchControlled ? search : internalSearch\n\n const setSearch = React.useCallback(\n (next: string) => {\n if (!searchControlled) setInternalSearch(next)\n onSearchChange?.(next)\n },\n [searchControlled, onSearchChange]\n )\n\n // Controlled / uncontrolled expansion. Always driven through `open` on each\n // branch, so it never flips between controlled and uncontrolled and the\n // manual expand/collapse state survives an active search.\n const expansionControlled = expandedIds !== undefined\n const [internalExpanded, setInternalExpanded] = React.useState<string[]>(\n () => {\n if (defaultExpandedIds) return defaultExpandedIds\n if (defaultExpanded) return collectBranchIds(nodes, maxDepth)\n return []\n }\n )\n const currentExpanded = expansionControlled ? expandedIds! : internalExpanded\n const expanded = React.useMemo(\n () => new Set(currentExpanded),\n [currentExpanded]\n )\n\n const setExpanded = React.useCallback(\n (next: string[]) => {\n if (!expansionControlled) setInternalExpanded(next)\n onExpandedChange?.(next)\n },\n [expansionControlled, onExpandedChange]\n )\n\n const handleExpandToggle = React.useCallback(\n (id: string, open: boolean) => {\n const next = new Set(expanded)\n if (open) next.add(id)\n else next.delete(id)\n setExpanded(Array.from(next))\n },\n [expanded, setExpanded]\n )\n\n const selectableIds = React.useMemo(\n () => collectSelectableIds(nodes, maxDepth, selectionMode),\n [nodes, maxDepth, selectionMode]\n )\n\n // Index the ORIGINAL (unfiltered) tree by id. The toggle target set resolves\n // through this, so an active search filter only affects visibility.\n const nodeIndex = React.useMemo(\n () => buildNodeIndex(nodes, maxDepth),\n [nodes, maxDepth]\n )\n\n // Tri-state for every node, computed once per (nodes, maxDepth, selection, mode).\n const checkedStates = React.useMemo(\n () => buildCheckedStates(nodes, maxDepth, selected, selectionMode),\n [nodes, maxDepth, selected, selectionMode]\n )\n\n const selectedCount = React.useMemo(\n () => currentValue.filter((id) => selectableIds.has(id)).length,\n [currentValue, selectableIds]\n )\n\n const filteredNodes = React.useMemo(\n () => (searchable ? filterTree(nodes, currentSearch) : nodes),\n [searchable, nodes, currentSearch]\n )\n\n const hasQuery = searchable && currentSearch.trim().length > 0\n\n const handleToggle = React.useCallback(\n (id: string, next: boolean) => {\n const ids = new Set(selected)\n // Resolve the ORIGINAL node + depth so the target set spans the full\n // (unfiltered) subtree, even when a search filter has pruned children.\n const entry = nodeIndex.get(id)\n let affected: string[]\n if (!entry || selectionMode === \"independent\") {\n affected = [id]\n } else if (selectionMode === \"leaf\") {\n // A branch toggles its enabled leaves; a leaf toggles only itself.\n affected = isExpandable(entry.node, entry.depth, maxDepth)\n ? descendantLeafIds(entry.node, entry.depth, maxDepth)\n : [entry.node.id]\n } else {\n // cascade: the node and all of its enabled descendants.\n affected = [\n entry.node.id,\n ...descendantIds(entry.node, entry.depth, maxDepth),\n ]\n }\n for (const target of affected) {\n if (!selectableIds.has(target)) continue\n if (next) ids.add(target)\n else ids.delete(target)\n }\n setValue(Array.from(ids))\n },\n [selected, maxDepth, selectableIds, nodeIndex, setValue, selectionMode]\n )\n\n const summaryNode = showSummary\n ? renderSummary\n ? renderSummary(selectedCount, selectableIds.size)\n : `${selectedCount} of ${selectableIds.size} selected`\n : null\n\n const isEmpty = filteredNodes.length === 0\n const emptyText = hasQuery ? noResultsMessage : emptyMessage\n\n return (\n <div\n data-slot=\"tree-select\"\n data-disabled={disabled || undefined}\n className={cn(\n \"flex flex-col gap-2\",\n disabled && \"pointer-events-none opacity-60\",\n className\n )}\n {...props}\n >\n {searchable && (\n <InputGroup data-slot=\"tree-select-search\">\n <InputGroupAddon>\n <SearchIcon data-icon=\"inline-start\" />\n </InputGroupAddon>\n <InputGroupInput\n type=\"search\"\n value={currentSearch}\n disabled={disabled}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n onChange={(event) => setSearch(event.target.value)}\n />\n </InputGroup>\n )}\n\n {summaryNode != null && (\n <div\n data-slot=\"tree-select-summary\"\n className=\"text-xs text-muted-foreground\"\n >\n {summaryNode}\n </div>\n )}\n\n <ScrollArea\n data-slot=\"tree-select-scroll\"\n className={cn(\n \"rounded-md border border-input\",\n scrollClassName\n )}\n viewportProps={{ style: { maxHeight: scrollHeight } }}\n >\n <div role=\"tree\" aria-multiselectable className=\"p-1\">\n {isEmpty ? (\n <Empty data-slot=\"tree-select-empty\" className=\"border-0 p-6\">\n <EmptyHeader>\n <EmptyTitle className=\"text-sm font-normal text-muted-foreground\">\n {emptyText}\n </EmptyTitle>\n </EmptyHeader>\n </Empty>\n ) : (\n filteredNodes.map((node) => (\n <TreeSelectRow\n key={node.id}\n node={node}\n depth={0}\n maxDepth={maxDepth}\n checkedStates={checkedStates}\n expanded={expanded}\n forceExpanded={hasQuery}\n disabled={disabled}\n onToggle={handleToggle}\n onExpandToggle={handleExpandToggle}\n renderNode={renderNode}\n />\n ))\n )}\n </div>\n </ScrollArea>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as cn } from "./utils-
|
|
2
|
-
import { t as Button } from "./button-
|
|
3
|
-
import "react";
|
|
1
|
+
import { t as cn } from "./utils-DUlptRpf.js";
|
|
2
|
+
import { t as Button } from "./button-DnHwqwy0.js";
|
|
4
3
|
import { XIcon } from "lucide-react";
|
|
5
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import "react";
|
|
6
6
|
import { Dialog } from "@base-ui/react/dialog";
|
|
7
7
|
|
|
8
8
|
//#region src/components/dialog.tsx
|
|
@@ -100,4 +100,4 @@ const createDialogHandle = Dialog.createHandle;
|
|
|
100
100
|
|
|
101
101
|
//#endregion
|
|
102
102
|
export { DialogFooter as a, DialogPortal as c, createDialogHandle as d, DialogDescription as i, DialogTitle as l, DialogClose as n, DialogHeader as o, DialogContent as r, DialogOverlay as s, Dialog$1 as t, DialogTrigger as u };
|
|
103
|
-
//# sourceMappingURL=dialog-
|
|
103
|
+
//# sourceMappingURL=dialog-DuGJUPQl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog-
|
|
1
|
+
{"version":3,"file":"dialog-DuGJUPQl.js","names":["Dialog","DialogPrimitive"],"sources":["../src/components/dialog.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\";\n\nimport { cn } from \"@px-ui/ui/lib/utils\";\nimport { Button } from \"@px-ui/ui/components/button\";\nimport { XIcon } from \"lucide-react\";\n\nfunction Dialog({ ...props }: DialogPrimitive.Root.Props) {\n return (\n <DialogPrimitive.Root\n data-slot=\"dialog\"\n disablePointerDismissal\n {...props}\n />\n );\n}\n\nfunction DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose({ ...props }: DialogPrimitive.Close.Props) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: DialogPrimitive.Backdrop.Props) {\n return (\n <DialogPrimitive.Backdrop\n data-slot=\"dialog-overlay\"\n className={cn(\n \"supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 fixed inset-0 isolate z-50 bg-black/10 duration-100\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n ...props\n}: DialogPrimitive.Popup.Props & {\n showCloseButton?: boolean;\n}) {\n return (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Popup\n data-slot=\"dialog-content\"\n className={cn(\n \"bg-popover text-popover-foreground ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 fixed start-1/2 top-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 rounded-xl p-6 text-sm outline-none ring-1 duration-100 ppx-sm:max-w-md rtl:translate-x-1/2\",\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n render={\n <Button\n variant=\"ghost\"\n className=\"absolute end-4 top-4\"\n size=\"icon-sm\"\n />\n }\n >\n <XIcon />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Popup>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogFooter({\n className,\n showCloseButton = false,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & {\n showCloseButton?: boolean;\n}) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 ppx-sm:flex-row ppx-sm:justify-end\",\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close render={<Button variant=\"outline\" />}>\n Close\n </DialogPrimitive.Close>\n )}\n </div>\n );\n}\n\nfunction DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn(\"font-heading text-lg font-medium leading-none\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: DialogPrimitive.Description.Props) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\n \"text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground text-sm\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Creates a handle that links a `Dialog` to one or more `DialogTrigger`s via\n * their `handle` prop. Use it for detached triggers (a trigger rendered outside\n * `Dialog`) and to reuse a single dialog from multiple triggers. The handle also\n * exposes imperative `open(triggerId)`, `openWithPayload(payload)`, `close()`,\n * and `isOpen`. Create it once, outside render.\n */\nconst createDialogHandle = DialogPrimitive.createHandle;\n\ntype DialogHandle<Payload = unknown> = DialogPrimitive.Handle<Payload>;\n\nexport {\n createDialogHandle,\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n\nexport type { DialogHandle };\n"],"mappings":";;;;;;;;AAOA,SAASA,SAAO,EAAE,GAAG,SAAqC;AACxD,QACE,oBAACC,OAAgB;EACf,aAAU;EACV;EACA,GAAI;GACJ;;AAIN,SAAS,cAAc,EAAE,GAAG,SAAwC;AAClE,QAAO,oBAACA,OAAgB;EAAQ,aAAU;EAAiB,GAAI;GAAS;;AAG1E,SAAS,aAAa,EAAE,GAAG,SAAuC;AAChE,QAAO,oBAACA,OAAgB;EAAO,aAAU;EAAgB,GAAI;GAAS;;AAGxE,SAAS,YAAY,EAAE,GAAG,SAAsC;AAC9D,QAAO,oBAACA,OAAgB;EAAM,aAAU;EAAe,GAAI;GAAS;;AAGtE,SAAS,cAAc,EACrB,WACA,GAAG,SAC8B;AACjC,QACE,oBAACA,OAAgB;EACf,aAAU;EACV,WAAW,GACT,yLACA,UACD;EACD,GAAI;GACJ;;AAIN,SAAS,cAAc,EACrB,WACA,UACA,kBAAkB,MAClB,GAAG,SAGF;AACD,QACE,qBAAC,2BACC,oBAAC,kBAAgB,EACjB,qBAACA,OAAgB;EACf,aAAU;EACV,WAAW,GACT,mYACA,UACD;EACD,GAAI;aAEH,UACA,mBACC,qBAACA,OAAgB;GACf,aAAU;GACV,QACE,oBAAC;IACC,SAAQ;IACR,WAAU;IACV,MAAK;KACL;cAGJ,oBAAC,UAAQ,EACT,oBAAC;IAAK,WAAU;cAAU;KAAY;IAChB;GAEJ,IACX;;AAInB,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;AAC1E,QACE,oBAAC;EACC,aAAU;EACV,WAAW,GAAG,uBAAuB,UAAU;EAC/C,GAAI;GACJ;;AAIN,SAAS,aAAa,EACpB,WACA,kBAAkB,OAClB,UACA,GAAG,SAGF;AACD,QACE,qBAAC;EACC,aAAU;EACV,WAAW,GACT,kEACA,UACD;EACD,GAAI;aAEH,UACA,mBACC,oBAACA,OAAgB;GAAM,QAAQ,oBAAC,UAAO,SAAQ,YAAY;aAAE;IAErC;GAEtB;;AAIV,SAAS,YAAY,EAAE,WAAW,GAAG,SAAsC;AACzE,QACE,oBAACA,OAAgB;EACf,aAAU;EACV,WAAW,GAAG,iDAAiD,UAAU;EACzE,GAAI;GACJ;;AAIN,SAAS,kBAAkB,EACzB,WACA,GAAG,SACiC;AACpC,QACE,oBAACA,OAAgB;EACf,aAAU;EACV,WAAW,GACT,sGACA,UACD;EACD,GAAI;GACJ;;;;;;;;;AAWN,MAAM,qBAAqBA,OAAgB"}
|