@jbpark/ui-kit 10.2.0 → 10.3.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/Alert.d.mts +2 -2
- package/dist/Alert.d.mts.map +1 -1
- package/dist/Alert.mjs +1 -1
- package/dist/Anchor.d.mts +29 -0
- package/dist/Anchor.d.mts.map +1 -0
- package/dist/Anchor.mjs +120 -0
- package/dist/Anchor.mjs.map +1 -0
- package/dist/AutoComplete.d.mts +34 -0
- package/dist/AutoComplete.d.mts.map +1 -0
- package/dist/AutoComplete.mjs +82 -0
- package/dist/AutoComplete.mjs.map +1 -0
- package/dist/Avatar.d.mts +2 -2
- package/dist/Avatar.d.mts.map +1 -1
- package/dist/Avatar.mjs +2 -2
- package/dist/Badge.d.mts +2 -2
- package/dist/Badge.d.mts.map +1 -1
- package/dist/Breadcrumb.d.mts +3 -3
- package/dist/Breadcrumb.d.mts.map +1 -1
- package/dist/Breadcrumb.mjs +1 -1
- package/dist/Breadcrumb.mjs.map +1 -1
- package/dist/Button.d.mts +3 -3
- package/dist/Button.d.mts.map +1 -1
- package/dist/Button.mjs +1 -1
- package/dist/Calendar.d.mts +28 -0
- package/dist/Calendar.d.mts.map +1 -0
- package/dist/Calendar.mjs +64 -0
- package/dist/Calendar.mjs.map +1 -0
- package/dist/Card.d.mts +2 -2
- package/dist/Card.d.mts.map +1 -1
- package/dist/Cascader.d.mts +34 -0
- package/dist/Cascader.d.mts.map +1 -0
- package/dist/Cascader.mjs +144 -0
- package/dist/Cascader.mjs.map +1 -0
- package/dist/CodeEditor.d.mts +2 -2
- package/dist/CodeEditor.d.mts.map +1 -1
- package/dist/ContextMenu.d.mts +33 -0
- package/dist/ContextMenu.d.mts.map +1 -0
- package/dist/ContextMenu.mjs +92 -0
- package/dist/ContextMenu.mjs.map +1 -0
- package/dist/Descriptions.d.mts +31 -0
- package/dist/Descriptions.d.mts.map +1 -0
- package/dist/Descriptions.mjs +67 -0
- package/dist/Descriptions.mjs.map +1 -0
- package/dist/Divider.d.mts +18 -0
- package/dist/Divider.d.mts.map +1 -0
- package/dist/Divider.mjs +44 -0
- package/dist/Divider.mjs.map +1 -0
- package/dist/Form.d.mts +12 -0
- package/dist/Form.d.mts.map +1 -0
- package/dist/Form.mjs +11 -0
- package/dist/Form.mjs.map +1 -0
- package/dist/Layout.d.mts.map +1 -1
- package/dist/Mentions.d.mts +34 -0
- package/dist/Mentions.d.mts.map +1 -0
- package/dist/Mentions.mjs +207 -0
- package/dist/Mentions.mjs.map +1 -0
- package/dist/Menu.mjs +1 -2
- package/dist/Pagination.d.mts +2 -2
- package/dist/Pagination.d.mts.map +1 -1
- package/dist/Pagination.mjs +1 -1
- package/dist/Popconfirm.d.mts +33 -0
- package/dist/Popconfirm.d.mts.map +1 -0
- package/dist/Popconfirm.mjs +119 -0
- package/dist/Popconfirm.mjs.map +1 -0
- package/dist/Rate.d.mts +27 -0
- package/dist/Rate.d.mts.map +1 -0
- package/dist/Rate.mjs +81 -0
- package/dist/Rate.mjs.map +1 -0
- package/dist/Reveals.d.mts.map +1 -1
- package/dist/ScrollArea.d.mts +8 -0
- package/dist/ScrollArea.d.mts.map +1 -0
- package/dist/ScrollArea.mjs +11 -0
- package/dist/ScrollArea.mjs.map +1 -0
- package/dist/Segmented.d.mts +3 -3
- package/dist/Segmented.d.mts.map +1 -1
- package/dist/Space.d.mts +2 -2
- package/dist/Space.d.mts.map +1 -1
- package/dist/Statistic.d.mts +22 -0
- package/dist/Statistic.d.mts.map +1 -0
- package/dist/Statistic.mjs +53 -0
- package/dist/Statistic.mjs.map +1 -0
- package/dist/Steps.d.mts +3 -3
- package/dist/Steps.d.mts.map +1 -1
- package/dist/Steps.mjs +1 -1
- package/dist/Table.d.mts +4 -4
- package/dist/Table.d.mts.map +1 -1
- package/dist/Tag.d.mts +3 -3
- package/dist/Tag.d.mts.map +1 -1
- package/dist/TimePicker.d.mts +26 -0
- package/dist/TimePicker.d.mts.map +1 -0
- package/dist/TimePicker.mjs +77 -0
- package/dist/TimePicker.mjs.map +1 -0
- package/dist/Timeline.d.mts +35 -0
- package/dist/Timeline.d.mts.map +1 -0
- package/dist/Timeline.mjs +59 -0
- package/dist/Timeline.mjs.map +1 -0
- package/dist/Tour.d.mts +37 -0
- package/dist/Tour.d.mts.map +1 -0
- package/dist/Tour.mjs +192 -0
- package/dist/Tour.mjs.map +1 -0
- package/dist/Transfer.d.mts +36 -0
- package/dist/Transfer.d.mts.map +1 -0
- package/dist/Transfer.mjs +147 -0
- package/dist/Transfer.mjs.map +1 -0
- package/dist/Tree.d.mts +62 -0
- package/dist/Tree.d.mts.map +1 -0
- package/dist/Tree.mjs +462 -0
- package/dist/Tree.mjs.map +1 -0
- package/dist/TreeSelect.d.mts +34 -0
- package/dist/TreeSelect.d.mts.map +1 -0
- package/dist/TreeSelect.mjs +135 -0
- package/dist/TreeSelect.mjs.map +1 -0
- package/dist/Typography.d.mts.map +1 -1
- package/dist/components/atoms/checkbox/checkbox.d.mts +5 -3
- package/dist/components/atoms/checkbox/checkbox.d.mts.map +1 -1
- package/dist/components/atoms/checkbox/checkbox.mjs +8 -4
- package/dist/components/atoms/checkbox/checkbox.mjs.map +1 -1
- package/dist/components/atoms/checkbox/group.d.mts +2 -2
- package/dist/components/atoms/checkbox/group.d.mts.map +1 -1
- package/dist/components/atoms/checkbox/index.d.mts.map +1 -1
- package/dist/components/atoms/color-picker.d.mts +2 -2
- package/dist/components/atoms/color-picker.d.mts.map +1 -1
- package/dist/components/atoms/date-picker.d.mts +5 -1
- package/dist/components/atoms/date-picker.d.mts.map +1 -1
- package/dist/components/atoms/date-picker.mjs +54 -10
- package/dist/components/atoms/date-picker.mjs.map +1 -1
- package/dist/components/atoms/float-button/back-top.d.mts +2 -2
- package/dist/components/atoms/float-button/back-top.d.mts.map +1 -1
- package/dist/components/atoms/float-button/back-top.mjs +1 -1
- package/dist/components/atoms/float-button/float-button.d.mts +2 -2
- package/dist/components/atoms/float-button/float-button.d.mts.map +1 -1
- package/dist/components/atoms/float-button/index.d.mts.map +1 -1
- package/dist/components/atoms/index.d.mts +13 -6
- package/dist/components/atoms/input/index.d.mts +3 -1
- package/dist/components/atoms/input/index.d.mts.map +1 -1
- package/dist/components/atoms/input/index.mjs +3 -1
- package/dist/components/atoms/input/index.mjs.map +1 -1
- package/dist/components/atoms/input/number.d.mts +2 -2
- package/dist/components/atoms/input/number.d.mts.map +1 -1
- package/dist/components/atoms/input/number.mjs +1 -1
- package/dist/components/atoms/input/otp.d.mts +26 -0
- package/dist/components/atoms/input/otp.d.mts.map +1 -0
- package/dist/components/atoms/input/otp.mjs +52 -0
- package/dist/components/atoms/input/otp.mjs.map +1 -0
- package/dist/components/atoms/input/search.d.mts +2 -2
- package/dist/components/atoms/input/search.d.mts.map +1 -1
- package/dist/components/atoms/input/search.mjs +2 -2
- package/dist/components/atoms/mentions-token.mjs +31 -0
- package/dist/components/atoms/mentions-token.mjs.map +1 -0
- package/dist/components/atoms/option-group.d.mts +4 -5
- package/dist/components/atoms/option-group.d.mts.map +1 -1
- package/dist/components/atoms/popover.d.mts +2 -2
- package/dist/components/atoms/popover.d.mts.map +1 -1
- package/dist/components/atoms/progress.d.mts +2 -2
- package/dist/components/atoms/progress.d.mts.map +1 -1
- package/dist/components/atoms/radio/group.d.mts +2 -2
- package/dist/components/atoms/radio/group.d.mts.map +1 -1
- package/dist/components/atoms/radio/group.mjs +1 -1
- package/dist/components/atoms/radio/index.d.mts.map +1 -1
- package/dist/components/atoms/radio/radio.d.mts +2 -2
- package/dist/components/atoms/radio/radio.d.mts.map +1 -1
- package/dist/components/atoms/radio/radio.mjs +1 -1
- package/dist/components/atoms/rich-text-editor/rich-text-editor.d.mts +2 -2
- package/dist/components/atoms/rich-text-editor/rich-text-editor.d.mts.map +1 -1
- package/dist/components/atoms/rich-text-editor/toolbar-presets.mjs +2 -2
- package/dist/components/atoms/rich-text-editor/types.d.mts +2 -3
- package/dist/components/atoms/rich-text-editor/types.d.mts.map +1 -1
- package/dist/components/atoms/select-multiple.d.mts +2 -3
- package/dist/components/atoms/select-multiple.d.mts.map +1 -1
- package/dist/components/atoms/select-multiple.mjs +4 -3
- package/dist/components/atoms/select-multiple.mjs.map +1 -1
- package/dist/components/atoms/select-searchable-options.d.mts +3 -4
- package/dist/components/atoms/select-searchable-options.d.mts.map +1 -1
- package/dist/components/atoms/select-searchable.d.mts +2 -3
- package/dist/components/atoms/select-searchable.d.mts.map +1 -1
- package/dist/components/atoms/select-searchable.mjs +4 -3
- package/dist/components/atoms/select-searchable.mjs.map +1 -1
- package/dist/components/atoms/select.d.mts +3 -3
- package/dist/components/atoms/select.d.mts.map +1 -1
- package/dist/components/atoms/skeleton/button.d.mts.map +1 -1
- package/dist/components/atoms/skeleton/index.d.mts.map +1 -1
- package/dist/components/atoms/skeleton/node.d.mts.map +1 -1
- package/dist/components/atoms/skeleton/skeleton.d.mts +2 -2
- package/dist/components/atoms/skeleton/skeleton.d.mts.map +1 -1
- package/dist/components/atoms/slider/slider.d.mts +3 -3
- package/dist/components/atoms/slider/slider.d.mts.map +1 -1
- package/dist/components/atoms/spin.d.mts +2 -2
- package/dist/components/atoms/spin.d.mts.map +1 -1
- package/dist/components/atoms/spin.mjs +1 -1
- package/dist/components/atoms/switch.d.mts +2 -2
- package/dist/components/atoms/switch.d.mts.map +1 -1
- package/dist/components/atoms/tooltip.d.mts +2 -2
- package/dist/components/atoms/tooltip.d.mts.map +1 -1
- package/dist/components/atoms/typography/link.d.mts +2 -2
- package/dist/components/atoms/typography/link.d.mts.map +1 -1
- package/dist/components/atoms/typography/paragraph.d.mts +2 -2
- package/dist/components/atoms/typography/paragraph.d.mts.map +1 -1
- package/dist/components/atoms/typography/text.d.mts +2 -2
- package/dist/components/atoms/typography/text.d.mts.map +1 -1
- package/dist/components/atoms/typography/title.d.mts +2 -2
- package/dist/components/atoms/typography/title.d.mts.map +1 -1
- package/dist/components/atoms/typography/typography.d.mts +2 -2
- package/dist/components/atoms/typography/typography.d.mts.map +1 -1
- package/dist/components/molecules/collapse.d.mts +2 -2
- package/dist/components/molecules/collapse.d.mts.map +1 -1
- package/dist/components/molecules/dropdown.d.mts +2 -2
- package/dist/components/molecules/dropdown.d.mts.map +1 -1
- package/dist/components/molecules/index.d.mts +22 -14
- package/dist/components/molecules/marquees/index.d.mts.map +1 -1
- package/dist/components/molecules/marquees/item.d.mts +4 -4
- package/dist/components/molecules/marquees/item.d.mts.map +1 -1
- package/dist/components/molecules/marquees/item.mjs +5 -5
- package/dist/components/molecules/marquees/item.mjs.map +1 -1
- package/dist/components/molecules/marquees/marquees.d.mts +2 -2
- package/dist/components/molecules/marquees/marquees.d.mts.map +1 -1
- package/dist/components/molecules/marquees/marquees.mjs +4 -5
- package/dist/components/molecules/marquees/marquees.mjs.map +1 -1
- package/dist/components/molecules/menu/item/item.mjs +1 -1
- package/dist/components/molecules/menu/menu.d.mts +9 -9
- package/dist/components/molecules/menu/menu.d.mts.map +1 -1
- package/dist/components/molecules/reveals/item.d.mts +2 -2
- package/dist/components/molecules/reveals/item.d.mts.map +1 -1
- package/dist/components/molecules/reveals/reveals.d.mts +5 -5
- package/dist/components/molecules/reveals/reveals.d.mts.map +1 -1
- package/dist/components/molecules/splitter/index.d.mts.map +1 -1
- package/dist/components/molecules/splitter/panel.d.mts +3 -3
- package/dist/components/molecules/splitter/panel.d.mts.map +1 -1
- package/dist/components/molecules/splitter/splitter.d.mts +3 -3
- package/dist/components/molecules/splitter/splitter.d.mts.map +1 -1
- package/dist/components/molecules/tabs.d.mts +4 -4
- package/dist/components/molecules/tabs.d.mts.map +1 -1
- package/dist/components/molecules/upload.d.mts +3 -3
- package/dist/components/molecules/upload.d.mts.map +1 -1
- package/dist/components/molecules/upload.mjs +1 -1
- package/dist/components/organisms/drawer.d.mts +2 -2
- package/dist/components/organisms/drawer.d.mts.map +1 -1
- package/dist/components/organisms/drawer.mjs +2 -2
- package/dist/components/organisms/form/context.d.mts +4 -0
- package/dist/components/organisms/form/context.d.mts.map +1 -0
- package/dist/components/organisms/form/context.mjs +9 -0
- package/dist/components/organisms/form/context.mjs.map +1 -0
- package/dist/components/organisms/form/control.d.mts +11 -0
- package/dist/components/organisms/form/control.d.mts.map +1 -0
- package/dist/components/organisms/form/control.mjs +19 -0
- package/dist/components/organisms/form/control.mjs.map +1 -0
- package/dist/components/organisms/form/field.d.mts +25 -0
- package/dist/components/organisms/form/field.d.mts.map +1 -0
- package/dist/components/organisms/form/field.mjs +54 -0
- package/dist/components/organisms/form/field.mjs.map +1 -0
- package/dist/components/organisms/form/form.d.mts +14 -0
- package/dist/components/organisms/form/form.d.mts.map +1 -0
- package/dist/components/organisms/form/form.mjs +23 -0
- package/dist/components/organisms/form/form.mjs.map +1 -0
- package/dist/components/organisms/index.d.mts +14 -6
- package/dist/components/organisms/list/index.d.mts.map +1 -1
- package/dist/components/organisms/list/list.d.mts +2 -2
- package/dist/components/organisms/list/list.d.mts.map +1 -1
- package/dist/components/organisms/modal.d.mts +6 -3
- package/dist/components/organisms/modal.d.mts.map +1 -1
- package/dist/components/organisms/modal.mjs +25 -18
- package/dist/components/organisms/modal.mjs.map +1 -1
- package/dist/components/organisms/swiper/index.d.mts.map +1 -1
- package/dist/components/organisms/swiper/swiper.d.mts +2 -2
- package/dist/components/organisms/swiper/swiper.d.mts.map +1 -1
- package/dist/components/organisms/toast.d.mts +2 -2
- package/dist/components/organisms/toast.d.mts.map +1 -1
- package/dist/components/organisms/toast.mjs +1 -1
- package/dist/components/templates/container.d.mts +2 -2
- package/dist/components/templates/container.d.mts.map +1 -1
- package/dist/components/templates/empty.d.mts +2 -2
- package/dist/components/templates/empty.d.mts.map +1 -1
- package/dist/components/templates/empty.mjs +1 -1
- package/dist/components/templates/grid/col.d.mts +2 -2
- package/dist/components/templates/grid/col.d.mts.map +1 -1
- package/dist/components/templates/grid/row.d.mts +2 -2
- package/dist/components/templates/grid/row.d.mts.map +1 -1
- package/dist/components/templates/layout/content.d.mts +2 -2
- package/dist/components/templates/layout/content.d.mts.map +1 -1
- package/dist/components/templates/layout/footer.d.mts +2 -2
- package/dist/components/templates/layout/footer.d.mts.map +1 -1
- package/dist/components/templates/layout/header.d.mts +2 -2
- package/dist/components/templates/layout/header.d.mts.map +1 -1
- package/dist/components/templates/layout/layout.d.mts +2 -2
- package/dist/components/templates/layout/layout.d.mts.map +1 -1
- package/dist/components/templates/layout/sider.d.mts +2 -2
- package/dist/components/templates/layout/sider.d.mts.map +1 -1
- package/dist/components/templates/layout/sider.mjs +1 -1
- package/dist/components/templates/page-header.d.mts +2 -2
- package/dist/components/templates/page-header.d.mts.map +1 -1
- package/dist/components/templates/page-header.mjs +1 -1
- package/dist/components/templates/result.d.mts +2 -2
- package/dist/components/templates/result.d.mts.map +1 -1
- package/dist/components/templates/result.mjs +1 -1
- package/dist/core/accordion.mjs +1 -1
- package/dist/core/autocomplete.d.mts +2 -0
- package/dist/core/autocomplete.mjs +48 -0
- package/dist/core/autocomplete.mjs.map +1 -0
- package/dist/core/badge.d.mts +5 -3
- package/dist/core/badge.d.mts.map +1 -1
- package/dist/core/button.d.mts +6 -4
- package/dist/core/button.d.mts.map +1 -1
- package/dist/core/calendar.d.mts +13 -3
- package/dist/core/calendar.d.mts.map +1 -0
- package/dist/core/calendar.mjs +1 -1
- package/dist/core/checkbox.mjs +11 -8
- package/dist/core/checkbox.mjs.map +1 -1
- package/dist/core/combobox.d.mts +26 -4
- package/dist/core/combobox.d.mts.map +1 -1
- package/dist/core/combobox.mjs +2 -2
- package/dist/core/combobox.mjs.map +1 -1
- package/dist/core/dialog.mjs +2 -2
- package/dist/core/dialog.mjs.map +1 -1
- package/dist/core/form.d.mts +8 -0
- package/dist/core/form.d.mts.map +1 -0
- package/dist/core/form.mjs +3 -0
- package/dist/core/index.d.mts +13 -9
- package/dist/core/popover.mjs +10 -2
- package/dist/core/popover.mjs.map +1 -1
- package/dist/core/radio-group.mjs +1 -1
- package/dist/core/resizable.d.mts +7 -2
- package/dist/core/resizable.d.mts.map +1 -1
- package/dist/core/resizable.mjs +1 -1
- package/dist/core/scroll-area.d.mts +20 -0
- package/dist/core/scroll-area.d.mts.map +1 -0
- package/dist/core/scroll-area.mjs +57 -0
- package/dist/core/scroll-area.mjs.map +1 -0
- package/dist/core/select.d.mts +24 -2
- package/dist/core/select.d.mts.map +1 -1
- package/dist/core/select.mjs +1 -1
- package/dist/core/separator.d.mts +13 -2
- package/dist/core/separator.d.mts.map +1 -0
- package/dist/core/tabs.d.mts +16 -2
- package/dist/core/tabs.d.mts.map +1 -1
- package/dist/index.d.mts +59 -36
- package/dist/index.mjs +25 -6
- package/dist/lib/colors.d.mts +2 -3
- package/dist/lib/colors.d.mts.map +1 -1
- package/dist/providers/config/context.d.mts +2 -3
- package/dist/providers/config/context.d.mts.map +1 -1
- package/dist/providers/config/context.mjs +3 -1
- package/dist/providers/config/context.mjs.map +1 -1
- package/dist/providers/config/registry.d.mts +2 -3
- package/dist/providers/config/registry.d.mts.map +1 -1
- package/dist/providers/config/types.d.mts +8 -7
- package/dist/providers/config/types.d.mts.map +1 -1
- package/dist/style.css +689 -332
- package/dist/utils.d.mts +2 -3
- package/dist/utils.d.mts.map +1 -1
- package/package.json +122 -26
- package/dist/components/molecules/marquees/use-pause-on-hover.mjs +0 -26
- package/dist/components/molecules/marquees/use-pause-on-hover.mjs.map +0 -1
package/dist/Tree.mjs
ADDED
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "./utils.mjs";
|
|
3
|
+
import { DEFAULT_LOCALE, useConfig } from "./providers/config/context.mjs";
|
|
4
|
+
import Button from "./Button.mjs";
|
|
5
|
+
import Checkbox from "./components/atoms/checkbox/index.mjs";
|
|
6
|
+
import { useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { useControllableState, useLatest, useResizeObserver } from "@jbpark/use-hooks";
|
|
8
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { ChevronDown, ChevronLeft, ChevronRight, CircleAlert, Loader2 } from "lucide-react";
|
|
10
|
+
//#region src/components/organisms/tree.tsx
|
|
11
|
+
const INDENT_REM = 1.5;
|
|
12
|
+
const isBranchNode = (node) => node.leaf === void 0 ? !!node.children?.length : !node.leaf;
|
|
13
|
+
const isUnloaded = (entry) => entry.isBranch && entry.node.children === void 0;
|
|
14
|
+
const deriveChecks = (roots, byKey, keys) => {
|
|
15
|
+
const states = /* @__PURE__ */ new Map();
|
|
16
|
+
const evaluate = (node, isInherited) => {
|
|
17
|
+
const entry = byKey.get(node.key);
|
|
18
|
+
const enabled = entry.children.map((child) => ({
|
|
19
|
+
node: child,
|
|
20
|
+
state: evaluate(child, !entry.isDisabled && (isInherited || keys.has(node.key)))
|
|
21
|
+
})).filter((child) => !byKey.get(child.node.key)?.isDisabled);
|
|
22
|
+
const isChecked = entry.isDisabled ? keys.has(node.key) : enabled.length ? enabled.every((child) => child.state.isChecked) : isInherited || keys.has(node.key);
|
|
23
|
+
const state = {
|
|
24
|
+
isChecked,
|
|
25
|
+
isMixed: !entry.isDisabled && !isChecked && enabled.some((child) => child.state.isChecked || child.state.isMixed)
|
|
26
|
+
};
|
|
27
|
+
states.set(node.key, state);
|
|
28
|
+
return state;
|
|
29
|
+
};
|
|
30
|
+
for (const node of roots) evaluate(node, false);
|
|
31
|
+
return states;
|
|
32
|
+
};
|
|
33
|
+
const Tree = ({ nodes, expandedKeys, defaultExpandedKeys = [], onExpand, selectedKeys, defaultSelectedKeys = [], onSelect, multiple = false, checkable = false, checkedKeys, defaultCheckedKeys = [], onCheck, disabled = false, emptyText = "No nodes", loadData, expandOnClick = false, virtual = false, height, itemHeight = 32, overscan = 8, actionRef, className, classNames, style, dir, ref, "aria-label": ariaLabel = "Tree", ...props }) => {
|
|
34
|
+
const { direction, locale } = useConfig();
|
|
35
|
+
const id = useId();
|
|
36
|
+
const [expanded, setExpanded] = useControllableState({
|
|
37
|
+
value: expandedKeys,
|
|
38
|
+
defaultValue: defaultExpandedKeys
|
|
39
|
+
});
|
|
40
|
+
const [selected, setSelected] = useControllableState({
|
|
41
|
+
value: selectedKeys,
|
|
42
|
+
defaultValue: defaultSelectedKeys,
|
|
43
|
+
onChange: (keys) => onSelect?.([...keys])
|
|
44
|
+
});
|
|
45
|
+
const [checked, setChecked] = useControllableState({
|
|
46
|
+
value: checkedKeys,
|
|
47
|
+
defaultValue: defaultCheckedKeys,
|
|
48
|
+
onChange: (keys) => onCheck?.([...keys])
|
|
49
|
+
});
|
|
50
|
+
const [focused, setFocused] = useState(null);
|
|
51
|
+
const focusedKey = focused?.key;
|
|
52
|
+
const [loadStatus, setLoadStatus] = useState(() => /* @__PURE__ */ new Map());
|
|
53
|
+
const controllers = useRef(/* @__PURE__ */ new Map());
|
|
54
|
+
const latestLoadData = useLatest(loadData);
|
|
55
|
+
const [scrollTop, setScrollTop] = useState(0);
|
|
56
|
+
const [observe, size] = useResizeObserver();
|
|
57
|
+
const root = useRef(null);
|
|
58
|
+
useImperativeHandle(ref, () => root.current, []);
|
|
59
|
+
const setRoot = useCallback((element) => {
|
|
60
|
+
root.current = element;
|
|
61
|
+
observe(virtual ? element : null);
|
|
62
|
+
}, [observe, virtual]);
|
|
63
|
+
const itemRefs = useRef(/* @__PURE__ */ new Map());
|
|
64
|
+
const hasFocus = useRef(false);
|
|
65
|
+
const { entries, byKey } = useMemo(() => {
|
|
66
|
+
const list = [];
|
|
67
|
+
const visit = (siblings, ancestors, isDisabled) => {
|
|
68
|
+
siblings.forEach((node, position) => {
|
|
69
|
+
const isBranch = isBranchNode(node);
|
|
70
|
+
const entry = {
|
|
71
|
+
node,
|
|
72
|
+
children: isBranch ? node.children ?? [] : [],
|
|
73
|
+
ancestors,
|
|
74
|
+
index: list.length,
|
|
75
|
+
level: ancestors.length + 1,
|
|
76
|
+
position: position + 1,
|
|
77
|
+
setSize: siblings.length,
|
|
78
|
+
isBranch,
|
|
79
|
+
isDisabled: isDisabled || !!node.disabled
|
|
80
|
+
};
|
|
81
|
+
list.push(entry);
|
|
82
|
+
visit(entry.children, [...ancestors, node.key], entry.isDisabled);
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
visit(nodes, [], disabled);
|
|
86
|
+
return {
|
|
87
|
+
entries: list,
|
|
88
|
+
byKey: new Map(list.map((entry) => [entry.node.key, entry]))
|
|
89
|
+
};
|
|
90
|
+
}, [nodes, disabled]);
|
|
91
|
+
const expandedSet = useMemo(() => new Set(expanded), [expanded]);
|
|
92
|
+
const visible = useMemo(() => {
|
|
93
|
+
const shown = /* @__PURE__ */ new Set();
|
|
94
|
+
return entries.filter((entry) => {
|
|
95
|
+
const parent = entry.ancestors.at(-1);
|
|
96
|
+
if (parent !== void 0 && !(shown.has(parent) && expandedSet.has(parent))) return false;
|
|
97
|
+
shown.add(entry.node.key);
|
|
98
|
+
return true;
|
|
99
|
+
});
|
|
100
|
+
}, [entries, expandedSet]);
|
|
101
|
+
const visibleIndex = useMemo(() => new Map(visible.map((entry, index) => [entry.node.key, index])), [visible]);
|
|
102
|
+
const selectedSet = new Set(multiple ? selected : selected.slice(0, 1));
|
|
103
|
+
const activeKey = focusedKey && visibleIndex.has(focusedKey) ? focusedKey : [...focused?.ancestors ?? []].reverse().find((key) => visibleIndex.has(key)) ?? visible[0]?.node.key;
|
|
104
|
+
const checks = useMemo(() => checkable ? deriveChecks(nodes, byKey, new Set(checked)) : /* @__PURE__ */ new Map(), [
|
|
105
|
+
checkable,
|
|
106
|
+
nodes,
|
|
107
|
+
byKey,
|
|
108
|
+
checked
|
|
109
|
+
]);
|
|
110
|
+
const hasLoadData = !!loadData;
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
const stale = [...loadStatus.keys()].filter((key) => {
|
|
113
|
+
const entry = byKey.get(key);
|
|
114
|
+
return !entry || !isUnloaded(entry);
|
|
115
|
+
});
|
|
116
|
+
const targets = hasLoadData ? visible.filter((entry) => isUnloaded(entry) && expandedSet.has(entry.node.key) && !loadStatus.has(entry.node.key) && !controllers.current.has(entry.node.key)) : [];
|
|
117
|
+
if (!stale.length && !targets.length) return;
|
|
118
|
+
for (const key of stale) {
|
|
119
|
+
controllers.current.get(key)?.abort();
|
|
120
|
+
controllers.current.delete(key);
|
|
121
|
+
}
|
|
122
|
+
for (const entry of targets) {
|
|
123
|
+
const { key } = entry.node;
|
|
124
|
+
const controller = new AbortController();
|
|
125
|
+
const settle = (status) => {
|
|
126
|
+
if (controller.signal.aborted || controllers.current.get(key) !== controller) return;
|
|
127
|
+
controllers.current.delete(key);
|
|
128
|
+
setLoadStatus((current) => new Map(current).set(key, status));
|
|
129
|
+
};
|
|
130
|
+
controllers.current.set(key, controller);
|
|
131
|
+
Promise.resolve().then(() => latestLoadData.current?.(entry.node, { signal: controller.signal })).then(() => settle("loaded"), () => settle("error"));
|
|
132
|
+
}
|
|
133
|
+
setLoadStatus((current) => {
|
|
134
|
+
const next = new Map(current);
|
|
135
|
+
for (const key of stale) next.delete(key);
|
|
136
|
+
for (const entry of targets) next.set(entry.node.key, "pending");
|
|
137
|
+
return next;
|
|
138
|
+
});
|
|
139
|
+
}, [
|
|
140
|
+
byKey,
|
|
141
|
+
visible,
|
|
142
|
+
expandedSet,
|
|
143
|
+
loadStatus,
|
|
144
|
+
hasLoadData,
|
|
145
|
+
latestLoadData
|
|
146
|
+
]);
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
const pending = controllers.current;
|
|
149
|
+
return () => {
|
|
150
|
+
for (const controller of pending.values()) controller.abort();
|
|
151
|
+
pending.clear();
|
|
152
|
+
};
|
|
153
|
+
}, []);
|
|
154
|
+
const viewportHeight = size?.height ?? (typeof height === "number" ? height : itemHeight * 10);
|
|
155
|
+
const scrollTo = (key, { align = "auto" } = {}) => {
|
|
156
|
+
const index = visibleIndex.get(key);
|
|
157
|
+
const element = root.current;
|
|
158
|
+
if (index === void 0 || !element) return false;
|
|
159
|
+
if (!virtual) {
|
|
160
|
+
itemRefs.current.get(key)?.firstElementChild?.scrollIntoView({ block: align === "auto" ? "nearest" : align });
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
const top = index * itemHeight;
|
|
164
|
+
const bottom = top + itemHeight;
|
|
165
|
+
const viewport = element.clientHeight;
|
|
166
|
+
const next = align === "start" ? top : align === "end" ? bottom - viewport : align === "center" ? top - (viewport - itemHeight) / 2 : top < element.scrollTop ? top : bottom > element.scrollTop + viewport ? bottom - viewport : element.scrollTop;
|
|
167
|
+
element.scrollTop = Math.max(0, next);
|
|
168
|
+
setScrollTop(element.scrollTop);
|
|
169
|
+
return true;
|
|
170
|
+
};
|
|
171
|
+
useImperativeHandle(actionRef, () => ({ scrollTo }));
|
|
172
|
+
const focus = (key) => {
|
|
173
|
+
if (!key) return;
|
|
174
|
+
if (virtual) scrollTo(key);
|
|
175
|
+
const element = itemRefs.current.get(key);
|
|
176
|
+
const entry = byKey.get(key);
|
|
177
|
+
if (element) element.focus({ preventScroll: virtual });
|
|
178
|
+
else if (entry) setFocused({
|
|
179
|
+
key,
|
|
180
|
+
ancestors: entry.ancestors
|
|
181
|
+
});
|
|
182
|
+
};
|
|
183
|
+
useLayoutEffect(() => {
|
|
184
|
+
if (hasFocus.current && activeKey && root.current && document.activeElement !== itemRefs.current.get(activeKey)) itemRefs.current.get(activeKey)?.focus({ preventScroll: virtual });
|
|
185
|
+
}, [
|
|
186
|
+
activeKey,
|
|
187
|
+
nodes,
|
|
188
|
+
virtual
|
|
189
|
+
]);
|
|
190
|
+
const clearStatus = (key) => setLoadStatus((current) => {
|
|
191
|
+
const next = new Map(current);
|
|
192
|
+
next.delete(key);
|
|
193
|
+
return next;
|
|
194
|
+
});
|
|
195
|
+
const expand = (entry) => {
|
|
196
|
+
if (entry.isDisabled || !entry.isBranch) return;
|
|
197
|
+
const { key } = entry.node;
|
|
198
|
+
const isOpening = !expandedSet.has(key);
|
|
199
|
+
const next = new Set(expanded);
|
|
200
|
+
if (isOpening) next.add(key);
|
|
201
|
+
else next.delete(key);
|
|
202
|
+
if (isOpening && loadStatus.get(key) === "error") clearStatus(key);
|
|
203
|
+
const keys = [...next];
|
|
204
|
+
setExpanded(keys);
|
|
205
|
+
onExpand?.([...keys], {
|
|
206
|
+
node: entry.node,
|
|
207
|
+
expanded: isOpening
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
const retry = (entry) => {
|
|
211
|
+
if (entry.isDisabled) return;
|
|
212
|
+
if (expandedSet.has(entry.node.key)) clearStatus(entry.node.key);
|
|
213
|
+
else expand(entry);
|
|
214
|
+
};
|
|
215
|
+
const select = (entry) => {
|
|
216
|
+
if (entry.isDisabled) return;
|
|
217
|
+
if (!multiple) {
|
|
218
|
+
setSelected([entry.node.key]);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const next = new Set(selected);
|
|
222
|
+
if (next.has(entry.node.key)) next.delete(entry.node.key);
|
|
223
|
+
else next.add(entry.node.key);
|
|
224
|
+
setSelected([...next]);
|
|
225
|
+
};
|
|
226
|
+
const check = (entry) => {
|
|
227
|
+
if (entry.isDisabled) return;
|
|
228
|
+
const next = new Set(checked.filter((key) => !byKey.has(key) || byKey.get(key)?.isDisabled));
|
|
229
|
+
for (const item of entries) if (!item.isDisabled && checks.get(item.node.key)?.isChecked) next.add(item.node.key);
|
|
230
|
+
for (const ancestor of entry.ancestors) next.delete(ancestor);
|
|
231
|
+
const shouldCheck = !checks.get(entry.node.key)?.isChecked;
|
|
232
|
+
for (const item of entries) {
|
|
233
|
+
if (item.isDisabled || item.node.key !== entry.node.key && !item.ancestors.includes(entry.node.key)) continue;
|
|
234
|
+
if (shouldCheck) next.add(item.node.key);
|
|
235
|
+
else next.delete(item.node.key);
|
|
236
|
+
}
|
|
237
|
+
const derived = deriveChecks(nodes, byKey, next);
|
|
238
|
+
const result = entries.filter((item) => derived.get(item.node.key)?.isChecked).map((item) => item.node.key);
|
|
239
|
+
setChecked([.../* @__PURE__ */ new Set([...result, ...[...next].filter((key) => !byKey.has(key))])]);
|
|
240
|
+
};
|
|
241
|
+
const loadingLabel = locale.loading ?? DEFAULT_LOCALE.loading;
|
|
242
|
+
const loadFailedLabel = locale.loadFailed ?? DEFAULT_LOCALE.loadFailed;
|
|
243
|
+
const retryLabel = locale.retry ?? DEFAULT_LOCALE.retry;
|
|
244
|
+
const renderItem = (entry, virtualIndex = 0) => {
|
|
245
|
+
const { node } = entry;
|
|
246
|
+
const isExpanded = expandedSet.has(node.key);
|
|
247
|
+
const status = loadStatus.get(node.key);
|
|
248
|
+
const isPending = status === "pending";
|
|
249
|
+
const isFailed = status === "error";
|
|
250
|
+
const state = checks.get(node.key);
|
|
251
|
+
const statusId = `${id}-status-${entry.index}`;
|
|
252
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
253
|
+
ref: (element) => {
|
|
254
|
+
if (element) itemRefs.current.set(node.key, element);
|
|
255
|
+
else itemRefs.current.delete(node.key);
|
|
256
|
+
},
|
|
257
|
+
"data-slot": "tree-item",
|
|
258
|
+
"data-key": node.key,
|
|
259
|
+
role: "treeitem",
|
|
260
|
+
"aria-label": node.label,
|
|
261
|
+
"aria-level": entry.level,
|
|
262
|
+
"aria-posinset": entry.position,
|
|
263
|
+
"aria-setsize": entry.setSize,
|
|
264
|
+
"aria-expanded": entry.isBranch ? isExpanded : void 0,
|
|
265
|
+
"aria-selected": selectedSet.has(node.key),
|
|
266
|
+
"aria-checked": checkable && state ? state.isMixed ? "mixed" : state.isChecked : void 0,
|
|
267
|
+
"aria-disabled": entry.isDisabled || void 0,
|
|
268
|
+
"aria-busy": isPending || void 0,
|
|
269
|
+
"aria-describedby": isPending || isFailed ? statusId : void 0,
|
|
270
|
+
tabIndex: node.key === activeKey ? 0 : -1,
|
|
271
|
+
style: virtual ? {
|
|
272
|
+
top: virtualIndex * itemHeight,
|
|
273
|
+
height: itemHeight
|
|
274
|
+
} : void 0,
|
|
275
|
+
className: cn(`focus-visible:ring-ring m-0 min-w-0 list-none rounded-sm outline-none
|
|
276
|
+
focus-visible:ring-2`, virtual && "absolute inset-x-0 focus-visible:ring-inset", classNames?.item),
|
|
277
|
+
onFocus: (event) => {
|
|
278
|
+
if (event.target !== event.currentTarget) return;
|
|
279
|
+
hasFocus.current = true;
|
|
280
|
+
setFocused({
|
|
281
|
+
key: node.key,
|
|
282
|
+
ancestors: entry.ancestors
|
|
283
|
+
});
|
|
284
|
+
},
|
|
285
|
+
onKeyDown: (event) => {
|
|
286
|
+
if (event.target !== event.currentTarget) return;
|
|
287
|
+
if (event.key === "Escape" || event.key === "Tab") return;
|
|
288
|
+
event.stopPropagation();
|
|
289
|
+
const position = visibleIndex.get(node.key) ?? 0;
|
|
290
|
+
const isRTL = getComputedStyle(event.currentTarget).direction === "rtl";
|
|
291
|
+
const forward = isRTL ? "ArrowLeft" : "ArrowRight";
|
|
292
|
+
const backward = isRTL ? "ArrowRight" : "ArrowLeft";
|
|
293
|
+
if ([
|
|
294
|
+
"ArrowDown",
|
|
295
|
+
"ArrowUp",
|
|
296
|
+
"Home",
|
|
297
|
+
"End",
|
|
298
|
+
forward,
|
|
299
|
+
backward,
|
|
300
|
+
"Enter",
|
|
301
|
+
" "
|
|
302
|
+
].includes(event.key)) event.preventDefault();
|
|
303
|
+
if (event.key === "ArrowDown") focus(visible[Math.min(position + 1, visible.length - 1)]?.node.key);
|
|
304
|
+
else if (event.key === "ArrowUp") focus(visible[Math.max(position - 1, 0)]?.node.key);
|
|
305
|
+
else if (event.key === "Home") focus(visible[0]?.node.key);
|
|
306
|
+
else if (event.key === "End") focus(visible.at(-1)?.node.key);
|
|
307
|
+
else if (event.key === forward && entry.isBranch) {
|
|
308
|
+
if (!isExpanded) expand(entry);
|
|
309
|
+
else if (isFailed) retry(entry);
|
|
310
|
+
else focus(entry.children[0]?.key);
|
|
311
|
+
} else if (event.key === backward) {
|
|
312
|
+
if (entry.isBranch && isExpanded && !entry.isDisabled) expand(entry);
|
|
313
|
+
else focus(entry.ancestors.at(-1));
|
|
314
|
+
} else if (event.key === "Enter") select(entry);
|
|
315
|
+
else if (event.key === " ") {
|
|
316
|
+
if (checkable) check(entry);
|
|
317
|
+
else select(entry);
|
|
318
|
+
} else if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
319
|
+
const candidates = [...visible.slice(position + 1), ...visible.slice(0, position + 1)];
|
|
320
|
+
focus(candidates.find((item) => item.node.label.toLocaleLowerCase().startsWith(event.key.toLocaleLowerCase()))?.node.key);
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
324
|
+
"data-slot": "tree-row",
|
|
325
|
+
style: virtual ? { paddingInlineStart: `${(entry.level - 1) * INDENT_REM + .5}rem` } : void 0,
|
|
326
|
+
className: cn("flex min-w-0 items-center gap-2 rounded-sm px-2 py-1.5 text-sm", virtual && "h-full py-0", selectedSet.has(node.key) && "bg-accent text-accent-foreground", entry.isDisabled && "cursor-not-allowed opacity-50", !entry.isDisabled && "hover:bg-accent/50 cursor-pointer", classNames?.row),
|
|
327
|
+
onClick: () => {
|
|
328
|
+
focus(node.key);
|
|
329
|
+
if (expandOnClick && entry.isBranch) expand(entry);
|
|
330
|
+
select(entry);
|
|
331
|
+
},
|
|
332
|
+
children: [
|
|
333
|
+
entry.isBranch ? /* @__PURE__ */ jsx(Button, {
|
|
334
|
+
tabIndex: -1,
|
|
335
|
+
"aria-hidden": "true",
|
|
336
|
+
variant: "text",
|
|
337
|
+
size: "small",
|
|
338
|
+
disabled: entry.isDisabled,
|
|
339
|
+
className: cn("size-5 shrink-0 p-0", classNames?.toggle),
|
|
340
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
341
|
+
onClick: (event) => {
|
|
342
|
+
event.stopPropagation();
|
|
343
|
+
focus(node.key);
|
|
344
|
+
expand(entry);
|
|
345
|
+
},
|
|
346
|
+
children: isPending ? /* @__PURE__ */ jsx(Loader2, { className: "animate-spin" }) : isExpanded ? /* @__PURE__ */ jsx(ChevronDown, {}) : (dir ?? direction) === "rtl" ? /* @__PURE__ */ jsx(ChevronLeft, {}) : /* @__PURE__ */ jsx(ChevronRight, {})
|
|
347
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
348
|
+
"aria-hidden": "true",
|
|
349
|
+
className: "size-5 shrink-0"
|
|
350
|
+
}),
|
|
351
|
+
checkable && state && /* @__PURE__ */ jsx("span", {
|
|
352
|
+
"data-slot": "tree-check",
|
|
353
|
+
className: cn("shrink-0", classNames?.checkbox),
|
|
354
|
+
onClick: (event) => {
|
|
355
|
+
event.stopPropagation();
|
|
356
|
+
focus(node.key);
|
|
357
|
+
check(entry);
|
|
358
|
+
},
|
|
359
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
360
|
+
"aria-hidden": "true",
|
|
361
|
+
inert: true,
|
|
362
|
+
className: "pointer-events-none",
|
|
363
|
+
children: /* @__PURE__ */ jsx(Checkbox, {
|
|
364
|
+
checked: state.isChecked,
|
|
365
|
+
indeterminate: state.isMixed,
|
|
366
|
+
disabled: entry.isDisabled
|
|
367
|
+
})
|
|
368
|
+
})
|
|
369
|
+
}),
|
|
370
|
+
node.icon != null && /* @__PURE__ */ jsx("span", {
|
|
371
|
+
"aria-hidden": "true",
|
|
372
|
+
className: cn("flex shrink-0 [&>svg]:size-4", classNames?.icon),
|
|
373
|
+
children: node.icon
|
|
374
|
+
}),
|
|
375
|
+
/* @__PURE__ */ jsx("span", {
|
|
376
|
+
className: cn("min-w-0", virtual ? "truncate" : "[overflow-wrap:anywhere]", classNames?.label),
|
|
377
|
+
children: node.label
|
|
378
|
+
}),
|
|
379
|
+
isPending && /* @__PURE__ */ jsx("span", {
|
|
380
|
+
id: statusId,
|
|
381
|
+
className: "sr-only",
|
|
382
|
+
children: loadingLabel
|
|
383
|
+
}),
|
|
384
|
+
isFailed && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
|
|
385
|
+
id: statusId,
|
|
386
|
+
"data-slot": "tree-status",
|
|
387
|
+
className: cn("text-destructive flex shrink-0 items-center gap-1 text-xs", classNames?.status),
|
|
388
|
+
children: [/* @__PURE__ */ jsx(CircleAlert, {
|
|
389
|
+
"aria-hidden": "true",
|
|
390
|
+
className: "size-3.5"
|
|
391
|
+
}), loadFailedLabel]
|
|
392
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
393
|
+
tabIndex: -1,
|
|
394
|
+
"aria-hidden": "true",
|
|
395
|
+
variant: "text",
|
|
396
|
+
size: "small",
|
|
397
|
+
className: cn("h-6 shrink-0 px-1.5 text-xs", classNames?.retry),
|
|
398
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
399
|
+
onClick: (event) => {
|
|
400
|
+
event.stopPropagation();
|
|
401
|
+
focus(node.key);
|
|
402
|
+
retry(entry);
|
|
403
|
+
},
|
|
404
|
+
children: retryLabel
|
|
405
|
+
})] })
|
|
406
|
+
]
|
|
407
|
+
}), !virtual && isExpanded && entry.children.length > 0 && /* @__PURE__ */ jsx("ul", {
|
|
408
|
+
role: "group",
|
|
409
|
+
className: cn("border-border m-0 ms-4 list-none border-s ps-2", classNames?.group),
|
|
410
|
+
children: renderNodes(entry.children)
|
|
411
|
+
})]
|
|
412
|
+
}, node.key);
|
|
413
|
+
};
|
|
414
|
+
const renderNodes = (list) => list.map((node) => renderItem(byKey.get(node.key)));
|
|
415
|
+
const renderWindow = () => {
|
|
416
|
+
const first = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
|
|
417
|
+
const last = Math.min(visible.length, Math.ceil((scrollTop + viewportHeight) / itemHeight) + overscan);
|
|
418
|
+
const indices = [];
|
|
419
|
+
const activeIndex = activeKey ? visibleIndex.get(activeKey) : void 0;
|
|
420
|
+
if (activeIndex !== void 0 && activeIndex < first) indices.push(activeIndex);
|
|
421
|
+
for (let index = first; index < last; index++) indices.push(index);
|
|
422
|
+
if (activeIndex !== void 0 && activeIndex >= last) indices.push(activeIndex);
|
|
423
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("li", {
|
|
424
|
+
role: "none",
|
|
425
|
+
"aria-hidden": "true",
|
|
426
|
+
style: { height: visible.length * itemHeight },
|
|
427
|
+
className: "pointer-events-none m-0 list-none"
|
|
428
|
+
}), indices.map((index) => renderItem(visible[index], index))] });
|
|
429
|
+
};
|
|
430
|
+
return /* @__PURE__ */ jsxs("ul", {
|
|
431
|
+
...props,
|
|
432
|
+
ref: setRoot,
|
|
433
|
+
dir: dir ?? direction,
|
|
434
|
+
"data-slot": "tree",
|
|
435
|
+
"data-virtual": virtual || void 0,
|
|
436
|
+
role: "tree",
|
|
437
|
+
"aria-label": ariaLabel,
|
|
438
|
+
"aria-multiselectable": multiple || void 0,
|
|
439
|
+
style: virtual ? {
|
|
440
|
+
height,
|
|
441
|
+
...style
|
|
442
|
+
} : style,
|
|
443
|
+
className: cn("text-foreground m-0 min-w-0 list-none p-0", virtual && "relative overflow-auto", className),
|
|
444
|
+
onScroll: (event) => {
|
|
445
|
+
if (virtual) setScrollTop(event.currentTarget.scrollTop);
|
|
446
|
+
props.onScroll?.(event);
|
|
447
|
+
},
|
|
448
|
+
onBlur: (event) => {
|
|
449
|
+
hasFocus.current = !!event.relatedTarget && event.currentTarget.contains(event.relatedTarget);
|
|
450
|
+
props.onBlur?.(event);
|
|
451
|
+
},
|
|
452
|
+
children: [virtual ? renderWindow() : renderNodes(nodes), !nodes.length && /* @__PURE__ */ jsx("li", {
|
|
453
|
+
role: "none",
|
|
454
|
+
className: cn("text-muted-foreground p-3 text-sm", classNames?.empty),
|
|
455
|
+
children: emptyText
|
|
456
|
+
})]
|
|
457
|
+
});
|
|
458
|
+
};
|
|
459
|
+
//#endregion
|
|
460
|
+
export { Tree as default };
|
|
461
|
+
|
|
462
|
+
//# sourceMappingURL=Tree.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tree.mjs","names":[],"sources":["../src/components/organisms/tree.tsx"],"sourcesContent":["'use client';\n\nimport {\n type CSSProperties,\n type ComponentPropsWithRef,\n type ReactNode,\n type Ref,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport {\n useControllableState,\n useLatest,\n useResizeObserver,\n} from '@jbpark/use-hooks';\nimport {\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n CircleAlert,\n Loader2,\n} from 'lucide-react';\n\nimport { DEFAULT_LOCALE, useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport Button from '../atoms/button';\nimport Checkbox from '../atoms/checkbox';\n\nexport interface Node {\n key: string;\n label: string;\n icon?: ReactNode;\n children?: readonly Node[];\n disabled?: boolean;\n // Overrides branch detection: `false` makes a branch whose children may\n // not be loaded yet, `true` makes a leaf and ignores `children`.\n leaf?: boolean;\n}\n\nexport interface ExpandInfo {\n node: Node;\n expanded: boolean;\n}\n\nexport interface LoadOptions {\n signal: AbortSignal;\n}\n\nexport interface ScrollOptions {\n align?: 'auto' | 'start' | 'center' | 'end';\n}\n\nexport interface Actions {\n // Scrolls a visible node into view; returns false when the key is not\n // visible because it is unknown or inside a collapsed branch.\n scrollTo: (key: string, options?: ScrollOptions) => boolean;\n}\n\nexport interface Props extends Omit<\n ComponentPropsWithRef<'ul'>,\n 'children' | 'onSelect'\n> {\n nodes: readonly Node[];\n expandedKeys?: readonly string[];\n defaultExpandedKeys?: readonly string[];\n onExpand?: (keys: string[], info: ExpandInfo) => void;\n selectedKeys?: readonly string[];\n defaultSelectedKeys?: readonly string[];\n onSelect?: (keys: string[]) => void;\n multiple?: boolean;\n checkable?: boolean;\n checkedKeys?: readonly string[];\n defaultCheckedKeys?: readonly string[];\n onCheck?: (keys: string[]) => void;\n disabled?: boolean;\n emptyText?: ReactNode;\n loadData?: (node: Node, options: LoadOptions) => Promise<void>;\n expandOnClick?: boolean;\n virtual?: boolean;\n height?: CSSProperties['height'];\n itemHeight?: number;\n overscan?: number;\n actionRef?: Ref<Actions>;\n classNames?: {\n item?: string;\n row?: string;\n group?: string;\n label?: string;\n icon?: string;\n toggle?: string;\n checkbox?: string;\n status?: string;\n retry?: string;\n empty?: string;\n };\n}\n\ninterface Entry {\n node: Node;\n children: readonly Node[];\n ancestors: string[];\n index: number;\n level: number;\n position: number;\n setSize: number;\n isBranch: boolean;\n isDisabled: boolean;\n}\n\ninterface CheckState {\n isChecked: boolean;\n isMixed: boolean;\n}\n\ntype LoadStatus = 'pending' | 'error' | 'loaded';\n\nconst INDENT_REM = 1.5;\n\nconst isBranchNode = (node: Node) =>\n node.leaf === undefined ? !!node.children?.length : !node.leaf;\n\nconst isUnloaded = (entry: Entry) =>\n entry.isBranch && entry.node.children === undefined;\n\nconst deriveChecks = (\n roots: readonly Node[],\n byKey: ReadonlyMap<string, Entry>,\n keys: ReadonlySet<string>,\n) => {\n const states = new Map<string, CheckState>();\n const evaluate = (node: Node, isInherited: boolean): CheckState => {\n const entry = byKey.get(node.key)!;\n const children = entry.children.map(child => ({\n node: child,\n state: evaluate(\n child,\n !entry.isDisabled && (isInherited || keys.has(node.key)),\n ),\n }));\n const enabled = children.filter(\n child => !byKey.get(child.node.key)?.isDisabled,\n );\n const isChecked = entry.isDisabled\n ? keys.has(node.key)\n : enabled.length\n ? enabled.every(child => child.state.isChecked)\n : isInherited || keys.has(node.key);\n const isMixed =\n !entry.isDisabled &&\n !isChecked &&\n enabled.some(child => child.state.isChecked || child.state.isMixed);\n const state = { isChecked, isMixed };\n\n states.set(node.key, state);\n\n return state;\n };\n\n for (const node of roots) {\n evaluate(node, false);\n }\n\n return states;\n};\n\nconst Tree = ({\n nodes,\n expandedKeys,\n defaultExpandedKeys = [],\n onExpand,\n selectedKeys,\n defaultSelectedKeys = [],\n onSelect,\n multiple = false,\n checkable = false,\n checkedKeys,\n defaultCheckedKeys = [],\n onCheck,\n disabled = false,\n emptyText = 'No nodes',\n loadData,\n expandOnClick = false,\n virtual = false,\n height,\n itemHeight = 32,\n overscan = 8,\n actionRef,\n className,\n classNames,\n style,\n dir,\n ref,\n 'aria-label': ariaLabel = 'Tree',\n ...props\n}: Props) => {\n const { direction, locale } = useConfig();\n const id = useId();\n const [expanded, setExpanded] = useControllableState<readonly string[]>({\n value: expandedKeys,\n defaultValue: defaultExpandedKeys,\n });\n const [selected, setSelected] = useControllableState<readonly string[]>({\n value: selectedKeys,\n defaultValue: defaultSelectedKeys,\n onChange: keys => onSelect?.([...keys]),\n });\n const [checked, setChecked] = useControllableState<readonly string[]>({\n value: checkedKeys,\n defaultValue: defaultCheckedKeys,\n onChange: keys => onCheck?.([...keys]),\n });\n const [focused, setFocused] = useState<{\n key: string;\n ancestors: string[];\n } | null>(null);\n const focusedKey = focused?.key;\n const [loadStatus, setLoadStatus] = useState<ReadonlyMap<string, LoadStatus>>(\n () => new Map(),\n );\n const controllers = useRef(new Map<string, AbortController>());\n const latestLoadData = useLatest(loadData);\n const [scrollTop, setScrollTop] = useState(0);\n const [observe, size] = useResizeObserver<HTMLUListElement>();\n const root = useRef<HTMLUListElement>(null);\n\n useImperativeHandle(ref, () => root.current!, []);\n\n const setRoot = useCallback(\n (element: HTMLUListElement | null) => {\n root.current = element;\n observe(virtual ? element : null);\n },\n [observe, virtual],\n );\n\n const itemRefs = useRef(new Map<string, HTMLLIElement>());\n const hasFocus = useRef(false);\n\n const { entries, byKey } = useMemo(() => {\n const list: Entry[] = [];\n const visit = (\n siblings: readonly Node[],\n ancestors: string[],\n isDisabled: boolean,\n ) => {\n siblings.forEach((node, position) => {\n const isBranch = isBranchNode(node);\n const entry: Entry = {\n node,\n children: isBranch ? (node.children ?? []) : [],\n ancestors,\n index: list.length,\n level: ancestors.length + 1,\n position: position + 1,\n setSize: siblings.length,\n isBranch,\n isDisabled: isDisabled || !!node.disabled,\n };\n\n list.push(entry);\n visit(entry.children, [...ancestors, node.key], entry.isDisabled);\n });\n };\n\n visit(nodes, [], disabled);\n\n return {\n entries: list,\n byKey: new Map(list.map(entry => [entry.node.key, entry])),\n };\n }, [nodes, disabled]);\n const expandedSet = useMemo(() => new Set(expanded), [expanded]);\n const visible = useMemo(() => {\n const shown = new Set<string>();\n\n return entries.filter(entry => {\n const parent = entry.ancestors.at(-1);\n\n if (\n parent !== undefined &&\n !(shown.has(parent) && expandedSet.has(parent))\n ) {\n return false;\n }\n\n shown.add(entry.node.key);\n\n return true;\n });\n }, [entries, expandedSet]);\n const visibleIndex = useMemo(\n () => new Map(visible.map((entry, index) => [entry.node.key, index])),\n [visible],\n );\n const selectedSet = new Set(multiple ? selected : selected.slice(0, 1));\n const activeKey =\n focusedKey && visibleIndex.has(focusedKey)\n ? focusedKey\n : ([...(focused?.ancestors ?? [])]\n .reverse()\n .find(key => visibleIndex.has(key)) ?? visible[0]?.node.key);\n const checks = useMemo(\n () =>\n checkable\n ? deriveChecks(nodes, byKey, new Set(checked))\n : new Map<string, CheckState>(),\n [checkable, nodes, byKey, checked],\n );\n const hasLoadData = !!loadData;\n\n // Starts loads for expanded, visible branches without children, and drops\n // load state for nodes that were removed or received children.\n useEffect(() => {\n const stale = [...loadStatus.keys()].filter(key => {\n const entry = byKey.get(key);\n\n return !entry || !isUnloaded(entry);\n });\n const targets = hasLoadData\n ? visible.filter(\n entry =>\n isUnloaded(entry) &&\n expandedSet.has(entry.node.key) &&\n !loadStatus.has(entry.node.key) &&\n !controllers.current.has(entry.node.key),\n )\n : [];\n\n if (!stale.length && !targets.length) {\n return;\n }\n\n for (const key of stale) {\n controllers.current.get(key)?.abort();\n controllers.current.delete(key);\n }\n\n for (const entry of targets) {\n const { key } = entry.node;\n const controller = new AbortController();\n const settle = (status: LoadStatus) => {\n if (\n controller.signal.aborted ||\n controllers.current.get(key) !== controller\n ) {\n return;\n }\n\n controllers.current.delete(key);\n setLoadStatus(current => new Map(current).set(key, status));\n };\n\n controllers.current.set(key, controller);\n Promise.resolve()\n .then(() =>\n latestLoadData.current?.(entry.node, { signal: controller.signal }),\n )\n .then(\n () => settle('loaded'),\n () => settle('error'),\n );\n }\n\n setLoadStatus(current => {\n const next = new Map(current);\n\n for (const key of stale) {\n next.delete(key);\n }\n\n for (const entry of targets) {\n next.set(entry.node.key, 'pending');\n }\n\n return next;\n });\n }, [byKey, visible, expandedSet, loadStatus, hasLoadData, latestLoadData]);\n\n useEffect(() => {\n const pending = controllers.current;\n\n return () => {\n for (const controller of pending.values()) {\n controller.abort();\n }\n\n pending.clear();\n };\n }, []);\n\n const viewportHeight =\n size?.height ?? (typeof height === 'number' ? height : itemHeight * 10);\n\n const scrollTo = (key: string, { align = 'auto' }: ScrollOptions = {}) => {\n const index = visibleIndex.get(key);\n const element = root.current;\n\n if (index === undefined || !element) {\n return false;\n }\n\n if (!virtual) {\n itemRefs.current.get(key)?.firstElementChild?.scrollIntoView({\n block: align === 'auto' ? 'nearest' : align,\n });\n\n return true;\n }\n\n const top = index * itemHeight;\n const bottom = top + itemHeight;\n const viewport = element.clientHeight;\n const next =\n align === 'start'\n ? top\n : align === 'end'\n ? bottom - viewport\n : align === 'center'\n ? top - (viewport - itemHeight) / 2\n : top < element.scrollTop\n ? top\n : bottom > element.scrollTop + viewport\n ? bottom - viewport\n : element.scrollTop;\n\n element.scrollTop = Math.max(0, next);\n setScrollTop(element.scrollTop);\n\n return true;\n };\n\n useImperativeHandle(actionRef, () => ({ scrollTo }));\n\n const focus = (key: string | undefined) => {\n if (!key) {\n return;\n }\n\n if (virtual) {\n scrollTo(key);\n }\n\n const element = itemRefs.current.get(key);\n const entry = byKey.get(key);\n\n if (element) {\n element.focus({ preventScroll: virtual });\n } else if (entry) {\n // Virtual rows outside the window mount once they become active.\n setFocused({ key, ancestors: entry.ancestors });\n }\n };\n\n useLayoutEffect(() => {\n if (\n hasFocus.current &&\n activeKey &&\n root.current &&\n document.activeElement !== itemRefs.current.get(activeKey)\n ) {\n itemRefs.current.get(activeKey)?.focus({ preventScroll: virtual });\n }\n }, [activeKey, nodes, virtual]);\n\n const clearStatus = (key: string) =>\n setLoadStatus(current => {\n const next = new Map(current);\n\n next.delete(key);\n\n return next;\n });\n\n const expand = (entry: Entry) => {\n if (entry.isDisabled || !entry.isBranch) {\n return;\n }\n\n const { key } = entry.node;\n const isOpening = !expandedSet.has(key);\n const next = new Set(expanded);\n\n if (isOpening) {\n next.add(key);\n } else {\n next.delete(key);\n }\n\n if (isOpening && loadStatus.get(key) === 'error') {\n clearStatus(key);\n }\n\n const keys = [...next];\n\n setExpanded(keys);\n onExpand?.([...keys], { node: entry.node, expanded: isOpening });\n };\n\n const retry = (entry: Entry) => {\n if (entry.isDisabled) {\n return;\n }\n\n if (expandedSet.has(entry.node.key)) {\n clearStatus(entry.node.key);\n } else {\n expand(entry);\n }\n };\n\n const select = (entry: Entry) => {\n if (entry.isDisabled) {\n return;\n }\n\n if (!multiple) {\n setSelected([entry.node.key]);\n\n return;\n }\n\n const next = new Set(selected);\n\n if (next.has(entry.node.key)) {\n next.delete(entry.node.key);\n } else {\n next.add(entry.node.key);\n }\n\n setSelected([...next]);\n };\n\n const check = (entry: Entry) => {\n if (entry.isDisabled) {\n return;\n }\n\n const next = new Set(\n checked.filter(key => !byKey.has(key) || byKey.get(key)?.isDisabled),\n );\n\n for (const item of entries) {\n if (!item.isDisabled && checks.get(item.node.key)?.isChecked) {\n next.add(item.node.key);\n }\n }\n\n for (const ancestor of entry.ancestors) {\n next.delete(ancestor);\n }\n\n const shouldCheck = !checks.get(entry.node.key)?.isChecked;\n\n for (const item of entries) {\n if (\n item.isDisabled ||\n (item.node.key !== entry.node.key &&\n !item.ancestors.includes(entry.node.key))\n ) {\n continue;\n }\n\n if (shouldCheck) {\n next.add(item.node.key);\n } else {\n next.delete(item.node.key);\n }\n }\n\n const derived = deriveChecks(nodes, byKey, next);\n const result = entries\n .filter(item => derived.get(item.node.key)?.isChecked)\n .map(item => item.node.key);\n\n setChecked([\n ...new Set([...result, ...[...next].filter(key => !byKey.has(key))]),\n ]);\n };\n\n const loadingLabel = locale.loading ?? DEFAULT_LOCALE.loading;\n const loadFailedLabel = locale.loadFailed ?? DEFAULT_LOCALE.loadFailed;\n const retryLabel = locale.retry ?? DEFAULT_LOCALE.retry;\n\n const renderItem = (entry: Entry, virtualIndex = 0): ReactNode => {\n const { node } = entry;\n const isExpanded = expandedSet.has(node.key);\n const status = loadStatus.get(node.key);\n const isPending = status === 'pending';\n const isFailed = status === 'error';\n const state = checks.get(node.key);\n const statusId = `${id}-status-${entry.index}`;\n\n return (\n <li\n key={node.key}\n ref={element => {\n if (element) {\n itemRefs.current.set(node.key, element);\n } else {\n itemRefs.current.delete(node.key);\n }\n }}\n data-slot=\"tree-item\"\n data-key={node.key}\n role=\"treeitem\"\n aria-label={node.label}\n aria-level={entry.level}\n aria-posinset={entry.position}\n aria-setsize={entry.setSize}\n aria-expanded={entry.isBranch ? isExpanded : undefined}\n aria-selected={selectedSet.has(node.key)}\n aria-checked={\n checkable && state\n ? state.isMixed\n ? 'mixed'\n : state.isChecked\n : undefined\n }\n aria-disabled={entry.isDisabled || undefined}\n aria-busy={isPending || undefined}\n aria-describedby={isPending || isFailed ? statusId : undefined}\n tabIndex={node.key === activeKey ? 0 : -1}\n style={\n virtual\n ? { top: virtualIndex * itemHeight, height: itemHeight }\n : undefined\n }\n className={cn(\n `focus-visible:ring-ring m-0 min-w-0 list-none rounded-sm outline-none\n focus-visible:ring-2`,\n virtual && 'absolute inset-x-0 focus-visible:ring-inset',\n classNames?.item, //\n )}\n onFocus={event => {\n if (event.target !== event.currentTarget) {\n return;\n }\n\n hasFocus.current = true;\n setFocused({ key: node.key, ancestors: entry.ancestors });\n }}\n onKeyDown={event => {\n if (event.target !== event.currentTarget) {\n return;\n }\n\n if (event.key === 'Escape' || event.key === 'Tab') {\n return;\n }\n\n event.stopPropagation();\n const position = visibleIndex.get(node.key) ?? 0;\n const isRTL =\n getComputedStyle(event.currentTarget).direction === 'rtl';\n const forward = isRTL ? 'ArrowLeft' : 'ArrowRight';\n const backward = isRTL ? 'ArrowRight' : 'ArrowLeft';\n\n if (\n [\n 'ArrowDown',\n 'ArrowUp',\n 'Home',\n 'End',\n forward,\n backward,\n 'Enter',\n ' ',\n ].includes(event.key)\n ) {\n event.preventDefault();\n }\n\n if (event.key === 'ArrowDown') {\n focus(\n visible[Math.min(position + 1, visible.length - 1)]?.node.key,\n );\n } else if (event.key === 'ArrowUp') {\n focus(visible[Math.max(position - 1, 0)]?.node.key);\n } else if (event.key === 'Home') {\n focus(visible[0]?.node.key);\n } else if (event.key === 'End') {\n focus(visible.at(-1)?.node.key);\n } else if (event.key === forward && entry.isBranch) {\n if (!isExpanded) {\n expand(entry);\n } else if (isFailed) {\n retry(entry);\n } else {\n focus(entry.children[0]?.key);\n }\n } else if (event.key === backward) {\n if (entry.isBranch && isExpanded && !entry.isDisabled) {\n expand(entry);\n } else {\n focus(entry.ancestors.at(-1));\n }\n } else if (event.key === 'Enter') {\n select(entry);\n } else if (event.key === ' ') {\n if (checkable) {\n check(entry);\n } else {\n select(entry);\n }\n } else if (\n event.key.length === 1 &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.altKey\n ) {\n const candidates = [\n ...visible.slice(position + 1),\n ...visible.slice(0, position + 1),\n ];\n\n focus(\n candidates.find(item =>\n item.node.label\n .toLocaleLowerCase()\n .startsWith(event.key.toLocaleLowerCase()),\n )?.node.key,\n );\n }\n }}\n >\n <div\n data-slot=\"tree-row\"\n style={\n virtual\n ? {\n paddingInlineStart: `${(entry.level - 1) * INDENT_REM + 0.5}rem`,\n }\n : undefined\n }\n className={cn(\n 'flex min-w-0 items-center gap-2 rounded-sm px-2 py-1.5 text-sm',\n virtual && 'h-full py-0',\n selectedSet.has(node.key) && 'bg-accent text-accent-foreground',\n entry.isDisabled && 'cursor-not-allowed opacity-50',\n !entry.isDisabled && 'hover:bg-accent/50 cursor-pointer',\n classNames?.row, //\n )}\n onClick={() => {\n focus(node.key);\n\n if (expandOnClick && entry.isBranch) {\n expand(entry);\n }\n\n select(entry);\n }}\n >\n {entry.isBranch ? (\n <Button\n tabIndex={-1}\n aria-hidden=\"true\"\n variant=\"text\"\n size=\"small\"\n disabled={entry.isDisabled}\n className={cn(\n 'size-5 shrink-0 p-0',\n classNames?.toggle, //\n )}\n onMouseDown={event => event.preventDefault()}\n onClick={event => {\n event.stopPropagation();\n focus(node.key);\n expand(entry);\n }}\n >\n {isPending ? (\n <Loader2 className=\"animate-spin\" />\n ) : isExpanded ? (\n <ChevronDown />\n ) : (dir ?? direction) === 'rtl' ? (\n <ChevronLeft />\n ) : (\n <ChevronRight />\n )}\n </Button>\n ) : (\n <span aria-hidden=\"true\" className=\"size-5 shrink-0\" />\n )}\n {checkable && state && (\n <span\n data-slot=\"tree-check\"\n className={cn(\n 'shrink-0',\n classNames?.checkbox, //\n )}\n onClick={event => {\n event.stopPropagation();\n focus(node.key);\n check(entry);\n }}\n >\n <span aria-hidden=\"true\" inert className=\"pointer-events-none\">\n <Checkbox\n checked={state.isChecked}\n indeterminate={state.isMixed}\n disabled={entry.isDisabled}\n />\n </span>\n </span>\n )}\n {node.icon != null && (\n <span\n aria-hidden=\"true\"\n className={cn(\n 'flex shrink-0 [&>svg]:size-4',\n classNames?.icon, //\n )}\n >\n {node.icon}\n </span>\n )}\n <span\n className={cn(\n 'min-w-0',\n virtual ? 'truncate' : '[overflow-wrap:anywhere]',\n classNames?.label, //\n )}\n >\n {node.label}\n </span>\n {isPending && (\n <span id={statusId} className=\"sr-only\">\n {loadingLabel}\n </span>\n )}\n {isFailed && (\n <>\n <span\n id={statusId}\n data-slot=\"tree-status\"\n className={cn(\n 'text-destructive flex shrink-0 items-center gap-1 text-xs',\n classNames?.status, //\n )}\n >\n <CircleAlert aria-hidden=\"true\" className=\"size-3.5\" />\n {loadFailedLabel}\n </span>\n <Button\n tabIndex={-1}\n aria-hidden=\"true\"\n variant=\"text\"\n size=\"small\"\n className={cn(\n 'h-6 shrink-0 px-1.5 text-xs',\n classNames?.retry, //\n )}\n onMouseDown={event => event.preventDefault()}\n onClick={event => {\n event.stopPropagation();\n focus(node.key);\n retry(entry);\n }}\n >\n {retryLabel}\n </Button>\n </>\n )}\n </div>\n {!virtual && isExpanded && entry.children.length > 0 && (\n <ul\n role=\"group\"\n className={cn(\n 'border-border m-0 ms-4 list-none border-s ps-2',\n classNames?.group, //\n )}\n >\n {renderNodes(entry.children)}\n </ul>\n )}\n </li>\n );\n };\n\n const renderNodes = (list: readonly Node[]): ReactNode =>\n list.map(node => renderItem(byKey.get(node.key)!));\n\n const renderWindow = () => {\n const first = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);\n const last = Math.min(\n visible.length,\n Math.ceil((scrollTop + viewportHeight) / itemHeight) + overscan,\n );\n const indices: number[] = [];\n const activeIndex = activeKey ? visibleIndex.get(activeKey) : undefined;\n\n // The active row stays mounted outside the window so it keeps DOM focus\n // and remains the tree's tab stop.\n if (activeIndex !== undefined && activeIndex < first) {\n indices.push(activeIndex);\n }\n\n for (let index = first; index < last; index++) {\n indices.push(index);\n }\n\n if (activeIndex !== undefined && activeIndex >= last) {\n indices.push(activeIndex);\n }\n\n return (\n <>\n <li\n role=\"none\"\n aria-hidden=\"true\"\n style={{ height: visible.length * itemHeight }}\n className=\"pointer-events-none m-0 list-none\"\n />\n {indices.map(index => renderItem(visible[index]!, index))}\n </>\n );\n };\n\n return (\n <ul\n {...props}\n ref={setRoot}\n dir={dir ?? direction}\n data-slot=\"tree\"\n data-virtual={virtual || undefined}\n role=\"tree\"\n aria-label={ariaLabel}\n aria-multiselectable={multiple || undefined}\n style={virtual ? { height, ...style } : style}\n className={cn(\n 'text-foreground m-0 min-w-0 list-none p-0',\n virtual && 'relative overflow-auto',\n className, //\n )}\n onScroll={event => {\n if (virtual) {\n setScrollTop(event.currentTarget.scrollTop);\n }\n\n props.onScroll?.(event);\n }}\n onBlur={event => {\n hasFocus.current =\n !!event.relatedTarget &&\n event.currentTarget.contains(event.relatedTarget);\n props.onBlur?.(event);\n }}\n >\n {virtual ? renderWindow() : renderNodes(nodes)}\n {!nodes.length && (\n <li\n role=\"none\"\n className={cn(\n 'text-muted-foreground p-3 text-sm',\n classNames?.empty, //\n )}\n >\n {emptyText}\n </li>\n )}\n </ul>\n );\n};\n\nexport default Tree;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Node, Props as Props$1 } from "./Tree.mjs";
|
|
2
|
+
import { ComponentPropsWithRef, ReactNode } from "react";
|
|
3
|
+
//#region src/components/organisms/tree-select.d.ts
|
|
4
|
+
export interface Props extends Omit<ComponentPropsWithRef<'button'>, 'children' | 'value' | 'defaultValue' | 'onChange' | 'type'> {
|
|
5
|
+
nodes: readonly Node[];
|
|
6
|
+
value?: string | null;
|
|
7
|
+
defaultValue?: string | null;
|
|
8
|
+
onChange?: (value: string | null, node: Node | null) => void;
|
|
9
|
+
expandedKeys?: readonly string[];
|
|
10
|
+
defaultExpandedKeys?: readonly string[];
|
|
11
|
+
onExpand?: (keys: string[]) => void;
|
|
12
|
+
open?: boolean;
|
|
13
|
+
defaultOpen?: boolean;
|
|
14
|
+
onOpenChange?: (open: boolean) => void;
|
|
15
|
+
allowClear?: boolean;
|
|
16
|
+
clearLabel?: string;
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
popupLabel?: string;
|
|
19
|
+
emptyText?: ReactNode;
|
|
20
|
+
container?: HTMLElement;
|
|
21
|
+
form?: string;
|
|
22
|
+
classNames?: {
|
|
23
|
+
trigger?: string;
|
|
24
|
+
value?: string;
|
|
25
|
+
clear?: string;
|
|
26
|
+
popup?: string;
|
|
27
|
+
tree?: string;
|
|
28
|
+
nodes?: Props$1['classNames'];
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
declare const TreeSelect: ({ nodes, value, defaultValue, onChange, expandedKeys, defaultExpandedKeys, onExpand, open, defaultOpen, onOpenChange, allowClear, clearLabel, placeholder, popupLabel, emptyText, container, name, form, disabled, className, classNames, dir, ref, onKeyDown, ...props }: Props) => import("react").JSX.Element;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { type Node, TreeSelect as default };
|
|
34
|
+
//# sourceMappingURL=TreeSelect.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeSelect.d.mts","names":["TreeProps"],"sources":["../src/components/organisms/tree-select.tsx"],"mappings":";;;iBAsBiB,cAAc,KAC7B;EAGA,gBAAgB;EAChB;EACA;EACA,YAAY,sBAAsB,MAAM;EACxC;EACA;EACA,YAAY;EACZ;EACA;EACA,gBAAgB;EAChB;EACA;EACA;EACA;EACA,YAAY;EACZ,YAAY;EACZ;EACA;IACE;IACA;IACA;IACA;IACA;IACA,QAAQA;;;cAIN,eAAc,OAAA,OAAA,cAAA,UAAA,cAAA,qBAAA,UAAA,MAAA,aAAA,cAAA,YAAA,YAAA,aAAA,YAAA,WAAA,WAAA,MAAA,MAAA,UAAA,WAAA,YAAA,KAAA,KAAA,cAAA,SA0BjB,0BAAK,IAAA"}
|