@enonic/ui 0.26.0 → 0.27.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.
Files changed (30) hide show
  1. package/dist/enonic-ui.cjs +1 -1
  2. package/dist/enonic-ui.es.js +104 -93
  3. package/dist/styles/preset.css +1 -1
  4. package/dist/styles/style.css +1 -1
  5. package/dist/styles/tokens.css +1 -1
  6. package/dist/styles/utilities.css +1 -1
  7. package/dist/types/components/icon-button/icon-button.d.ts +1 -1
  8. package/dist/types/components/index.d.ts +2 -0
  9. package/dist/types/components/skeleton/index.d.ts +1 -0
  10. package/dist/types/components/skeleton/skeleton.d.ts +26 -0
  11. package/dist/types/components/tree-list/index.d.ts +2 -1
  12. package/dist/types/components/tree-list/tree-list.d.ts +141 -106
  13. package/dist/types/components/virtualized-tree-list/index.d.ts +2 -0
  14. package/dist/types/components/virtualized-tree-list/virtualized-tree-list.d.ts +195 -0
  15. package/dist/types/hooks/index.d.ts +1 -0
  16. package/dist/types/hooks/use-item-registry.d.ts +5 -0
  17. package/dist/types/hooks/use-virtualized-keyboard-navigation.d.ts +81 -0
  18. package/dist/types/icons/circle-disc.d.ts +7 -0
  19. package/dist/types/icons/filled-circle-alert.d.ts +8 -0
  20. package/dist/types/icons/filled-circle-check.d.ts +8 -0
  21. package/dist/types/icons/filled-circle-info.d.ts +8 -0
  22. package/dist/types/icons/filled-circle-x.d.ts +8 -0
  23. package/dist/types/icons/filled-square-check.d.ts +8 -0
  24. package/dist/types/icons/filled-square-minus.d.ts +8 -0
  25. package/dist/types/icons/index.d.ts +7 -0
  26. package/dist/types/index.d.ts +1 -0
  27. package/dist/types/providers/index.d.ts +1 -0
  28. package/dist/types/providers/tree-list-provider.d.ts +30 -17
  29. package/dist/types/providers/virtualized-tree-list-provider.d.ts +26 -0
  30. package/package.json +11 -7
@@ -1,141 +1,176 @@
1
1
  import { ComponentPropsWithoutRef, ReactElement, ReactNode } from 'react';
2
2
  import { IconButtonProps } from '../icon-button';
3
+ import { SelectionMode } from '../../providers/tree-list-provider';
3
4
  import { LucideIcon } from '../../types';
4
- export declare const LOADING_SUFFIX = "__loading__";
5
- export declare const ROOT_PARENT_ID = "__root__";
6
- export type TreeData = {
7
- id: string;
8
- hasChildren: boolean;
9
- };
10
- export type TreeItems<TreeData> = {
11
- nodes: Record<string, TreeData | undefined>;
12
- children: Record<string, string[] | undefined>;
13
- hasMore: Record<string, boolean | undefined>;
14
- };
15
- export type FlatTreeNode<TData extends TreeData> = {
16
- id: string;
17
- data: TData;
18
- level: number;
19
- parentId: string | null;
20
- nodeType: 'node' | 'loading' | 'error';
21
- };
22
- export type TreeListProps<TData extends TreeData = TreeData> = {
23
- className?: string;
24
- fetchChildren: (parentId: string | undefined, offset: number) => Promise<{
25
- items: TData[];
26
- hasMore: boolean;
27
- }>;
28
- expanded?: ReadonlySet<string>;
29
- onExpandedChange?: (expanded: ReadonlySet<string>) => void;
5
+ export declare const treeListRowVariants: (props?: ({
6
+ active?: boolean | null | undefined;
7
+ selected?: boolean | null | undefined;
8
+ disabled?: boolean | null | undefined;
9
+ selectable?: boolean | null | undefined;
10
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
11
+ export type TreeListRootProps = {
30
12
  selection?: ReadonlySet<string>;
13
+ defaultSelection?: ReadonlySet<string>;
31
14
  onSelectionChange?: (selection: ReadonlySet<string>) => void;
32
- selectionMode?: 'single' | 'multiple';
33
- active?: string | null;
15
+ selectionMode?: SelectionMode;
16
+ active?: string;
34
17
  defaultActive?: string;
35
- setActive?: (active: string | null | undefined) => void;
36
- isItemSelectable?: (item: TData) => boolean;
37
- items?: TreeItems<TData>;
38
- onItemsChange?: (items: TreeItems<TData>) => void;
18
+ onActiveChange?: (active: string | undefined) => void;
19
+ loop?: boolean;
20
+ className?: string;
39
21
  children?: ReactNode;
22
+ onActivate?: (id: string) => void;
23
+ getParentId?: (id: string) => string | undefined;
24
+ getFirstChildId?: (id: string) => string | undefined;
25
+ expanded?: ReadonlySet<string>;
26
+ onExpandedChange?: (expanded: ReadonlySet<string>) => void;
40
27
  } & ComponentPropsWithoutRef<'div'>;
41
28
  export type TreeListContainerProps = {
42
29
  children?: ReactNode;
43
30
  className?: string;
44
31
  } & ComponentPropsWithoutRef<'div'>;
45
- export type DefaultTreeListLoadingRowViewProps<TData extends TreeData> = {
46
- item: FlatTreeNode<TData>;
47
- } & ComponentPropsWithoutRef<'div'>;
48
- export type TreeListLoadingRowProps<TData extends TreeData> = {
49
- item: FlatTreeNode<TData>;
50
- renderLoading?: (item: FlatTreeNode<TData>) => ReactNode;
51
- children?: ReactNode;
52
- intersectionProps?: IntersectionObserverInit;
53
- } & ComponentPropsWithoutRef<'div'>;
54
- export type TreeListErrorRowProps<TData extends TreeData> = {
55
- item: FlatTreeNode<TData>;
56
- renderError?: (item: FlatTreeNode<TData>) => ReactNode;
32
+ export type TreeListRowProps = {
33
+ id: string;
34
+ disabled?: boolean;
35
+ selectable?: boolean;
36
+ /** ARIA level for tree hierarchy (1-based, optional for accessibility) */
37
+ level?: number;
38
+ /** Whether this node has children (affects aria-expanded) */
39
+ hasChildren?: boolean;
40
+ /** Whether this node is expanded (required if hasChildren=true) */
41
+ expanded?: boolean;
42
+ /**
43
+ * Position of this item within its siblings (1-indexed).
44
+ * Used for `aria-posinset`. Optional - only set if you have this data.
45
+ */
46
+ posinset?: number;
47
+ /**
48
+ * Total number of siblings at this level.
49
+ * Used for `aria-setsize`. Optional - only set if you have this data.
50
+ */
51
+ setsize?: number;
57
52
  className?: string;
58
- onRetry?: () => void;
53
+ children?: ReactNode;
59
54
  } & ComponentPropsWithoutRef<'div'>;
60
- export type TreeListContentProps<TData extends TreeData> = {
61
- renderNode: (item: FlatTreeNode<TData>) => ReactNode;
62
- renderLoading?: (item: FlatTreeNode<TData>) => ReactNode;
63
- renderError?: (item: FlatTreeNode<TData>) => ReactNode;
64
- };
65
55
  export type TreeListRowLeftProps = {
66
56
  children?: ReactNode;
67
57
  className?: string;
68
58
  } & ComponentPropsWithoutRef<'div'>;
59
+ export declare const TreeListRowLeft: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowLeftProps> & {
60
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
61
+ }>;
69
62
  export type TreeListRowRightProps = {
70
63
  children?: ReactNode;
71
64
  className?: string;
72
65
  } & ComponentPropsWithoutRef<'div'>;
66
+ export declare const TreeListRowRight: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowRightProps> & {
67
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
68
+ }>;
69
+ export type TreeListRowContentProps = {
70
+ children?: ReactNode;
71
+ className?: string;
72
+ } & ComponentPropsWithoutRef<'div'>;
73
+ export declare const TreeListRowContent: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowContentProps> & {
74
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
75
+ }>;
76
+ export type TreeListActionProps = {
77
+ /** Interactive element to exclude from normal tab order (use F2 action mode) */
78
+ children: ReactElement;
79
+ };
80
+ /**
81
+ * Wrapper for interactive elements inside TreeList rows.
82
+ * Removes the element from normal tab order (tabIndex={-1}) so it's only
83
+ * accessible via F2 action mode.
84
+ */
85
+ export declare const TreeListAction: {
86
+ ({ children }: TreeListActionProps): ReactElement;
87
+ displayName: string;
88
+ };
73
89
  export type TreeListRowLevelSpacerProps = {
74
90
  level?: number;
75
91
  className?: string;
76
92
  } & ComponentPropsWithoutRef<'div'>;
77
- export type TreeListRowExpandControlProps<TData extends TreeData> = {
78
- data: FlatTreeNode<TData>;
93
+ export declare const TreeListRowLevelSpacer: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowLevelSpacerProps> & {
94
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
95
+ }>;
96
+ export type TreeListRowExpandControlProps = {
97
+ /** Row ID - if provided, clicking will also set this row as active */
98
+ rowId?: string;
99
+ expanded?: boolean;
100
+ hasChildren?: boolean;
101
+ onToggle?: () => void;
79
102
  icon?: LucideIcon;
80
- } & Omit<IconButtonProps, 'icon'>;
81
- export type TreeListRowContentProps = {
82
- children?: ReactNode;
103
+ selected?: boolean;
83
104
  className?: string;
84
- } & ComponentPropsWithoutRef<'div'>;
85
- export type TreeListRowSelectionControlProps<TData extends TreeData> = {
86
- data: FlatTreeNode<TData>;
105
+ } & Omit<IconButtonProps, 'icon' | 'onClick'>;
106
+ export declare const TreeListRowExpandControl: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowExpandControlProps> & {
107
+ ref?: import('preact').Ref<HTMLButtonElement> | undefined;
108
+ }>;
109
+ export type TreeListRowSelectionControlProps = {
110
+ /** Row ID - required for toggle selection to work */
111
+ rowId: string;
112
+ /** Override selection state. If not provided, reads from TreeList selection context. */
113
+ selected?: boolean;
114
+ selectable?: boolean;
87
115
  className?: string;
116
+ } & Omit<ComponentPropsWithoutRef<'div'>, 'onClick'>;
117
+ export declare const TreeListRowSelectionControl: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowSelectionControlProps> & {
118
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
119
+ }>;
120
+ export type TreeListRowLoadingProps = {
121
+ level?: number;
122
+ className?: string;
123
+ children?: ReactNode;
88
124
  } & ComponentPropsWithoutRef<'div'>;
89
- export type TreeListRowProps<TData extends TreeData> = {
90
- item: FlatTreeNode<TData>;
91
- children: ReactNode;
125
+ export declare const TreeListRowLoading: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowLoadingProps> & {
126
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
127
+ }>;
128
+ export type TreeListRowPlaceholderProps = {
129
+ level?: number;
92
130
  className?: string;
131
+ children?: ReactNode;
93
132
  } & ComponentPropsWithoutRef<'div'>;
94
- export declare const TreeList: (<TData extends TreeData = TreeData>({ className, fetchChildren, selection: controlledSelection, expanded: controlledExpanded, onSelectionChange, onExpandedChange, active: controlledActive, defaultActive, setActive, selectionMode, isItemSelectable, items: controlledItems, onItemsChange, children, ...props }: TreeListProps<TData>) => ReactElement) & {
95
- Root: <TData extends TreeData = TreeData>({ className, fetchChildren, selection: controlledSelection, expanded: controlledExpanded, onSelectionChange, onExpandedChange, active: controlledActive, defaultActive, setActive, selectionMode, isItemSelectable, items: controlledItems, onItemsChange, children, ...props }: TreeListProps<TData>) => ReactElement;
96
- Container: {
97
- ({ children, className, ...props }: TreeListContainerProps): ReactElement<TreeListContainerProps>;
98
- displayName: string;
99
- };
100
- Content: {
101
- <TData extends TreeData>({ renderNode, renderLoading, renderError, }: TreeListContentProps<TData>): ReactElement;
102
- displayName: string;
103
- };
104
- Row: {
105
- <TData extends TreeData>({ item, children, className, ...props }: TreeListRowProps<TData>): ReactElement;
106
- displayName: string;
107
- };
108
- LoadingRow: {
109
- <TData extends TreeData>({ item, renderLoading, className, children, intersectionProps, ...props }: TreeListLoadingRowProps<TData>): ReactElement;
110
- displayName: string;
111
- };
112
- DefaultLoadingRowView: <TData extends TreeData>({ item, className, children, ...props }: DefaultTreeListLoadingRowViewProps<TData>) => ReactElement;
113
- ErrorRow: {
114
- <TData extends TreeData>({ item, onRetry, renderError, className, ...props }: TreeListErrorRowProps<TData>): ReactElement;
115
- displayName: string;
116
- };
117
- RowLeft: {
118
- ({ children, className, ...props }: TreeListRowLeftProps): ReactElement<TreeListRowLeftProps>;
119
- displayName: string;
120
- };
121
- RowRight: {
122
- ({ children, className, ...props }: TreeListRowRightProps): ReactElement<TreeListRowRightProps>;
123
- displayName: string;
124
- };
125
- RowLevelSpacer: {
126
- ({ level, className, ...props }: TreeListRowLevelSpacerProps): ReactElement<TreeListRowLevelSpacerProps> | null;
127
- displayName: string;
128
- };
129
- RowExpandControl: {
130
- <TData extends TreeData>({ data, icon, className, ...props }: TreeListRowExpandControlProps<TData>): ReactElement<TreeListRowExpandControlProps<TData>>;
131
- displayName: string;
132
- };
133
- RowContent: {
134
- ({ className, children, ...props }: TreeListRowContentProps): ReactElement<TreeListRowContentProps>;
135
- displayName: string;
136
- };
137
- RowSelectionControl: {
138
- <TData extends TreeData>({ data, className, ...props }: TreeListRowSelectionControlProps<TData>): ReactElement;
133
+ export declare const TreeListRowPlaceholder: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowPlaceholderProps> & {
134
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
135
+ }>;
136
+ export declare const TreeList: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRootProps> & {
137
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
138
+ }> & {
139
+ Root: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRootProps> & {
140
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
141
+ }>;
142
+ Container: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListContainerProps> & {
143
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
144
+ }>;
145
+ Row: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowProps> & {
146
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
147
+ }>;
148
+ RowLeft: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowLeftProps> & {
149
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
150
+ }>;
151
+ RowRight: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowRightProps> & {
152
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
153
+ }>;
154
+ RowContent: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowContentProps> & {
155
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
156
+ }>;
157
+ RowLevelSpacer: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowLevelSpacerProps> & {
158
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
159
+ }>;
160
+ RowExpandControl: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowExpandControlProps> & {
161
+ ref?: import('preact').Ref<HTMLButtonElement> | undefined;
162
+ }>;
163
+ RowSelectionControl: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowSelectionControlProps> & {
164
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
165
+ }>;
166
+ RowLoading: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowLoadingProps> & {
167
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
168
+ }>;
169
+ RowPlaceholder: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowPlaceholderProps> & {
170
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
171
+ }>;
172
+ Action: {
173
+ ({ children }: TreeListActionProps): ReactElement;
139
174
  displayName: string;
140
175
  };
141
176
  };
@@ -0,0 +1,2 @@
1
+ export type { FlatNode, VirtualizedTreeListItemProps, VirtualizedTreeListRenderProps, VirtualizedTreeListRootProps, VirtualizedTreeListRowContentProps, VirtualizedTreeListRowExpandControlProps, VirtualizedTreeListRowLeftProps, VirtualizedTreeListRowLevelSpacerProps, VirtualizedTreeListRowLoadingProps, VirtualizedTreeListRowPlaceholderProps, VirtualizedTreeListRowProps, VirtualizedTreeListRowRightProps, VirtualizedTreeListRowSelectionControlProps, VirtuosoHandle, } from './virtualized-tree-list';
2
+ export { VirtualizedTreeList } from './virtualized-tree-list';
@@ -0,0 +1,195 @@
1
+ import { ComponentPropsWithoutRef, ReactElement, ReactNode, RefObject } from 'react';
2
+ import { IconButtonProps } from '../icon-button';
3
+ import { TreeListRowContentProps, TreeListRowLeftProps, TreeListRowLevelSpacerProps, TreeListRowLoadingProps, TreeListRowPlaceholderProps, TreeListRowRightProps } from '../tree-list/tree-list';
4
+ import { LucideIcon } from '../../types';
5
+ /**
6
+ * Flat node type for virtualized tree list.
7
+ * This represents a single node in a flattened tree structure.
8
+ */
9
+ export type FlatNode<TData = unknown> = {
10
+ /** Unique identifier for the node */
11
+ id: string;
12
+ /** User data associated with the node */
13
+ data: TData;
14
+ /** Nesting level (1 = root level) */
15
+ level: number;
16
+ /** Parent node ID, null for root nodes */
17
+ parentId: string | null;
18
+ /** Whether the node has children */
19
+ hasChildren: boolean;
20
+ /** Whether the node is currently expanded */
21
+ isExpanded: boolean;
22
+ /** Whether the node is in a loading state */
23
+ isLoading?: boolean;
24
+ };
25
+ /**
26
+ * Props returned by getItemProps for a row item.
27
+ */
28
+ export type VirtualizedTreeListItemProps = {
29
+ id: string;
30
+ 'data-index': number;
31
+ role: 'treeitem';
32
+ 'aria-selected': boolean | undefined;
33
+ 'aria-expanded': boolean | undefined;
34
+ 'aria-level': number;
35
+ onClick: (e: React.MouseEvent<HTMLElement>) => void;
36
+ active: boolean;
37
+ selected: boolean;
38
+ };
39
+ /**
40
+ * Props passed to the render function.
41
+ */
42
+ export type VirtualizedTreeListRenderProps<TData> = {
43
+ /** The flat list of nodes to render */
44
+ items: readonly FlatNode<TData>[];
45
+ /** Function to get props for each row item */
46
+ getItemProps: (index: number, node: FlatNode<TData>) => VirtualizedTreeListItemProps;
47
+ /** Current active item index */
48
+ activeIndex: number | null;
49
+ /** Props to spread on the Virtuoso container for keyboard navigation and ARIA */
50
+ containerProps: {
51
+ role: 'tree';
52
+ 'aria-label'?: string;
53
+ 'aria-activedescendant': string | undefined;
54
+ 'aria-multiselectable': boolean | undefined;
55
+ tabIndex: 0;
56
+ onKeyDown: (e: React.KeyboardEvent<HTMLElement>) => void;
57
+ onFocus: () => void;
58
+ onBlur: () => void;
59
+ };
60
+ };
61
+ /**
62
+ * Virtuoso handle type for scroll operations.
63
+ * This matches the VirtuosoHandle from react-virtuoso.
64
+ */
65
+ export type VirtuosoHandle = {
66
+ scrollToIndex: (location: number | {
67
+ index: number;
68
+ align?: 'start' | 'center' | 'end';
69
+ behavior?: 'auto' | 'smooth';
70
+ }) => void;
71
+ scrollIntoView?: (location: {
72
+ index: number;
73
+ align?: 'start' | 'center' | 'end';
74
+ behavior?: 'auto' | 'smooth';
75
+ }) => void;
76
+ };
77
+ export type VirtualizedTreeListRootProps<TData = unknown> = {
78
+ /** Flat list of tree nodes to render */
79
+ items: readonly FlatNode<TData>[];
80
+ /** Controlled selection state */
81
+ selection?: ReadonlySet<string>;
82
+ /** Default selection for uncontrolled mode */
83
+ defaultSelection?: ReadonlySet<string>;
84
+ /** Callback when selection changes */
85
+ onSelectionChange?: (selection: ReadonlySet<string>) => void;
86
+ /** Selection mode: 'single', 'multiple', or 'none' (navigation only) */
87
+ selectionMode?: 'single' | 'multiple' | 'none';
88
+ /** Controlled active item ID (null = no active item in controlled mode) */
89
+ active?: string | null;
90
+ /** Default active item ID for uncontrolled mode */
91
+ defaultActive?: string;
92
+ /** Callback when active item changes (null = no active item) */
93
+ onActiveChange?: (active: string | null) => void;
94
+ /** Callback when a node should be expanded */
95
+ onExpand?: (id: string) => void;
96
+ /** Callback when a node should be collapsed */
97
+ onCollapse?: (id: string) => void;
98
+ /** Callback when an item is activated (Enter key or double-click) */
99
+ onActivate?: (id: string) => void;
100
+ /** Ref to Virtuoso component for scroll operations */
101
+ virtuosoRef?: RefObject<VirtuosoHandle | null>;
102
+ /** Whether navigation should loop at start/end */
103
+ loop?: boolean;
104
+ /** Accessible label for the tree */
105
+ 'aria-label'?: string;
106
+ /** Render function that receives items and helper props */
107
+ children: (props: VirtualizedTreeListRenderProps<TData>) => ReactNode;
108
+ } & Omit<ComponentPropsWithoutRef<'div'>, 'children'>;
109
+ export type VirtualizedTreeListRowProps = {
110
+ /** Whether this row is the active (focused) row */
111
+ active?: boolean;
112
+ /** Whether this row is selected */
113
+ selected?: boolean;
114
+ /** Whether this row is disabled */
115
+ disabled?: boolean;
116
+ /** Whether this row is selectable */
117
+ selectable?: boolean;
118
+ /** Additional class names */
119
+ className?: string;
120
+ /** Row content */
121
+ children?: ReactNode;
122
+ } & ComponentPropsWithoutRef<'div'>;
123
+ export type VirtualizedTreeListActionProps = {
124
+ /** Interactive element to exclude from normal tab order (use F2 action mode) */
125
+ children: ReactElement;
126
+ };
127
+ /**
128
+ * Wrapper for interactive elements inside VirtualizedTreeList rows.
129
+ * Removes the element from normal tab order (tabIndex={-1}) so it's only
130
+ * accessible via F2 action mode.
131
+ */
132
+ export declare const VirtualizedTreeListAction: {
133
+ ({ children }: VirtualizedTreeListActionProps): ReactElement;
134
+ displayName: string;
135
+ };
136
+ export type VirtualizedTreeListRowExpandControlProps = {
137
+ /** Row ID - if provided, clicking will also set this row as active */
138
+ rowId?: string;
139
+ expanded?: boolean;
140
+ hasChildren?: boolean;
141
+ onToggle?: () => void;
142
+ icon?: LucideIcon;
143
+ selected?: boolean;
144
+ className?: string;
145
+ } & Omit<IconButtonProps, 'icon' | 'onClick'>;
146
+ export declare const VirtualizedTreeListRowExpandControl: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<VirtualizedTreeListRowExpandControlProps> & {
147
+ ref?: import('preact').Ref<HTMLButtonElement> | undefined;
148
+ }>;
149
+ export type VirtualizedTreeListRowSelectionControlProps = {
150
+ /** Row ID - required for toggle selection to work */
151
+ rowId: string;
152
+ /** Override selection state. If not provided, reads from VirtualizedTreeList selection context. */
153
+ selected?: boolean;
154
+ selectable?: boolean;
155
+ className?: string;
156
+ } & Omit<ComponentPropsWithoutRef<'div'>, 'onClick'>;
157
+ export declare const VirtualizedTreeListRowSelectionControl: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<VirtualizedTreeListRowSelectionControlProps> & {
158
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
159
+ }>;
160
+ export declare const VirtualizedTreeList: (<TData = unknown>(props: VirtualizedTreeListRootProps<TData> & {
161
+ ref?: React.ForwardedRef<HTMLDivElement>;
162
+ }) => ReactElement) & {
163
+ Row: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<VirtualizedTreeListRowProps> & {
164
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
165
+ }>;
166
+ RowLeft: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowLeftProps> & {
167
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
168
+ }>;
169
+ RowRight: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowRightProps> & {
170
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
171
+ }>;
172
+ RowContent: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowContentProps> & {
173
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
174
+ }>;
175
+ RowLevelSpacer: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowLevelSpacerProps> & {
176
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
177
+ }>;
178
+ RowExpandControl: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<VirtualizedTreeListRowExpandControlProps> & {
179
+ ref?: import('preact').Ref<HTMLButtonElement> | undefined;
180
+ }>;
181
+ RowSelectionControl: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<VirtualizedTreeListRowSelectionControlProps> & {
182
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
183
+ }>;
184
+ RowLoading: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowLoadingProps> & {
185
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
186
+ }>;
187
+ RowPlaceholder: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<TreeListRowPlaceholderProps> & {
188
+ ref?: import('preact').Ref<HTMLDivElement> | undefined;
189
+ }>;
190
+ Action: {
191
+ ({ children }: VirtualizedTreeListActionProps): ReactElement;
192
+ displayName: string;
193
+ };
194
+ };
195
+ export type { TreeListRowContentProps as VirtualizedTreeListRowContentProps, TreeListRowLeftProps as VirtualizedTreeListRowLeftProps, TreeListRowLevelSpacerProps as VirtualizedTreeListRowLevelSpacerProps, TreeListRowLoadingProps as VirtualizedTreeListRowLoadingProps, TreeListRowPlaceholderProps as VirtualizedTreeListRowPlaceholderProps, TreeListRowRightProps as VirtualizedTreeListRowRightProps, };
@@ -13,3 +13,4 @@ export { useScrollLock } from './use-scroll-lock';
13
13
  export { type UseSelectorKeyboardConfig, type UseSelectorKeyboardReturn, useSelectorKeyboard, } from './use-selector-keyboard';
14
14
  export { useSyncValue } from './use-sync-value';
15
15
  export { type UseTypeAheadConfig, type UseTypeAheadReturn, useTypeAhead } from './use-type-ahead';
16
+ export { type FlatNodeBase, type UseVirtualizedKeyboardNavigationReturn, useVirtualizedKeyboardNavigation, type VirtualizedKeyboardNavigationConfig, } from './use-virtualized-keyboard-navigation';
@@ -24,6 +24,11 @@ export type UseItemRegistryReturn = {
24
24
  * @returns True if the item is disabled
25
25
  */
26
26
  isItemDisabled: (id: string) => boolean;
27
+ /**
28
+ * Version counter that increments when items are registered or unregistered.
29
+ * Use as a dependency in useEffect to react to item changes.
30
+ */
31
+ registryVersion: number;
27
32
  };
28
33
  /**
29
34
  * Hook for managing a registry of items (menu items, listbox options, etc.).
@@ -0,0 +1,81 @@
1
+ export type FlatNodeBase = {
2
+ id: string;
3
+ level: number;
4
+ parentId: string | null;
5
+ hasChildren: boolean;
6
+ isExpanded: boolean;
7
+ };
8
+ export type VirtualizedKeyboardNavigationConfig<TNode extends FlatNodeBase> = {
9
+ /**
10
+ * Flat list of all visible tree nodes
11
+ */
12
+ items: readonly TNode[];
13
+ /**
14
+ * Currently active item index
15
+ */
16
+ activeIndex: number | null;
17
+ /**
18
+ * Set the active item index
19
+ */
20
+ setActiveIndex: (index: number | null) => void;
21
+ /**
22
+ * Scroll to index using virtuoso's scrollToIndex API
23
+ */
24
+ scrollToIndex: (index: number) => void;
25
+ /**
26
+ * Called when user requests expand (ArrowRight on collapsed node with children)
27
+ */
28
+ onExpand?: (id: string) => void;
29
+ /**
30
+ * Called when user requests collapse (ArrowLeft on expanded node)
31
+ */
32
+ onCollapse?: (id: string) => void;
33
+ /**
34
+ * Called when user requests selection (Enter/Space)
35
+ */
36
+ onSelect?: (id: string, index: number) => void;
37
+ /**
38
+ * Called when user presses Escape
39
+ */
40
+ onEscape?: () => void;
41
+ /**
42
+ * Whether to loop navigation at start/end
43
+ * @default false
44
+ */
45
+ loop?: boolean;
46
+ /**
47
+ * Check if an item is disabled
48
+ * @default () => false
49
+ */
50
+ isItemDisabled?: (node: TNode) => boolean;
51
+ /**
52
+ * Returns the number of items to move for PageUp/PageDown navigation.
53
+ * If not provided, defaults to 10.
54
+ */
55
+ getPageSize?: () => number;
56
+ };
57
+ export type UseVirtualizedKeyboardNavigationReturn = {
58
+ /**
59
+ * Move active item by delta (1 for next, -1 for previous)
60
+ */
61
+ moveActive: (delta: number) => void;
62
+ /**
63
+ * Keyboard event handler to attach to the container
64
+ */
65
+ handleKeyDown: (e: React.KeyboardEvent<HTMLElement>) => void;
66
+ };
67
+ /**
68
+ * Hook for keyboard navigation through a virtualized tree list.
69
+ * Works with array indices instead of DOM IDs since items may not be in DOM.
70
+ *
71
+ * Supports:
72
+ * - ArrowUp/ArrowDown for moving between items
73
+ * - ArrowRight for expand or move to first child
74
+ * - ArrowLeft for collapse or move to parent
75
+ * - Home/End keys for jumping to first/last
76
+ * - Enter/Space for selection
77
+ * - Escape key handling
78
+ * - Loop navigation (optional)
79
+ * - Disabled item skipping
80
+ */
81
+ export declare function useVirtualizedKeyboardNavigation<TNode extends FlatNodeBase>(config: VirtualizedKeyboardNavigationConfig<TNode>): UseVirtualizedKeyboardNavigationReturn;
@@ -0,0 +1,7 @@
1
+ import { LucideIcon } from 'lucide-react';
2
+ /**
3
+ * A circle with a disc inside.
4
+ */
5
+ export declare const CircleDisc: LucideIcon;
6
+ /** @alias CircleDisc */
7
+ export declare const CircleDiscIcon: LucideIcon;
@@ -0,0 +1,8 @@
1
+ import { LucideIcon } from 'lucide-react';
2
+ /**
3
+ * A filled circle with an alert sign inside.
4
+ * Useful for representing warning states.
5
+ */
6
+ export declare const FilledCircleAlert: LucideIcon;
7
+ /** @alias FilledCircleAlert */
8
+ export declare const FilledCircleAlertIcon: LucideIcon;
@@ -0,0 +1,8 @@
1
+ import { LucideIcon } from 'lucide-react';
2
+ /**
3
+ * A filled circle with a checkmark sign inside.
4
+ * Useful for representing success states.
5
+ */
6
+ export declare const FilledCircleCheck: LucideIcon;
7
+ /** @alias FilledCircleCheck */
8
+ export declare const FilledCircleCheckIcon: LucideIcon;
@@ -0,0 +1,8 @@
1
+ import { LucideIcon } from 'lucide-react';
2
+ /**
3
+ * A filled circle with an info sign inside.
4
+ * Useful for representing info states.
5
+ */
6
+ export declare const FilledCircleInfo: LucideIcon;
7
+ /** @alias FilledCircleInfo */
8
+ export declare const FilledCircleInfoIcon: LucideIcon;
@@ -0,0 +1,8 @@
1
+ import { LucideIcon } from 'lucide-react';
2
+ /**
3
+ * A filled circle with an X sign inside.
4
+ * Useful for representing error states.
5
+ */
6
+ export declare const FilledCircleX: LucideIcon;
7
+ /** @alias FilledCircleX */
8
+ export declare const FilledCircleXIcon: LucideIcon;
@@ -0,0 +1,8 @@
1
+ import { LucideIcon } from 'lucide-react';
2
+ /**
3
+ * A filled square with a checkmark inside.
4
+ * Useful for representing selected or checked states.
5
+ */
6
+ export declare const FilledSquareCheck: LucideIcon;
7
+ /** @alias FilledSquareCheck */
8
+ export declare const FilledSquareCheckIcon: LucideIcon;
@@ -0,0 +1,8 @@
1
+ import { LucideIcon } from 'lucide-react';
2
+ /**
3
+ * A filled square with a minus sign inside.
4
+ * Useful for representing indeterminate or partial selection states.
5
+ */
6
+ export declare const FilledSquareMinus: LucideIcon;
7
+ /** @alias FilledSquareMinus */
8
+ export declare const FilledSquareMinusIcon: LucideIcon;