torch-glare 2.4.0 → 2.4.1
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/README.md +8 -0
- package/apps/lib/components/ActionButton.tsx +7 -12
- package/apps/lib/components/ActionsGroup.tsx +4 -15
- package/apps/lib/components/AlertDialog.tsx +173 -191
- package/apps/lib/components/Avatar.tsx +13 -16
- package/apps/lib/components/Badge.tsx +1 -3
- package/apps/lib/components/BadgeField.tsx +76 -71
- package/apps/lib/components/Breadcrumb.tsx +49 -85
- package/apps/lib/components/Button.tsx +20 -19
- package/apps/lib/components/ButtonGroup.tsx +31 -41
- package/apps/lib/components/Calendar.tsx +51 -29
- package/apps/lib/components/Card.tsx +2 -13
- package/apps/lib/components/ChartBlockTool.ts +17 -52
- package/apps/lib/components/Checkbox.tsx +9 -16
- package/apps/lib/components/ContextMenu.tsx +97 -96
- package/apps/lib/components/CountBadge.tsx +4 -6
- package/apps/lib/components/DataTable.tsx +196 -216
- package/apps/lib/components/DataViews/DataViewRadio.tsx +1 -6
- package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +13 -47
- package/apps/lib/components/DataViews/DataViewsHeader.tsx +1 -3
- package/apps/lib/components/DataViews/DataViewsLayout.tsx +5 -12
- package/apps/lib/components/DataViews/FilterPanel.tsx +155 -149
- package/apps/lib/components/DataViews/HeaderSearch.tsx +1 -5
- package/apps/lib/components/DataViews/InboxView.tsx +22 -68
- package/apps/lib/components/DataViews/InboxViewCard.tsx +68 -77
- package/apps/lib/components/DataViews/KanbanView.tsx +8 -25
- package/apps/lib/components/DataViews/PanelControls.tsx +3 -13
- package/apps/lib/components/DataViews/SettingsPanel.tsx +83 -89
- package/apps/lib/components/DataViews/TableView.tsx +8 -28
- package/apps/lib/components/DataViews/TreeView.tsx +12 -40
- package/apps/lib/components/DataViews/badgeAdapter.ts +32 -28
- package/apps/lib/components/DataViews/fieldRenderers.tsx +106 -141
- package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +30 -23
- package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +39 -32
- package/apps/lib/components/DataViews/filters/PresetChips.tsx +15 -15
- package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +69 -58
- package/apps/lib/components/DataViews/index.ts +26 -26
- package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +12 -16
- package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +28 -31
- package/apps/lib/components/DataViews/types.ts +104 -115
- package/apps/lib/components/DatePicker.tsx +198 -196
- package/apps/lib/components/Dialog.tsx +92 -105
- package/apps/lib/components/Divider.tsx +21 -24
- package/apps/lib/components/Drawer.tsx +79 -139
- package/apps/lib/components/DropdownMenu.tsx +131 -171
- package/apps/lib/components/FieldHint.tsx +4 -11
- package/apps/lib/components/Form.tsx +146 -155
- package/apps/lib/components/FormStepper.tsx +9 -39
- package/apps/lib/components/HeaderBar.tsx +1 -9
- package/apps/lib/components/ImageAttachment.tsx +111 -73
- package/apps/lib/components/InnerLabelField.tsx +20 -16
- package/apps/lib/components/Input.tsx +171 -172
- package/apps/lib/components/InputField.tsx +44 -45
- package/apps/lib/components/InputOTP.tsx +68 -69
- package/apps/lib/components/Label.tsx +31 -35
- package/apps/lib/components/LabelField.tsx +4 -5
- package/apps/lib/components/LabeledCheckBox.tsx +8 -12
- package/apps/lib/components/LabeledRadio.tsx +7 -5
- package/apps/lib/components/LinkButton.tsx +2 -9
- package/apps/lib/components/LoginButton.tsx +4 -9
- package/apps/lib/components/PasswordLevel.tsx +5 -5
- package/apps/lib/components/Popover.tsx +15 -33
- package/apps/lib/components/ProfileMenu.tsx +67 -72
- package/apps/lib/components/Radio.tsx +1 -5
- package/apps/lib/components/RadioCard.tsx +9 -28
- package/apps/lib/components/ScrollArea.tsx +45 -43
- package/apps/lib/components/SearchField.tsx +49 -39
- package/apps/lib/components/SearchableSelect.tsx +8 -14
- package/apps/lib/components/SearchableTable.tsx +108 -118
- package/apps/lib/components/SearchableTree.tsx +469 -0
- package/apps/lib/components/SearchableTreeDialog.tsx +493 -0
- package/apps/lib/components/SectionBlock.tsx +4 -16
- package/apps/lib/components/Select.tsx +53 -80
- package/apps/lib/components/SimpleSelect.tsx +196 -187
- package/apps/lib/components/Skeleton.tsx +9 -12
- package/apps/lib/components/SlideDatePicker.tsx +215 -166
- package/apps/lib/components/SpinLoading.tsx +33 -49
- package/apps/lib/components/Stepper.tsx +13 -56
- package/apps/lib/components/Switch.tsx +8 -10
- package/apps/lib/components/TabFormItem.tsx +3 -12
- package/apps/lib/components/TabSwitch.tsx +7 -34
- package/apps/lib/components/Table.tsx +60 -75
- package/apps/lib/components/TableDnDWrapper.ts +15 -48
- package/apps/lib/components/TextEditor.tsx +93 -104
- package/apps/lib/components/Textarea.tsx +8 -12
- package/apps/lib/components/Timeline.tsx +21 -41
- package/apps/lib/components/Toast.tsx +83 -83
- package/apps/lib/components/Toggle.tsx +112 -114
- package/apps/lib/components/ToggleButton.tsx +1 -1
- package/apps/lib/components/Tooltip.tsx +24 -19
- package/apps/lib/components/TransparentLabel.tsx +61 -62
- package/apps/lib/components/TreeDropDown.tsx +86 -52
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +15 -48
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +16 -21
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +9 -20
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +3 -3
- package/apps/lib/components/TreeFolder/icons.tsx +14 -17
- package/apps/lib/components/TreeFolder/index.ts +15 -8
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +47 -52
- package/apps/lib/components/TreeFolder/types.ts +32 -32
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +117 -123
- package/apps/lib/hooks/useActiveTreeItem.ts +52 -55
- package/apps/lib/hooks/useClickOutside.ts +21 -20
- package/apps/lib/hooks/useDataViewsState.ts +86 -80
- package/apps/lib/hooks/useIsMobile.ts +12 -12
- package/apps/lib/hooks/useResize.ts +54 -65
- package/apps/lib/hooks/useTagSelection.ts +201 -201
- package/apps/lib/layouts/CNLayout.tsx +181 -140
- package/apps/lib/layouts/DataViewCard.tsx +4 -18
- package/apps/lib/layouts/FieldSection.tsx +2 -6
- package/apps/lib/layouts/TreeSubLayout.tsx +24 -38
- package/apps/lib/providers/ThemeProvider.tsx +8 -23
- package/apps/lib/registry.json +1004 -0
- package/apps/lib/tsconfig.json +9 -0
- package/apps/lib/utils/cn.ts +1 -1
- package/apps/lib/utils/dataViews/columnUtils.ts +46 -44
- package/apps/lib/utils/dataViews/fieldUtils.ts +70 -71
- package/apps/lib/utils/dataViews/nestedDataUtils.tsx +129 -122
- package/apps/lib/utils/dataViews/pathUtils.ts +74 -67
- package/apps/lib/utils/dataViews/rangeUtils.ts +121 -112
- package/apps/lib/utils/dataViews/treeUtils.ts +204 -211
- package/apps/lib/utils/dateFormat.ts +64 -54
- package/apps/lib/utils/markdownParser.ts +2 -7
- package/apps/lib/utils/resize.ts +21 -25
- package/apps/lib/utils/types.ts +13 -13
- package/dist/bin/index.js +8 -2
- package/dist/bin/index.js.map +1 -1
- package/dist/src/shared/getAvailableFiles.d.ts.map +1 -1
- package/dist/src/shared/getAvailableFiles.js +6 -1
- package/dist/src/shared/getAvailableFiles.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +7 -0
- package/dist/src/shared/loadRegistry.d.ts.map +1 -0
- package/dist/src/shared/loadRegistry.js +31 -0
- package/dist/src/shared/loadRegistry.js.map +1 -0
- package/dist/src/shared/resolveInstallPlan.d.ts +12 -0
- package/dist/src/shared/resolveInstallPlan.d.ts.map +1 -0
- package/dist/src/shared/resolveInstallPlan.js +39 -0
- package/dist/src/shared/resolveInstallPlan.js.map +1 -0
- package/dist/src/types/main.d.ts +24 -0
- package/dist/src/types/main.d.ts.map +1 -1
- package/docs/README.md +10 -2
- package/docs/components/action-button.md +30 -24
- package/docs/components/actions-group.md +26 -20
- package/docs/components/alert-dialog.md +45 -45
- package/docs/components/avatar.md +6 -2
- package/docs/components/badge-field.md +6 -2
- package/docs/components/badge.md +7 -1
- package/docs/components/breadcrumb.md +15 -40
- package/docs/components/button-group.md +13 -10
- package/docs/components/button.md +58 -33
- package/docs/components/calendar.md +26 -19
- package/docs/components/card.md +19 -16
- package/docs/components/chart-block-tool.md +128 -0
- package/docs/components/checkbox.md +16 -8
- package/docs/components/cn-layout.md +7 -1
- package/docs/components/context-menu.md +18 -25
- package/docs/components/count-badge.md +7 -1
- package/docs/components/data-table.md +45 -33
- package/docs/components/data-views-config-panel.md +15 -11
- package/docs/components/data-views-layout.md +13 -16
- package/docs/components/date-picker.md +30 -23
- package/docs/components/dialog.md +43 -42
- package/docs/components/divider.md +10 -4
- package/docs/components/drawer.md +8 -33
- package/docs/components/dropdown-menu.md +25 -34
- package/docs/components/field-hint.md +37 -25
- package/docs/components/field-section.md +9 -3
- package/docs/components/form-stepper.md +6 -0
- package/docs/components/form.md +17 -20
- package/docs/components/header-bar.md +6 -0
- package/docs/components/image-attachment.md +33 -41
- package/docs/components/inbox-view.md +16 -5
- package/docs/components/inner-label-field.md +34 -24
- package/docs/components/input-field.md +18 -10
- package/docs/components/input-otp.md +14 -11
- package/docs/components/input.md +22 -16
- package/docs/components/kanban-view.md +15 -5
- package/docs/components/label-field.md +32 -22
- package/docs/components/label.md +43 -32
- package/docs/components/labeled-check-box.md +16 -8
- package/docs/components/labeled-radio.md +18 -11
- package/docs/components/link-button.md +7 -1
- package/docs/components/login-button.md +8 -2
- package/docs/components/password-level.md +37 -24
- package/docs/components/popover.md +26 -23
- package/docs/components/profile-menu.md +38 -27
- package/docs/components/radio-card.md +16 -9
- package/docs/components/radio.md +16 -8
- package/docs/components/scroll-area.md +6 -2
- package/docs/components/search-field.md +14 -6
- package/docs/components/searchable-select.md +19 -14
- package/docs/components/searchable-table.md +18 -13
- package/docs/components/searchable-tree-dialog.md +190 -0
- package/docs/components/searchable-tree.md +200 -0
- package/docs/components/section-block.md +12 -4
- package/docs/components/select.md +23 -18
- package/docs/components/simple-select.md +14 -10
- package/docs/components/skeleton.md +43 -33
- package/docs/components/slide-date-picker.md +37 -29
- package/docs/components/spin-loading.md +32 -23
- package/docs/components/stepper.md +6 -0
- package/docs/components/switch.md +14 -6
- package/docs/components/tab-form-item.md +7 -1
- package/docs/components/tab-switch.md +13 -6
- package/docs/components/table-dnd-wrapper.md +105 -0
- package/docs/components/table-view.md +15 -5
- package/docs/components/table.md +28 -28
- package/docs/components/text-editor.md +19 -13
- package/docs/components/textarea.md +15 -7
- package/docs/components/timeline.md +6 -0
- package/docs/components/toast.md +35 -26
- package/docs/components/toggle-button.md +24 -21
- package/docs/components/toggle.md +23 -15
- package/docs/components/tooltip.md +42 -30
- package/docs/components/transparent-label.md +29 -20
- package/docs/components/tree-drop-down.md +31 -23
- package/docs/components/tree-sub-layout.md +6 -2
- package/docs/components/tree-view.md +16 -5
- package/docs/explanation/architecture.md +54 -0
- package/docs/explanation/design-system.md +52 -0
- package/docs/how-to/data-views-from-backend-response.md +6 -4
- package/docs/how-to/guides.md +24 -18
- package/docs/migration/changelog.md +38 -0
- package/docs/reference/cli.md +87 -0
- package/docs/reference/components.md +11 -12
- package/docs/reference/hooks.md +8 -8
- package/docs/reference/providers.md +22 -22
- package/docs/reference/tailwind-plugins.md +2 -2
- package/docs/reference/theme.md +85 -0
- package/docs/reference/types.md +4 -4
- package/docs/reference/utilities.md +19 -26
- package/docs/tutorials/building-first-form.md +20 -13
- package/docs/tutorials/component-composition.md +34 -50
- package/docs/tutorials/getting-started.md +2 -2
- package/docs/tutorials/theming-basics.md +13 -10
- package/package.json +31 -3
- package/dist/src/commands/block.d.ts +0 -5
- package/dist/src/commands/block.d.ts.map +0 -1
- package/dist/src/commands/block.js +0 -255
- package/dist/src/commands/block.js.map +0 -1
- package/dist/src/shared/configureFonts.d.ts +0 -6
- package/dist/src/shared/configureFonts.d.ts.map +0 -1
- package/dist/src/shared/configureFonts.js +0 -106
- package/dist/src/shared/configureFonts.js.map +0 -1
- package/dist/src/shared/configureGlobalCss.d.ts +0 -6
- package/dist/src/shared/configureGlobalCss.d.ts.map +0 -1
- package/dist/src/shared/configureGlobalCss.js +0 -154
- package/dist/src/shared/configureGlobalCss.js.map +0 -1
- package/dist/src/shared/configureTailwind.d.ts +0 -7
- package/dist/src/shared/configureTailwind.d.ts.map +0 -1
- package/dist/src/shared/configureTailwind.js +0 -163
- package/dist/src/shared/configureTailwind.js.map +0 -1
- package/dist/src/shared/detectFramework.d.ts +0 -23
- package/dist/src/shared/detectFramework.d.ts.map +0 -1
- package/dist/src/shared/detectFramework.js +0 -119
- package/dist/src/shared/detectFramework.js.map +0 -1
- package/dist/src/shared/installBaseUtils.d.ts +0 -5
- package/dist/src/shared/installBaseUtils.d.ts.map +0 -1
- package/dist/src/shared/installBaseUtils.js +0 -79
- package/dist/src/shared/installBaseUtils.js.map +0 -1
- package/dist/src/shared/resolveAliases.d.ts +0 -24
- package/dist/src/shared/resolveAliases.d.ts.map +0 -1
- package/dist/src/shared/resolveAliases.js +0 -98
- package/dist/src/shared/resolveAliases.js.map +0 -1
|
@@ -1,69 +1,103 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
2
|
import { cn } from "../utils/cn";
|
|
3
3
|
import { cva, VariantProps } from "class-variance-authority";
|
|
4
4
|
import { HTMLAttributes, ReactNode, useEffect, useState } from "react";
|
|
5
5
|
|
|
6
|
-
const TreeDropDownVariants = cva(
|
|
6
|
+
const TreeDropDownVariants = cva(
|
|
7
|
+
[
|
|
8
|
+
"cursor-pointer flex px-[6px] h-[40px] gap-2 justify-start items-center w-full",
|
|
7
9
|
"text-content-system-global-primary border-l-[2px] rtl:border-r-[2px] border-transparent outline-none",
|
|
8
10
|
"hover:bg-white-alpha-075 hover:border-black-300 hover:text-content-system-action-primary-hover hover:gap-[14px]",
|
|
9
11
|
"rounded-r-[4px] text-start whitespace-nowrap transition-all duration-150 ease-in-out",
|
|
10
|
-
],
|
|
12
|
+
],
|
|
13
|
+
{
|
|
11
14
|
variants: {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
variant: {
|
|
16
|
+
secondary: "",
|
|
17
|
+
default: "",
|
|
18
|
+
},
|
|
19
|
+
active: {
|
|
20
|
+
true: "hover:gap-[8px]",
|
|
21
|
+
},
|
|
19
22
|
},
|
|
20
23
|
compoundVariants: [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
{
|
|
25
|
+
active: true,
|
|
26
|
+
variant: "default",
|
|
27
|
+
className: [
|
|
28
|
+
"bg-background-system-action-primary-hover border-border-system-action-primary-hover [&_button]:bg-purple-alpha-15 hover:bg-background-system-action-primary-hover hover:border-border-system-action-primary-hover",
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
active: true,
|
|
33
|
+
variant: "secondary",
|
|
34
|
+
className: [
|
|
35
|
+
"bg-wavy-navy-1000 border-border-system-action-field-hover-selected [&_button]:bg-blue-sparkle-alpha-15 hover:bg-wavy-navy-1000 hover:border-border-system-action-field-hover-selected",
|
|
36
|
+
],
|
|
37
|
+
},
|
|
35
38
|
],
|
|
36
|
-
defaultVariants: {}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
defaultVariants: {}, //
|
|
40
|
+
},
|
|
41
|
+
);
|
|
39
42
|
|
|
40
43
|
interface Props extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof TreeDropDownVariants> {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
theme?: "dark" | "light" | "default";
|
|
45
|
+
treeLabel: ReactNode;
|
|
46
|
+
open?: boolean;
|
|
47
|
+
variant?: "secondary" | "default";
|
|
48
|
+
childrenContainerClassName?: string;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
export const TreeDropDown = ({
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
export const TreeDropDown = ({
|
|
52
|
+
childrenContainerClassName,
|
|
53
|
+
className,
|
|
54
|
+
variant = "secondary",
|
|
55
|
+
treeLabel,
|
|
56
|
+
open,
|
|
57
|
+
theme,
|
|
58
|
+
...props
|
|
59
|
+
}: Props) => {
|
|
60
|
+
const [isActive, setIsActive] = useState(open);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
setIsActive(open);
|
|
63
|
+
}, [open]);
|
|
64
|
+
return (
|
|
65
|
+
<div {...props} className={cn("flex h-fit flex-col transition-all ease-in-out duration-500")}>
|
|
66
|
+
<div
|
|
67
|
+
onClick={() => setIsActive(!isActive)}
|
|
68
|
+
data-theme={theme}
|
|
69
|
+
className={cn(TreeDropDownVariants({ variant, active: isActive }), className)}
|
|
70
|
+
>
|
|
71
|
+
<button
|
|
72
|
+
className={cn(
|
|
73
|
+
"cursor-pointer outline-none border-none flex-0 leading-0 transition-transform ease-in-out flex justify-center items-center bg-background-system-body-tertiary h-[28px] w-[28px] rounded-full text-[20px] text-content-system-global-primary",
|
|
74
|
+
{ "rotate-180": isActive },
|
|
75
|
+
)}
|
|
76
|
+
>
|
|
77
|
+
<i className={cn("leading-none ri-arrow-down-s-line ")}></i>
|
|
78
|
+
</button>
|
|
79
|
+
<div
|
|
80
|
+
className={cn(
|
|
81
|
+
"text-content-system-global-primary typography-body-medium-medium transition-all ease-in-out duration-100 flex-1 cursor-pointer",
|
|
82
|
+
)}
|
|
83
|
+
>
|
|
84
|
+
{treeLabel}
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
<div
|
|
88
|
+
className={cn(
|
|
89
|
+
"mt-0 pl-[22px] relative overflow-auto scrollbar-hide transition-all duration-500 ease-in-out",
|
|
90
|
+
{
|
|
91
|
+
"max-h-[20000px] mt-1": isActive,
|
|
92
|
+
"max-h-0": !isActive,
|
|
93
|
+
},
|
|
94
|
+
)}
|
|
95
|
+
>
|
|
96
|
+
<span className="h-full w-[1px] bg-border-system-global-primary absolute left-[21px] top-0 rounded-sm z-10" />
|
|
97
|
+
<div className={cn("h-full flex flex-col gap-1 w-full", childrenContainerClassName)}>
|
|
98
|
+
{props.children}
|
|
67
99
|
</div>
|
|
68
|
-
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
69
103
|
};
|
|
@@ -14,13 +14,7 @@ import type { Themes } from "../../utils/types";
|
|
|
14
14
|
import { TreeFolderBreadcrumb } from "./TreeFolderBreadcrumb";
|
|
15
15
|
import { TreeFolderRow } from "./TreeFolderRow";
|
|
16
16
|
import { TreeFolderStyles } from "./TreeFolderStyles";
|
|
17
|
-
import {
|
|
18
|
-
applyMove,
|
|
19
|
-
descendantIds,
|
|
20
|
-
findNode,
|
|
21
|
-
findPath,
|
|
22
|
-
toBreadcrumb,
|
|
23
|
-
} from "./treeFolderUtils";
|
|
17
|
+
import { applyMove, descendantIds, findNode, findPath, toBreadcrumb } from "./treeFolderUtils";
|
|
24
18
|
import type {
|
|
25
19
|
TreeFolderIconResolver,
|
|
26
20
|
TreeFolderMoveArgs,
|
|
@@ -85,21 +79,14 @@ function rootIds(nodes: TreeFolderNode[]): string[] {
|
|
|
85
79
|
return nodes.map((n) => n.id);
|
|
86
80
|
}
|
|
87
81
|
|
|
88
|
-
function flattenVisible(
|
|
89
|
-
data: TreeFolderNode[],
|
|
90
|
-
expanded: Set<string>,
|
|
91
|
-
): TreeFolderVisibleRow[] {
|
|
82
|
+
function flattenVisible(data: TreeFolderNode[], expanded: Set<string>): TreeFolderVisibleRow[] {
|
|
92
83
|
const out: TreeFolderVisibleRow[] = [];
|
|
93
84
|
// `ancestorHasMore` tracks, for each open ancestor depth on the descent
|
|
94
85
|
// path, whether that ancestor still has more siblings to render. We push
|
|
95
86
|
// before descending and pop on the way back up; each row snapshots the
|
|
96
87
|
// current state so its connector gutters know which verticals to draw.
|
|
97
88
|
const ancestorHasMore: boolean[] = [];
|
|
98
|
-
const walk = (
|
|
99
|
-
nodes: TreeFolderNode[],
|
|
100
|
-
level: number,
|
|
101
|
-
parentId: string | null,
|
|
102
|
-
) => {
|
|
89
|
+
const walk = (nodes: TreeFolderNode[], level: number, parentId: string | null) => {
|
|
103
90
|
nodes.forEach((node, idx) => {
|
|
104
91
|
const isInternal = !!(node.children && node.children.length > 0);
|
|
105
92
|
const isOpen = isInternal && expanded.has(node.id);
|
|
@@ -156,11 +143,8 @@ export const TreeFolder = forwardRef<TreeFolderHandle, TreeFolderProps>(
|
|
|
156
143
|
const scrollRef = useRef<HTMLDivElement | null>(null);
|
|
157
144
|
|
|
158
145
|
// ---- Selection state ----
|
|
159
|
-
const [internalSelected, setInternalSelected] = useState<string | null>(
|
|
160
|
-
|
|
161
|
-
);
|
|
162
|
-
const selectedId =
|
|
163
|
-
controlledSelected !== undefined ? controlledSelected : internalSelected;
|
|
146
|
+
const [internalSelected, setInternalSelected] = useState<string | null>(defaultSelectedId);
|
|
147
|
+
const selectedId = controlledSelected !== undefined ? controlledSelected : internalSelected;
|
|
164
148
|
const isSelectionControlled = controlledSelected !== undefined;
|
|
165
149
|
|
|
166
150
|
// ---- Expansion state ----
|
|
@@ -175,10 +159,7 @@ export const TreeFolder = forwardRef<TreeFolderHandle, TreeFolderProps>(
|
|
|
175
159
|
const expandedSet = useMemo(() => new Set(expandedIds), [expandedIds]);
|
|
176
160
|
|
|
177
161
|
// ---- Visible rows ----
|
|
178
|
-
const visibleRows = useMemo(
|
|
179
|
-
() => flattenVisible(data, expandedSet),
|
|
180
|
-
[data, expandedSet],
|
|
181
|
-
);
|
|
162
|
+
const visibleRows = useMemo(() => flattenVisible(data, expandedSet), [data, expandedSet]);
|
|
182
163
|
const rowsById = useMemo(() => {
|
|
183
164
|
const m = new Map<string, TreeFolderVisibleRow>();
|
|
184
165
|
for (const r of visibleRows) m.set(r.node.id, r);
|
|
@@ -244,9 +225,7 @@ export const TreeFolder = forwardRef<TreeFolderHandle, TreeFolderProps>(
|
|
|
244
225
|
);
|
|
245
226
|
|
|
246
227
|
const scrollToId = useCallback((id: string) => {
|
|
247
|
-
const el = scrollRef.current?.querySelector<HTMLElement>(
|
|
248
|
-
`[data-row-id="${CSS.escape(id)}"]`,
|
|
249
|
-
);
|
|
228
|
+
const el = scrollRef.current?.querySelector<HTMLElement>(`[data-row-id="${CSS.escape(id)}"]`);
|
|
250
229
|
el?.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
251
230
|
}, []);
|
|
252
231
|
|
|
@@ -299,9 +278,7 @@ export const TreeFolder = forwardRef<TreeFolderHandle, TreeFolderProps>(
|
|
|
299
278
|
);
|
|
300
279
|
|
|
301
280
|
const isEmpty = data.length === 0;
|
|
302
|
-
const stripStyle = contentMinWidth
|
|
303
|
-
? { minWidth: contentMinWidth }
|
|
304
|
-
: undefined;
|
|
281
|
+
const stripStyle = contentMinWidth ? { minWidth: contentMinWidth } : undefined;
|
|
305
282
|
|
|
306
283
|
return (
|
|
307
284
|
<div
|
|
@@ -333,11 +310,7 @@ export const TreeFolder = forwardRef<TreeFolderHandle, TreeFolderProps>(
|
|
|
333
310
|
)}
|
|
334
311
|
|
|
335
312
|
<TreeFolderStyles />
|
|
336
|
-
<div
|
|
337
|
-
ref={scrollRef}
|
|
338
|
-
role="tree"
|
|
339
|
-
className="tf-scroll flex-1 min-h-0 overflow-auto"
|
|
340
|
-
>
|
|
313
|
+
<div ref={scrollRef} role="tree" className="tf-scroll flex-1 min-h-0 overflow-auto">
|
|
341
314
|
{isEmpty ? (
|
|
342
315
|
(emptyState ?? (
|
|
343
316
|
<div className="text-xs text-content-presentation-global-tertiary p-3">
|
|
@@ -350,8 +323,7 @@ export const TreeFolder = forwardRef<TreeFolderHandle, TreeFolderProps>(
|
|
|
350
323
|
const prevRow = visibleRows[idx - 1];
|
|
351
324
|
const nextRow = visibleRows[idx + 1];
|
|
352
325
|
const isSelected = selectedId === row.node.id;
|
|
353
|
-
const isDescendant =
|
|
354
|
-
isDescendantOfSelected(row.node.id) && !isSelected;
|
|
326
|
+
const isDescendant = isDescendantOfSelected(row.node.id) && !isSelected;
|
|
355
327
|
const inBand = isSelected || isDescendant;
|
|
356
328
|
|
|
357
329
|
// Neighbour-aware band rounding: a row is "in-band" if it's the selected
|
|
@@ -359,24 +331,19 @@ export const TreeFolder = forwardRef<TreeFolderHandle, TreeFolderProps>(
|
|
|
359
331
|
const prevInBand =
|
|
360
332
|
inBand &&
|
|
361
333
|
!!prevRow &&
|
|
362
|
-
(prevRow.node.id === selectedId ||
|
|
363
|
-
descendantIdSet.has(prevRow.node.id));
|
|
334
|
+
(prevRow.node.id === selectedId || descendantIdSet.has(prevRow.node.id));
|
|
364
335
|
const nextInBand =
|
|
365
336
|
inBand &&
|
|
366
337
|
!!nextRow &&
|
|
367
|
-
(nextRow.node.id === selectedId ||
|
|
368
|
-
descendantIdSet.has(nextRow.node.id));
|
|
338
|
+
(nextRow.node.id === selectedId || descendantIdSet.has(nextRow.node.id));
|
|
369
339
|
|
|
370
340
|
const isDragging = dragIdSet.has(row.node.id);
|
|
371
341
|
const isDropTargetInside =
|
|
372
|
-
dropTarget?.rowId === row.node.id &&
|
|
373
|
-
dropTarget.position === "inside";
|
|
342
|
+
dropTarget?.rowId === row.node.id && dropTarget.position === "inside";
|
|
374
343
|
const isDropBefore =
|
|
375
|
-
dropTarget?.rowId === row.node.id &&
|
|
376
|
-
dropTarget.position === "before";
|
|
344
|
+
dropTarget?.rowId === row.node.id && dropTarget.position === "before";
|
|
377
345
|
const isDropAfter =
|
|
378
|
-
dropTarget?.rowId === row.node.id &&
|
|
379
|
-
dropTarget.position === "after";
|
|
346
|
+
dropTarget?.rowId === row.node.id && dropTarget.position === "after";
|
|
380
347
|
|
|
381
348
|
return (
|
|
382
349
|
<TreeFolderRow
|
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
"use client"
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import { ChevronRight } from "lucide-react"
|
|
4
|
-
import { cn } from "../../utils/cn"
|
|
5
|
-
import type { TreeFolderBreadcrumb as BreadcrumbItems } from "./types"
|
|
3
|
+
import { ChevronRight } from "lucide-react";
|
|
4
|
+
import { cn } from "../../utils/cn";
|
|
5
|
+
import type { TreeFolderBreadcrumb as BreadcrumbItems } from "./types";
|
|
6
6
|
|
|
7
7
|
type Props = {
|
|
8
|
-
items: BreadcrumbItems
|
|
9
|
-
onSelect?: (id: string) => void
|
|
10
|
-
className?: string
|
|
11
|
-
maxItems?: number
|
|
12
|
-
}
|
|
8
|
+
items: BreadcrumbItems;
|
|
9
|
+
onSelect?: (id: string) => void;
|
|
10
|
+
className?: string;
|
|
11
|
+
maxItems?: number;
|
|
12
|
+
};
|
|
13
13
|
|
|
14
|
-
export function TreeFolderBreadcrumb({
|
|
15
|
-
items,
|
|
16
|
-
onSelect,
|
|
17
|
-
className,
|
|
18
|
-
maxItems = 4,
|
|
19
|
-
}: Props) {
|
|
14
|
+
export function TreeFolderBreadcrumb({ items, onSelect, className, maxItems = 4 }: Props) {
|
|
20
15
|
if (items.length === 0) {
|
|
21
16
|
return (
|
|
22
17
|
<div
|
|
@@ -27,13 +22,13 @@ export function TreeFolderBreadcrumb({
|
|
|
27
22
|
>
|
|
28
23
|
No selection
|
|
29
24
|
</div>
|
|
30
|
-
)
|
|
25
|
+
);
|
|
31
26
|
}
|
|
32
27
|
|
|
33
28
|
const display =
|
|
34
29
|
items.length > maxItems
|
|
35
30
|
? [items[0], { id: "__ellipsis", name: "…" }, ...items.slice(-(maxItems - 2))]
|
|
36
|
-
: items
|
|
31
|
+
: items;
|
|
37
32
|
|
|
38
33
|
return (
|
|
39
34
|
<nav
|
|
@@ -45,8 +40,8 @@ export function TreeFolderBreadcrumb({
|
|
|
45
40
|
>
|
|
46
41
|
<ol className="flex items-center gap-1 min-w-0 flex-1">
|
|
47
42
|
{display.map((item, idx) => {
|
|
48
|
-
const isLast = idx === display.length - 1
|
|
49
|
-
const isEllipsis = item.id === "__ellipsis"
|
|
43
|
+
const isLast = idx === display.length - 1;
|
|
44
|
+
const isEllipsis = item.id === "__ellipsis";
|
|
50
45
|
return (
|
|
51
46
|
<li key={`${item.id}-${idx}`} className="flex items-center gap-1 min-w-0">
|
|
52
47
|
{idx > 0 && (
|
|
@@ -72,9 +67,9 @@ export function TreeFolderBreadcrumb({
|
|
|
72
67
|
</button>
|
|
73
68
|
)}
|
|
74
69
|
</li>
|
|
75
|
-
)
|
|
70
|
+
);
|
|
76
71
|
})}
|
|
77
72
|
</ol>
|
|
78
73
|
</nav>
|
|
79
|
-
)
|
|
74
|
+
);
|
|
80
75
|
}
|
|
@@ -4,7 +4,7 @@ import { ChevronRight, ChevronDown, GripVertical } from "lucide-react";
|
|
|
4
4
|
import type { DragEvent } from "react";
|
|
5
5
|
import { cn } from "../../utils/cn";
|
|
6
6
|
import { resolveIcon } from "./icons";
|
|
7
|
-
import type { TreeFolderIconResolver, TreeFolderVisibleRow } from "./types";
|
|
7
|
+
import type { TreeFolderIconResolver, TreeFolderNode, TreeFolderVisibleRow } from "./types";
|
|
8
8
|
|
|
9
9
|
export type TreeFolderRowDragHandlers = {
|
|
10
10
|
draggable: boolean;
|
|
@@ -70,8 +70,7 @@ export function TreeFolderRow({
|
|
|
70
70
|
// they read as "members of the selected group" without competing with the
|
|
71
71
|
// selection itself. Rows stand alone — no neighbor-aware joining anymore.
|
|
72
72
|
const showSelected = isSelected && !willReceiveDrop;
|
|
73
|
-
const showChildOfSelected =
|
|
74
|
-
inSubtreeOfSelected && !isSelected && !willReceiveDrop;
|
|
73
|
+
const showChildOfSelected = inSubtreeOfSelected && !isSelected && !willReceiveDrop;
|
|
75
74
|
// A row is "in the selection group" if it's the selected node itself or a
|
|
76
75
|
// descendant tinted by it. Neighbor-aware rounding then merges adjacent rows
|
|
77
76
|
// into one continuous pill instead of stacked individual chips.
|
|
@@ -102,9 +101,7 @@ export function TreeFolderRow({
|
|
|
102
101
|
// Token isn't exposed as channels, so Tailwind's /alpha modifier doesn't
|
|
103
102
|
// work on it — paint the descendant tint with the same hex at 30% alpha.
|
|
104
103
|
showChildOfSelected && "bg-[#005ECC]/30",
|
|
105
|
-
inAncestorChain &&
|
|
106
|
-
!inGroup &&
|
|
107
|
-
"bg-background-presentation-state-information-secondary",
|
|
104
|
+
inAncestorChain && !inGroup && "bg-background-presentation-state-information-secondary",
|
|
108
105
|
willReceiveDrop && "bg-background-presentation-state-information-primary",
|
|
109
106
|
);
|
|
110
107
|
|
|
@@ -155,9 +152,7 @@ export function TreeFolderRow({
|
|
|
155
152
|
<GripVertical
|
|
156
153
|
className={cn(
|
|
157
154
|
"w-3.5 h-3.5",
|
|
158
|
-
showSelected
|
|
159
|
-
? "text-white/80"
|
|
160
|
-
: "text-content-presentation-global-tertiary",
|
|
155
|
+
showSelected ? "text-white/80" : "text-content-presentation-global-tertiary",
|
|
161
156
|
)}
|
|
162
157
|
/>
|
|
163
158
|
</span>
|
|
@@ -228,9 +223,7 @@ export function TreeFolderRow({
|
|
|
228
223
|
<span
|
|
229
224
|
className={cn(
|
|
230
225
|
"shrink-0 w-4 h-4 flex items-center justify-center",
|
|
231
|
-
showSelected
|
|
232
|
-
? "text-white/90"
|
|
233
|
-
: "text-content-presentation-global-tertiary",
|
|
226
|
+
showSelected ? "text-white/90" : "text-content-presentation-global-tertiary",
|
|
234
227
|
)}
|
|
235
228
|
aria-hidden
|
|
236
229
|
>
|
|
@@ -245,9 +238,7 @@ export function TreeFolderRow({
|
|
|
245
238
|
<span
|
|
246
239
|
className={cn(
|
|
247
240
|
"shrink-0 text-xs tabular-nums",
|
|
248
|
-
showSelected
|
|
249
|
-
? "text-white/80"
|
|
250
|
-
: "text-content-presentation-global-tertiary",
|
|
241
|
+
showSelected ? "text-white/80" : "text-content-presentation-global-tertiary",
|
|
251
242
|
)}
|
|
252
243
|
>
|
|
253
244
|
({countDescendants(node)})
|
|
@@ -348,16 +339,14 @@ function TreeConnectors({
|
|
|
348
339
|
return <>{segments}</>;
|
|
349
340
|
}
|
|
350
341
|
|
|
351
|
-
function countDescendants(node: {
|
|
352
|
-
children?: { children?: any[] }[] | null;
|
|
353
|
-
}): number {
|
|
342
|
+
function countDescendants(node: { children?: TreeFolderNode[] | null }): number {
|
|
354
343
|
if (!node.children) return 0;
|
|
355
344
|
let n = 0;
|
|
356
|
-
const stack:
|
|
345
|
+
const stack: TreeFolderNode[] = [...node.children];
|
|
357
346
|
while (stack.length) {
|
|
358
347
|
n++;
|
|
359
348
|
const top = stack.pop();
|
|
360
|
-
if (top
|
|
349
|
+
if (top?.children) for (const c of top.children) stack.push(c);
|
|
361
350
|
}
|
|
362
351
|
return n;
|
|
363
352
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client"
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Component-scoped CSS for TreeFolder. Rendered once by TreeFolder itself so
|
|
@@ -47,7 +47,7 @@ const CSS = `
|
|
|
47
47
|
background: rgba(0, 0, 0, 0.35);
|
|
48
48
|
background-clip: content-box;
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
`;
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Renders a single <style> tag containing TreeFolder's scoped CSS.
|
|
@@ -56,5 +56,5 @@ const CSS = `
|
|
|
56
56
|
* keeps just one DOM node when it can.
|
|
57
57
|
*/
|
|
58
58
|
export function TreeFolderStyles() {
|
|
59
|
-
return <style id="torch-treefolder-styles" dangerouslySetInnerHTML={{ __html: CSS }}
|
|
59
|
+
return <style id="torch-treefolder-styles" dangerouslySetInnerHTML={{ __html: CSS }} />;
|
|
60
60
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client"
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
Folder,
|
|
@@ -14,14 +14,11 @@ import {
|
|
|
14
14
|
Link as LinkIcon,
|
|
15
15
|
Square,
|
|
16
16
|
LayoutGrid,
|
|
17
|
-
} from "lucide-react"
|
|
18
|
-
import type { ReactNode } from "react"
|
|
19
|
-
import type { TreeFolderIconResolver, TreeFolderNode } from "./types"
|
|
17
|
+
} from "lucide-react";
|
|
18
|
+
import type { ReactNode } from "react";
|
|
19
|
+
import type { TreeFolderIconResolver, TreeFolderNode } from "./types";
|
|
20
20
|
|
|
21
|
-
export const defaultIconRegistry: Record<
|
|
22
|
-
string,
|
|
23
|
-
(state: { isOpen: boolean }) => ReactNode
|
|
24
|
-
> = {
|
|
21
|
+
export const defaultIconRegistry: Record<string, (state: { isOpen: boolean }) => ReactNode> = {
|
|
25
22
|
folder: ({ isOpen }) =>
|
|
26
23
|
isOpen ? <FolderOpen className="w-3.5 h-3.5" /> : <Folder className="w-3.5 h-3.5" />,
|
|
27
24
|
file: () => <File className="w-3.5 h-3.5" />,
|
|
@@ -35,19 +32,19 @@ export const defaultIconRegistry: Record<
|
|
|
35
32
|
link: () => <LinkIcon className="w-3.5 h-3.5" />,
|
|
36
33
|
section: () => <LayoutGrid className="w-3.5 h-3.5" />,
|
|
37
34
|
container: () => <Square className="w-3.5 h-3.5" />,
|
|
38
|
-
}
|
|
35
|
+
};
|
|
39
36
|
|
|
40
37
|
export function defaultIconFor(
|
|
41
38
|
node: TreeFolderNode,
|
|
42
39
|
state: { isOpen: boolean; isInternal: boolean; isSelected: boolean },
|
|
43
40
|
): ReactNode {
|
|
44
|
-
if (node.icon !== undefined) return node.icon
|
|
45
|
-
const type = node.type ?? (state.isInternal ? "folder" : "file")
|
|
46
|
-
const resolver = defaultIconRegistry[type]
|
|
47
|
-
if (resolver) return resolver({ isOpen: state.isOpen })
|
|
41
|
+
if (node.icon !== undefined) return node.icon;
|
|
42
|
+
const type = node.type ?? (state.isInternal ? "folder" : "file");
|
|
43
|
+
const resolver = defaultIconRegistry[type];
|
|
44
|
+
if (resolver) return resolver({ isOpen: state.isOpen });
|
|
48
45
|
return state.isInternal
|
|
49
46
|
? defaultIconRegistry.folder({ isOpen: state.isOpen })
|
|
50
|
-
: defaultIconRegistry.file({ isOpen: state.isOpen })
|
|
47
|
+
: defaultIconRegistry.file({ isOpen: state.isOpen });
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
export function resolveIcon(
|
|
@@ -56,8 +53,8 @@ export function resolveIcon(
|
|
|
56
53
|
state: { isOpen: boolean; isInternal: boolean; isSelected: boolean },
|
|
57
54
|
): ReactNode {
|
|
58
55
|
if (iconFor) {
|
|
59
|
-
const custom = iconFor(node, state)
|
|
60
|
-
if (custom !== undefined && custom !== null) return custom
|
|
56
|
+
const custom = iconFor(node, state);
|
|
57
|
+
if (custom !== undefined && custom !== null) return custom;
|
|
61
58
|
}
|
|
62
|
-
return defaultIconFor(node, state)
|
|
59
|
+
return defaultIconFor(node, state);
|
|
63
60
|
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
export { TreeFolder } from "./TreeFolder"
|
|
2
|
-
export type { TreeFolderHandle, TreeFolderProps } from "./TreeFolder"
|
|
3
|
-
export { TreeFolderRow } from "./TreeFolderRow"
|
|
4
|
-
export type { TreeFolderRowProps, TreeFolderRowDragHandlers } from "./TreeFolderRow"
|
|
5
|
-
export { TreeFolderBreadcrumb } from "./TreeFolderBreadcrumb"
|
|
6
|
-
export { defaultIconRegistry, defaultIconFor } from "./icons"
|
|
7
|
-
export {
|
|
1
|
+
export { TreeFolder } from "./TreeFolder";
|
|
2
|
+
export type { TreeFolderHandle, TreeFolderProps } from "./TreeFolder";
|
|
3
|
+
export { TreeFolderRow } from "./TreeFolderRow";
|
|
4
|
+
export type { TreeFolderRowProps, TreeFolderRowDragHandlers } from "./TreeFolderRow";
|
|
5
|
+
export { TreeFolderBreadcrumb } from "./TreeFolderBreadcrumb";
|
|
6
|
+
export { defaultIconRegistry, defaultIconFor } from "./icons";
|
|
7
|
+
export {
|
|
8
|
+
applyMove,
|
|
9
|
+
findPath,
|
|
10
|
+
findNode,
|
|
11
|
+
isAncestor,
|
|
12
|
+
descendantIds,
|
|
13
|
+
toBreadcrumb,
|
|
14
|
+
} from "./treeFolderUtils";
|
|
8
15
|
export type {
|
|
9
16
|
TreeFolderNode,
|
|
10
17
|
TreeFolderNodeType,
|
|
@@ -14,4 +21,4 @@ export type {
|
|
|
14
21
|
TreeFolderDropPosition,
|
|
15
22
|
TreeFolderDropTarget,
|
|
16
23
|
TreeFolderBreadcrumb as TreeFolderBreadcrumbItems,
|
|
17
|
-
} from "./types"
|
|
24
|
+
} from "./types";
|