@enonic/ui 0.23.1 → 0.25.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/enonic-ui.cjs +1 -1
- package/dist/enonic-ui.es.js +94 -81
- package/dist/styles/style.css +1 -1
- package/dist/types/components/checkbox/checkbox.d.ts +11 -1
- package/dist/types/components/context-menu/context-menu.d.ts +71 -0
- package/dist/types/components/context-menu/index.d.ts +2 -0
- package/dist/types/components/index.d.ts +2 -0
- package/dist/types/components/menu/menu.d.ts +13 -43
- package/dist/types/components/menubar/menubar.d.ts +3 -5
- package/dist/types/components/selector/index.d.ts +1 -0
- package/dist/types/components/selector/selector.d.ts +131 -0
- package/dist/types/components/tree-list/index.d.ts +1 -1
- package/dist/types/components/tree-list/tree-list.d.ts +68 -44
- package/dist/types/hooks/index.d.ts +4 -0
- package/dist/types/hooks/use-item-text-registry.d.ts +29 -0
- package/dist/types/hooks/use-pointer-position.d.ts +57 -0
- package/dist/types/hooks/use-selector-keyboard.d.ts +68 -0
- package/dist/types/hooks/use-type-ahead.d.ts +76 -0
- package/dist/types/primitives/menu-primitive/index.d.ts +1 -0
- package/dist/types/primitives/menu-primitive/menu-primitive.d.ts +93 -0
- package/dist/types/providers/context-menu-provider.d.ts +26 -0
- package/dist/types/providers/index.d.ts +2 -0
- package/dist/types/providers/menu-provider.d.ts +1 -2
- package/dist/types/providers/selector-provider.d.ts +33 -0
- package/dist/types/providers/tree-list-provider.d.ts +11 -9
- package/package.json +14 -14
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactElement, ReactNode } from 'react';
|
|
2
|
+
export type SelectorRootProps = {
|
|
3
|
+
children?: ReactNode;
|
|
4
|
+
value?: string;
|
|
5
|
+
defaultValue?: string;
|
|
6
|
+
onValueChange?: (value: string) => void;
|
|
7
|
+
open?: boolean;
|
|
8
|
+
defaultOpen?: boolean;
|
|
9
|
+
onOpenChange?: (open: boolean) => void;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
error?: boolean;
|
|
12
|
+
required?: boolean;
|
|
13
|
+
name?: string;
|
|
14
|
+
form?: string;
|
|
15
|
+
};
|
|
16
|
+
export type SelectorTriggerProps = {
|
|
17
|
+
className?: string;
|
|
18
|
+
children?: ReactNode;
|
|
19
|
+
} & Omit<ComponentPropsWithoutRef<'button'>, 'children'>;
|
|
20
|
+
export type SelectorValueProps = {
|
|
21
|
+
className?: string;
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Content to display for the selected value.
|
|
25
|
+
* Can be a render function `(value: string) => ReactNode` for dynamic display text,
|
|
26
|
+
* or a static ReactNode. If not provided, falls back to raw value.
|
|
27
|
+
*
|
|
28
|
+
* **Recommended**: Use a render function to display proper labels instead of raw values.
|
|
29
|
+
* This ensures the correct text is shown even before the dropdown is opened.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* // Render function (recommended)
|
|
34
|
+
* <Selector.Value placeholder="Select...">
|
|
35
|
+
* {(value) => items.find(i => i.value === value)?.label}
|
|
36
|
+
* </Selector.Value>
|
|
37
|
+
*
|
|
38
|
+
* // Falls back to raw value when no children provided
|
|
39
|
+
* <Selector.Value placeholder="Select..." />
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
children?: ReactNode | ((value: string) => ReactNode);
|
|
43
|
+
} & Omit<ComponentPropsWithoutRef<'span'>, 'children'>;
|
|
44
|
+
export type SelectorIconProps = {
|
|
45
|
+
className?: string;
|
|
46
|
+
children?: ReactNode;
|
|
47
|
+
} & ComponentPropsWithoutRef<'span'>;
|
|
48
|
+
export type SelectorContentProps = {
|
|
49
|
+
className?: string;
|
|
50
|
+
children?: ReactNode;
|
|
51
|
+
align?: 'start' | 'end';
|
|
52
|
+
onEscapeKeyDown?: (event: KeyboardEvent) => void;
|
|
53
|
+
onPointerDownOutside?: (event: PointerEvent) => void;
|
|
54
|
+
onInteractOutside?: (event: Event) => void;
|
|
55
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
56
|
+
export type SelectorViewportProps = {
|
|
57
|
+
className?: string;
|
|
58
|
+
children?: ReactNode;
|
|
59
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
60
|
+
export type SelectorItemProps = {
|
|
61
|
+
value: string;
|
|
62
|
+
disabled?: boolean;
|
|
63
|
+
textValue?: string;
|
|
64
|
+
className?: string;
|
|
65
|
+
children: ReactNode;
|
|
66
|
+
} & Omit<ComponentPropsWithoutRef<'div'>, 'children'>;
|
|
67
|
+
export type SelectorItemTextProps = {
|
|
68
|
+
className?: string;
|
|
69
|
+
children?: ReactNode;
|
|
70
|
+
} & ComponentPropsWithoutRef<'span'>;
|
|
71
|
+
export type SelectorItemIndicatorProps = {
|
|
72
|
+
className?: string;
|
|
73
|
+
children?: ReactNode;
|
|
74
|
+
} & ComponentPropsWithoutRef<'span'>;
|
|
75
|
+
export type SelectorGroupProps = {
|
|
76
|
+
className?: string;
|
|
77
|
+
children?: ReactNode;
|
|
78
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
79
|
+
export type SelectorLabelProps = {
|
|
80
|
+
className?: string;
|
|
81
|
+
children?: ReactNode;
|
|
82
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
83
|
+
export type SelectorSeparatorProps = {
|
|
84
|
+
className?: string;
|
|
85
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
86
|
+
export type SelectorHiddenSelectProps = ComponentPropsWithoutRef<'select'>;
|
|
87
|
+
export declare const Selector: {
|
|
88
|
+
({ children, value: controlledValue, defaultValue, onValueChange, open: controlledOpen, defaultOpen, onOpenChange, disabled, error, required, name, form, }: SelectorRootProps): ReactElement;
|
|
89
|
+
displayName: string;
|
|
90
|
+
} & {
|
|
91
|
+
Root: {
|
|
92
|
+
({ children, value: controlledValue, defaultValue, onValueChange, open: controlledOpen, defaultOpen, onOpenChange, disabled, error, required, name, form, }: SelectorRootProps): ReactElement;
|
|
93
|
+
displayName: string;
|
|
94
|
+
};
|
|
95
|
+
Trigger: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorTriggerProps> & {
|
|
96
|
+
ref?: import('preact').Ref<HTMLButtonElement> | undefined;
|
|
97
|
+
}>;
|
|
98
|
+
Value: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorValueProps> & {
|
|
99
|
+
ref?: import('preact').Ref<HTMLSpanElement> | undefined;
|
|
100
|
+
}>;
|
|
101
|
+
Icon: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorIconProps> & {
|
|
102
|
+
ref?: import('preact').Ref<HTMLSpanElement> | undefined;
|
|
103
|
+
}>;
|
|
104
|
+
Content: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorContentProps> & {
|
|
105
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
106
|
+
}>;
|
|
107
|
+
Viewport: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorViewportProps> & {
|
|
108
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
109
|
+
}>;
|
|
110
|
+
Item: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorItemProps> & {
|
|
111
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
112
|
+
}>;
|
|
113
|
+
ItemText: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorItemTextProps> & {
|
|
114
|
+
ref?: import('preact').Ref<HTMLSpanElement> | undefined;
|
|
115
|
+
}>;
|
|
116
|
+
ItemIndicator: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorItemIndicatorProps> & {
|
|
117
|
+
ref?: import('preact').Ref<HTMLSpanElement> | undefined;
|
|
118
|
+
}>;
|
|
119
|
+
Group: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorGroupProps> & {
|
|
120
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
121
|
+
}>;
|
|
122
|
+
Label: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorLabelProps> & {
|
|
123
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
124
|
+
}>;
|
|
125
|
+
Separator: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorSeparatorProps> & {
|
|
126
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
127
|
+
}>;
|
|
128
|
+
HiddenSelect: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<SelectorHiddenSelectProps> & {
|
|
129
|
+
ref?: import('preact').Ref<HTMLSelectElement> | undefined;
|
|
130
|
+
}>;
|
|
131
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { type DefaultTreeListLoadingRowViewProps, type FlatTreeNode, LOADING_SUFFIX, ROOT_PARENT_ID, type TreeData, type TreeItems, TreeList, type TreeListContainerProps, type TreeListContentProps, type TreeListErrorRowProps, type TreeListLoadingRowProps, type TreeListProps, type TreeListRowContentProps, type TreeListRowExpandControlProps, type TreeListRowLeftProps, type TreeListRowLevelSpacerProps, type TreeListRowProps, type TreeListRowRightProps, type TreeListRowSelectionControlProps, } from './tree-list';
|
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, ReactElement, ReactNode } from 'react';
|
|
2
2
|
import { IconButtonProps } from '../icon-button';
|
|
3
3
|
import { LucideIcon } from '../../types';
|
|
4
|
-
export
|
|
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> = {
|
|
5
23
|
className?: string;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
fetchChildren: (parentNode: T | undefined, offset: number) => Promise<{
|
|
10
|
-
items: T[];
|
|
11
|
-
total: number;
|
|
24
|
+
fetchChildren: (parentId: string | undefined, offset: number) => Promise<{
|
|
25
|
+
items: TData[];
|
|
26
|
+
hasMore: boolean;
|
|
12
27
|
}>;
|
|
13
28
|
expanded?: ReadonlySet<string>;
|
|
14
29
|
onExpandedChange?: (expanded: ReadonlySet<string>) => void;
|
|
@@ -18,75 +33,85 @@ export type TreeListProps<T extends TreeNode = TreeNode> = {
|
|
|
18
33
|
active?: string | null;
|
|
19
34
|
defaultActive?: string;
|
|
20
35
|
setActive?: (active: string | null | undefined) => void;
|
|
36
|
+
isItemSelectable?: (item: TData) => boolean;
|
|
37
|
+
items?: TreeItems<TData>;
|
|
38
|
+
onItemsChange?: (items: TreeItems<TData>) => void;
|
|
21
39
|
children?: ReactNode;
|
|
22
40
|
} & ComponentPropsWithoutRef<'div'>;
|
|
23
|
-
export type
|
|
41
|
+
export type TreeListContainerProps = {
|
|
24
42
|
children?: ReactNode;
|
|
25
|
-
|
|
43
|
+
className?: string;
|
|
44
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
45
|
+
export type DefaultTreeListLoadingRowViewProps<TData extends TreeData> = {
|
|
46
|
+
item: FlatTreeNode<TData>;
|
|
26
47
|
} & ComponentPropsWithoutRef<'div'>;
|
|
27
|
-
type
|
|
48
|
+
export type TreeListLoadingRowProps<TData extends TreeData> = {
|
|
49
|
+
item: FlatTreeNode<TData>;
|
|
50
|
+
renderLoading?: (item: FlatTreeNode<TData>) => ReactNode;
|
|
28
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;
|
|
29
57
|
className?: string;
|
|
58
|
+
onRetry?: () => void;
|
|
30
59
|
} & ComponentPropsWithoutRef<'div'>;
|
|
31
|
-
type
|
|
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
|
+
export type TreeListRowLeftProps = {
|
|
32
66
|
children?: ReactNode;
|
|
33
67
|
className?: string;
|
|
34
68
|
} & ComponentPropsWithoutRef<'div'>;
|
|
35
|
-
type TreeListRowRightProps = {
|
|
69
|
+
export type TreeListRowRightProps = {
|
|
36
70
|
children?: ReactNode;
|
|
37
71
|
className?: string;
|
|
38
72
|
} & ComponentPropsWithoutRef<'div'>;
|
|
39
|
-
type TreeListRowLevelSpacerProps = {
|
|
73
|
+
export type TreeListRowLevelSpacerProps = {
|
|
40
74
|
level?: number;
|
|
41
75
|
className?: string;
|
|
42
76
|
} & ComponentPropsWithoutRef<'div'>;
|
|
43
|
-
type TreeListRowExpandControlProps = {
|
|
44
|
-
data:
|
|
77
|
+
export type TreeListRowExpandControlProps<TData extends TreeData> = {
|
|
78
|
+
data: FlatTreeNode<TData>;
|
|
45
79
|
icon?: LucideIcon;
|
|
46
80
|
} & Omit<IconButtonProps, 'icon'>;
|
|
47
|
-
type TreeListRowContentProps = {
|
|
81
|
+
export type TreeListRowContentProps = {
|
|
48
82
|
children?: ReactNode;
|
|
49
83
|
className?: string;
|
|
50
84
|
} & ComponentPropsWithoutRef<'div'>;
|
|
51
|
-
type TreeListRowSelectionControlProps = {
|
|
52
|
-
data:
|
|
85
|
+
export type TreeListRowSelectionControlProps<TData extends TreeData> = {
|
|
86
|
+
data: FlatTreeNode<TData>;
|
|
53
87
|
className?: string;
|
|
54
88
|
} & ComponentPropsWithoutRef<'div'>;
|
|
55
|
-
type TreeListRowProps<
|
|
56
|
-
item:
|
|
89
|
+
export type TreeListRowProps<TData extends TreeData> = {
|
|
90
|
+
item: FlatTreeNode<TData>;
|
|
57
91
|
children: ReactNode;
|
|
58
92
|
className?: string;
|
|
59
93
|
} & ComponentPropsWithoutRef<'div'>;
|
|
60
|
-
export
|
|
61
|
-
|
|
62
|
-
children?: ReactNode;
|
|
63
|
-
intersectionProps?: IntersectionObserverInit;
|
|
64
|
-
} & ComponentPropsWithoutRef<'div'>;
|
|
65
|
-
export declare const TreeListRoot: <T extends TreeNode = TreeNode>({ className, items: controlledItems, setItems: setItemsControlled, fetchChildren, selection: controlledSelection, expanded: controlledExpanded, onSelectionChange, onExpandedChange, active: controlledActive, defaultActive, setActive, selectionMode, isItemSelectable, children, ...props }: TreeListProps<T>) => ReactElement;
|
|
66
|
-
export type TreeNode = {
|
|
67
|
-
id: string;
|
|
68
|
-
hasChildren?: boolean;
|
|
69
|
-
children?: TreeNode[];
|
|
70
|
-
hasMoreChildren?: boolean;
|
|
71
|
-
path: string[];
|
|
72
|
-
};
|
|
73
|
-
export declare function isLoadingPlaceholder(node: TreeNode): boolean;
|
|
74
|
-
export declare const TreeList: (<T extends TreeNode = TreeNode>({ className, items: controlledItems, setItems: setItemsControlled, fetchChildren, selection: controlledSelection, expanded: controlledExpanded, onSelectionChange, onExpandedChange, active: controlledActive, defaultActive, setActive, selectionMode, isItemSelectable, children, ...props }: TreeListProps<T>) => ReactElement) & {
|
|
75
|
-
Root: <T extends TreeNode = TreeNode>({ className, items: controlledItems, setItems: setItemsControlled, fetchChildren, selection: controlledSelection, expanded: controlledExpanded, onSelectionChange, onExpandedChange, active: controlledActive, defaultActive, setActive, selectionMode, isItemSelectable, children, ...props }: TreeListProps<T>) => ReactElement;
|
|
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;
|
|
76
96
|
Container: {
|
|
77
97
|
({ children, className, ...props }: TreeListContainerProps): ReactElement<TreeListContainerProps>;
|
|
78
98
|
displayName: string;
|
|
79
99
|
};
|
|
80
100
|
Content: {
|
|
81
|
-
({
|
|
101
|
+
<TData extends TreeData>({ renderNode, renderLoading, renderError, }: TreeListContentProps<TData>): ReactElement;
|
|
82
102
|
displayName: string;
|
|
83
103
|
};
|
|
84
104
|
Row: {
|
|
85
|
-
<
|
|
105
|
+
<TData extends TreeData>({ item, children, className, ...props }: TreeListRowProps<TData>): ReactElement;
|
|
86
106
|
displayName: string;
|
|
87
107
|
};
|
|
88
108
|
LoadingRow: {
|
|
89
|
-
({ item, children, intersectionProps, ...props }: TreeListLoadingRowProps): ReactElement;
|
|
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;
|
|
90
115
|
displayName: string;
|
|
91
116
|
};
|
|
92
117
|
RowLeft: {
|
|
@@ -94,15 +119,15 @@ export declare const TreeList: (<T extends TreeNode = TreeNode>({ className, ite
|
|
|
94
119
|
displayName: string;
|
|
95
120
|
};
|
|
96
121
|
RowRight: {
|
|
97
|
-
({ children, className, ...props }: TreeListRowRightProps): ReactElement<
|
|
122
|
+
({ children, className, ...props }: TreeListRowRightProps): ReactElement<TreeListRowRightProps>;
|
|
98
123
|
displayName: string;
|
|
99
124
|
};
|
|
100
125
|
RowLevelSpacer: {
|
|
101
|
-
({ level, className, ...props }: TreeListRowLevelSpacerProps): ReactElement<
|
|
126
|
+
({ level, className, ...props }: TreeListRowLevelSpacerProps): ReactElement<TreeListRowLevelSpacerProps> | null;
|
|
102
127
|
displayName: string;
|
|
103
128
|
};
|
|
104
129
|
RowExpandControl: {
|
|
105
|
-
({ data, icon, className, ...props }: TreeListRowExpandControlProps): ReactElement<TreeListRowExpandControlProps
|
|
130
|
+
<TData extends TreeData>({ data, icon, className, ...props }: TreeListRowExpandControlProps<TData>): ReactElement<TreeListRowExpandControlProps<TData>>;
|
|
106
131
|
displayName: string;
|
|
107
132
|
};
|
|
108
133
|
RowContent: {
|
|
@@ -110,8 +135,7 @@ export declare const TreeList: (<T extends TreeNode = TreeNode>({ className, ite
|
|
|
110
135
|
displayName: string;
|
|
111
136
|
};
|
|
112
137
|
RowSelectionControl: {
|
|
113
|
-
({ data, className, ...props }: TreeListRowSelectionControlProps): ReactElement;
|
|
138
|
+
<TData extends TreeData>({ data, className, ...props }: TreeListRowSelectionControlProps<TData>): ReactElement;
|
|
114
139
|
displayName: string;
|
|
115
140
|
};
|
|
116
141
|
};
|
|
117
|
-
export {};
|
|
@@ -4,8 +4,12 @@ export { useControlledState } from './use-controlled-state';
|
|
|
4
4
|
export { useControlledStateWithNull } from './use-controlled-state-with-null';
|
|
5
5
|
export { type FloatingPosition, type UseFloatingPositionConfig, useFloatingPosition } from './use-floating-position';
|
|
6
6
|
export { type ItemMetadata, type UseItemRegistryReturn, useItemRegistry } from './use-item-registry';
|
|
7
|
+
export { type UseItemTextRegistryReturn, useItemTextRegistry } from './use-item-text-registry';
|
|
7
8
|
export { type KeyboardNavigationConfig, type UseKeyboardNavigationReturn, useKeyboardNavigation, } from './use-keyboard-navigation';
|
|
9
|
+
export { type PointerPosition, type UsePointerPositionConfig, usePointerPosition } from './use-pointer-position';
|
|
8
10
|
export { type UseRovingTabIndexConfig, type UseRovingTabIndexReturn, useRovingTabIndex } from './use-roving-tabindex';
|
|
9
11
|
export { type UseScrollActiveIntoViewConfig, useScrollActiveIntoView } from './use-scroll-active-into-view';
|
|
10
12
|
export { useScrollLock } from './use-scroll-lock';
|
|
13
|
+
export { type UseSelectorKeyboardConfig, type UseSelectorKeyboardReturn, useSelectorKeyboard, } from './use-selector-keyboard';
|
|
11
14
|
export { useSyncValue } from './use-sync-value';
|
|
15
|
+
export { type UseTypeAheadConfig, type UseTypeAheadReturn, useTypeAhead } from './use-type-ahead';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type UseItemTextRegistryReturn = {
|
|
2
|
+
/**
|
|
3
|
+
* Register text content for an item (for type-ahead matching)
|
|
4
|
+
*/
|
|
5
|
+
registerItemText: (id: string, text: string) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Unregister text content for an item
|
|
8
|
+
*/
|
|
9
|
+
unregisterItemText: (id: string) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Get the text content for an item
|
|
12
|
+
*/
|
|
13
|
+
getItemText: (id: string) => string | undefined;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Hook for managing item text content registry.
|
|
17
|
+
* Used for type-ahead search functionality.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* const { registerItemText, getItemText } = useItemTextRegistry();
|
|
22
|
+
*
|
|
23
|
+
* // In item component:
|
|
24
|
+
* useEffect(() => {
|
|
25
|
+
* registerItemText(id, textContent);
|
|
26
|
+
* }, [id, textContent]);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function useItemTextRegistry(): UseItemTextRegistryReturn;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export type PointerPosition = {
|
|
3
|
+
top: number;
|
|
4
|
+
left: number;
|
|
5
|
+
};
|
|
6
|
+
export type UsePointerPositionConfig = {
|
|
7
|
+
/** Whether positioning is enabled/active */
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
/** Mouse/pointer position where the menu was triggered */
|
|
10
|
+
mousePosition: {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
} | null;
|
|
14
|
+
/** Reference to the floating content element */
|
|
15
|
+
contentRef: RefObject<HTMLElement> | null;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Calculates optimal position for floating content relative to pointer coordinates,
|
|
19
|
+
* with automatic viewport collision detection and flip behavior.
|
|
20
|
+
*
|
|
21
|
+
* This hook handles:
|
|
22
|
+
* - Positioning at pointer cursor location
|
|
23
|
+
* - Horizontal flipping when overflowing right edge
|
|
24
|
+
* - Vertical flipping when overflowing bottom edge
|
|
25
|
+
* - Automatic repositioning on window resize
|
|
26
|
+
*
|
|
27
|
+
* @param config - Configuration object for positioning behavior
|
|
28
|
+
* @returns Position object with top and left coordinates, or null if not yet calculated
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* function ContextMenu() {
|
|
33
|
+
* const contentRef = useRef<HTMLDivElement>(null);
|
|
34
|
+
* const [mousePosition, setMousePosition] = useState<{ x: number; y: number } | null>(null);
|
|
35
|
+
*
|
|
36
|
+
* const position = usePointerPosition({
|
|
37
|
+
* enabled: open,
|
|
38
|
+
* mousePosition,
|
|
39
|
+
* contentRef,
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* return (
|
|
43
|
+
* <div
|
|
44
|
+
* ref={contentRef}
|
|
45
|
+
* style={{
|
|
46
|
+
* position: 'fixed',
|
|
47
|
+
* top: position ? `${position.top}px` : '0',
|
|
48
|
+
* left: position ? `${position.left}px` : '0',
|
|
49
|
+
* }}
|
|
50
|
+
* >
|
|
51
|
+
* Context menu content
|
|
52
|
+
* </div>
|
|
53
|
+
* );
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function usePointerPosition({ enabled, mousePosition, contentRef, }: UsePointerPositionConfig): PointerPosition | null;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type UseSelectorKeyboardConfig = {
|
|
2
|
+
/**
|
|
3
|
+
* Get all item IDs in order
|
|
4
|
+
*/
|
|
5
|
+
getItems: () => string[];
|
|
6
|
+
/**
|
|
7
|
+
* Check if an item is disabled
|
|
8
|
+
*/
|
|
9
|
+
isItemDisabled: (id: string) => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Get the text content for an item (for type-ahead matching)
|
|
12
|
+
*/
|
|
13
|
+
getItemText: (id: string) => string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Currently active item ID
|
|
16
|
+
*/
|
|
17
|
+
active: string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Set the active item ID
|
|
20
|
+
*/
|
|
21
|
+
setActive: (id: string | undefined) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Currently selected value
|
|
24
|
+
*/
|
|
25
|
+
value: string | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Whether the dropdown is open
|
|
28
|
+
*/
|
|
29
|
+
open: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Set open state (internal, doesn't return focus)
|
|
32
|
+
*/
|
|
33
|
+
setOpenInternal: (open: boolean) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Set open state (with focus return handling)
|
|
36
|
+
*/
|
|
37
|
+
setOpen: (open: boolean) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Whether the selector is disabled
|
|
40
|
+
*/
|
|
41
|
+
disabled: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Called when an item is selected
|
|
44
|
+
*/
|
|
45
|
+
onSelect: (id: string) => void;
|
|
46
|
+
};
|
|
47
|
+
export type UseSelectorKeyboardReturn = {
|
|
48
|
+
/**
|
|
49
|
+
* Combined keyboard event handler
|
|
50
|
+
*/
|
|
51
|
+
keyHandler: (e: React.KeyboardEvent<HTMLElement>) => void;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Hook for Selector keyboard handling.
|
|
55
|
+
*
|
|
56
|
+
* Combines keyboard navigation, type-ahead, and selector-specific behaviors:
|
|
57
|
+
* - Arrow keys, Home/End for navigation
|
|
58
|
+
* - Enter/Space for selection
|
|
59
|
+
* - Escape to close
|
|
60
|
+
* - Tab to select and close
|
|
61
|
+
* - PageUp/PageDown for large jumps
|
|
62
|
+
* - Type-ahead search (single char cycling, multi-char search)
|
|
63
|
+
* - Opens dropdown on navigation keys when closed
|
|
64
|
+
*
|
|
65
|
+
* @param config - Configuration object
|
|
66
|
+
* @returns Object with keyHandler
|
|
67
|
+
*/
|
|
68
|
+
export declare function useSelectorKeyboard(config: UseSelectorKeyboardConfig): UseSelectorKeyboardReturn;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export type UseTypeAheadConfig = {
|
|
2
|
+
/**
|
|
3
|
+
* Get all item IDs in order
|
|
4
|
+
*/
|
|
5
|
+
getItems: () => string[];
|
|
6
|
+
/**
|
|
7
|
+
* Check if an item is disabled
|
|
8
|
+
*/
|
|
9
|
+
isItemDisabled: (id: string) => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Get the text content for an item (for matching)
|
|
12
|
+
*/
|
|
13
|
+
getItemText: (id: string) => string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Currently active item ID
|
|
16
|
+
*/
|
|
17
|
+
active: string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Set the active item ID
|
|
20
|
+
*/
|
|
21
|
+
setActive: (id: string | undefined) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Called when a match is found
|
|
24
|
+
*/
|
|
25
|
+
onMatch?: (id: string) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Timeout in ms before search string resets
|
|
28
|
+
* @default 500
|
|
29
|
+
*/
|
|
30
|
+
timeout?: number;
|
|
31
|
+
};
|
|
32
|
+
export type UseTypeAheadReturn = {
|
|
33
|
+
/**
|
|
34
|
+
* Handle a typed character for type-ahead search
|
|
35
|
+
*/
|
|
36
|
+
handleTypeAhead: (char: string) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Reset the search string manually
|
|
39
|
+
*/
|
|
40
|
+
resetSearch: () => void;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Hook for type-ahead search in a list of items.
|
|
44
|
+
*
|
|
45
|
+
* Behavior:
|
|
46
|
+
* - Single character: cycles through items starting with that character
|
|
47
|
+
* - Multiple characters typed quickly: finds first match for full string
|
|
48
|
+
* - Case-insensitive matching
|
|
49
|
+
* - Skips disabled items
|
|
50
|
+
* - Resets after timeout (default 500ms)
|
|
51
|
+
*
|
|
52
|
+
* **Important**: The `getItemText` function must return the searchable text for each item.
|
|
53
|
+
* When using complex children (e.g., `<ItemText>{label}</ItemText>`), you must either:
|
|
54
|
+
* 1. Provide a `textValue` prop to register searchable text explicitly
|
|
55
|
+
* 2. Extract text from DOM after mount using `element.textContent`
|
|
56
|
+
*
|
|
57
|
+
* Plain string children work automatically, but wrapped content requires explicit registration.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* const { handleTypeAhead } = useTypeAhead({
|
|
62
|
+
* getItems,
|
|
63
|
+
* isItemDisabled,
|
|
64
|
+
* getItemText,
|
|
65
|
+
* active,
|
|
66
|
+
* setActive,
|
|
67
|
+
* onMatch: (id) => console.log('Found:', id),
|
|
68
|
+
* });
|
|
69
|
+
*
|
|
70
|
+
* // In keyboard handler:
|
|
71
|
+
* if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
72
|
+
* handleTypeAhead(e.key);
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function useTypeAhead(config: UseTypeAheadConfig): UseTypeAheadReturn;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type MenuItemOwnProps, MenuPrimitiveItem, MenuPrimitiveItemIndicator, type MenuPrimitiveItemIndicatorProps, type MenuPrimitiveItemProps, MenuPrimitiveLabel, type MenuPrimitiveLabelProps, MenuPrimitiveRadioGroup, type MenuPrimitiveRadioGroupProps, MenuPrimitiveRadioItem, type MenuPrimitiveRadioItemProps, MenuPrimitiveSeparator, type MenuPrimitiveSeparatorProps, type MenuRadioGroupOwnProps, type MenuRadioItemOwnProps, menuItemVariants, menuRadioItemVariants, useRadioGroup, } from './menu-primitive';
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
|
+
export type MenuContextOperations = {
|
|
3
|
+
active: string | undefined;
|
|
4
|
+
setActive: (id: string | undefined) => void;
|
|
5
|
+
setOpen: (open: boolean) => void;
|
|
6
|
+
registerItem: (id: string, disabled?: boolean) => void;
|
|
7
|
+
unregisterItem: (id: string) => void;
|
|
8
|
+
getItems: () => string[];
|
|
9
|
+
isItemDisabled: (id: string) => boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare const menuItemVariants: (props?: ({
|
|
12
|
+
active?: boolean | null | undefined;
|
|
13
|
+
disabled?: boolean | null | undefined;
|
|
14
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
15
|
+
/** Public API props for menu items (without context operations) */
|
|
16
|
+
export type MenuItemOwnProps = {
|
|
17
|
+
id?: string;
|
|
18
|
+
asChild?: boolean;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
onSelect?: (event: Event) => void;
|
|
21
|
+
className?: string;
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
24
|
+
/** Internal primitive props (own props + context operations for dependency injection) */
|
|
25
|
+
export type MenuPrimitiveItemProps = MenuItemOwnProps & MenuContextOperations;
|
|
26
|
+
export declare const MenuPrimitiveItem: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<MenuPrimitiveItemProps> & {
|
|
27
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
28
|
+
}>;
|
|
29
|
+
export type MenuPrimitiveLabelProps = {
|
|
30
|
+
className?: string;
|
|
31
|
+
children: ReactNode;
|
|
32
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
33
|
+
export declare const MenuPrimitiveLabel: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<MenuPrimitiveLabelProps> & {
|
|
34
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
35
|
+
}>;
|
|
36
|
+
export type MenuPrimitiveSeparatorProps = {
|
|
37
|
+
className?: string;
|
|
38
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
39
|
+
export declare const MenuPrimitiveSeparator: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<MenuPrimitiveSeparatorProps> & {
|
|
40
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
41
|
+
}>;
|
|
42
|
+
type RadioGroupContextValue = {
|
|
43
|
+
value: string | undefined;
|
|
44
|
+
setValue: (value: string) => void;
|
|
45
|
+
closeOnSelect: boolean;
|
|
46
|
+
setOpen: (open: boolean) => void;
|
|
47
|
+
};
|
|
48
|
+
export declare const useRadioGroup: () => RadioGroupContextValue;
|
|
49
|
+
/** Public API props for radio groups (without setOpen) */
|
|
50
|
+
export type MenuRadioGroupOwnProps = {
|
|
51
|
+
value?: string;
|
|
52
|
+
defaultValue?: string;
|
|
53
|
+
onValueChange?: (value: string) => void;
|
|
54
|
+
closeOnSelect?: boolean;
|
|
55
|
+
className?: string;
|
|
56
|
+
children?: ReactNode;
|
|
57
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
58
|
+
/** Internal primitive props (own props + setOpen for dependency injection) */
|
|
59
|
+
export type MenuPrimitiveRadioGroupProps = MenuRadioGroupOwnProps & {
|
|
60
|
+
setOpen: (open: boolean) => void;
|
|
61
|
+
};
|
|
62
|
+
export declare const MenuPrimitiveRadioGroup: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<MenuPrimitiveRadioGroupProps> & {
|
|
63
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
64
|
+
}>;
|
|
65
|
+
export declare const menuRadioItemVariants: (props?: ({
|
|
66
|
+
active?: boolean | null | undefined;
|
|
67
|
+
disabled?: boolean | null | undefined;
|
|
68
|
+
checked?: boolean | null | undefined;
|
|
69
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
70
|
+
/** Public API props for radio items (without context operations) */
|
|
71
|
+
export type MenuRadioItemOwnProps = {
|
|
72
|
+
id?: string;
|
|
73
|
+
value: string;
|
|
74
|
+
asChild?: boolean;
|
|
75
|
+
disabled?: boolean;
|
|
76
|
+
onSelect?: (event: Event) => void;
|
|
77
|
+
className?: string;
|
|
78
|
+
children: ReactNode;
|
|
79
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
80
|
+
/** Internal primitive props (own props + context operations except setOpen, which comes from RadioGroup) */
|
|
81
|
+
export type MenuPrimitiveRadioItemProps = MenuRadioItemOwnProps & Omit<MenuContextOperations, 'setOpen'>;
|
|
82
|
+
export declare const MenuPrimitiveRadioItem: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<MenuPrimitiveRadioItemProps> & {
|
|
83
|
+
ref?: import('preact').Ref<HTMLDivElement> | undefined;
|
|
84
|
+
}>;
|
|
85
|
+
export type MenuPrimitiveItemIndicatorProps = {
|
|
86
|
+
forceMount?: boolean;
|
|
87
|
+
className?: string;
|
|
88
|
+
children?: ReactNode;
|
|
89
|
+
} & ComponentPropsWithoutRef<'span'>;
|
|
90
|
+
export declare const MenuPrimitiveItemIndicator: import('preact').FunctionalComponent<import('preact/compat').PropsWithoutRef<MenuPrimitiveItemIndicatorProps> & {
|
|
91
|
+
ref?: import('preact').Ref<HTMLSpanElement> | undefined;
|
|
92
|
+
}>;
|
|
93
|
+
export {};
|