@proyecto-viviana/solidaria-components 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +39 -272
- package/dist/ActionBar.d.ts +79 -0
- package/dist/ActionBar.d.ts.map +1 -0
- package/dist/ActionGroup.d.ts +74 -0
- package/dist/ActionGroup.d.ts.map +1 -0
- package/dist/Alert.d.ts +70 -0
- package/dist/Alert.d.ts.map +1 -0
- package/dist/Autocomplete.d.ts +5 -5
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Breadcrumbs.d.ts +27 -8
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +28 -5
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +51 -7
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +33 -8
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +130 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/Color.d.ts +210 -9
- package/dist/Color.d.ts.map +1 -1
- package/dist/ColorEditor.d.ts +42 -0
- package/dist/ColorEditor.d.ts.map +1 -0
- package/dist/ComboBox.d.ts +146 -16
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ContextualHelpTrigger.d.ts +40 -0
- package/dist/ContextualHelpTrigger.d.ts.map +1 -0
- package/dist/DateField.d.ts +35 -8
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +101 -5
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DateRangePickerContext.d.ts +30 -0
- package/dist/DateRangePickerContext.d.ts.map +1 -0
- package/dist/Dialog.d.ts +5 -5
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Disclosure.d.ts +25 -5
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/DragAndDrop.d.ts +80 -0
- package/dist/DragAndDrop.d.ts.map +1 -0
- package/dist/DragPreview.d.ts +14 -0
- package/dist/DragPreview.d.ts.map +1 -0
- package/dist/DropZone.d.ts +27 -0
- package/dist/DropZone.d.ts.map +1 -0
- package/dist/FieldError.d.ts +27 -0
- package/dist/FieldError.d.ts.map +1 -0
- package/dist/FileTrigger.d.ts +26 -0
- package/dist/FileTrigger.d.ts.map +1 -0
- package/dist/Focusable.d.ts +27 -0
- package/dist/Focusable.d.ts.map +1 -0
- package/dist/Form.d.ts +41 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/GridList.d.ts +69 -10
- package/dist/GridList.d.ts.map +1 -1
- package/dist/HiddenDateInput.d.ts +26 -0
- package/dist/HiddenDateInput.d.ts.map +1 -0
- package/dist/HiddenTimeInput.d.ts +25 -0
- package/dist/HiddenTimeInput.d.ts.map +1 -0
- package/dist/Icon.d.ts +57 -0
- package/dist/Icon.d.ts.map +1 -0
- package/dist/Keyboard.d.ts +13 -0
- package/dist/Keyboard.d.ts.map +1 -0
- package/dist/Landmark.d.ts +3 -3
- package/dist/Landmark.d.ts.map +1 -1
- package/dist/Link.d.ts +10 -4
- package/dist/Link.d.ts.map +1 -1
- package/dist/ListBox.d.ts +73 -11
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListDropTargetDelegate.d.ts +38 -0
- package/dist/ListDropTargetDelegate.d.ts.map +1 -0
- package/dist/Menu.d.ts +79 -10
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +4 -4
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +6 -4
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +10 -12
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +32 -7
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Pressable.d.ts +27 -0
- package/dist/Pressable.d.ts.map +1 -0
- package/dist/ProgressBar.d.ts +6 -4
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/RadioGroup.d.ts +43 -9
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RangeCalendar.d.ts +39 -7
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RouterProvider.d.ts +75 -0
- package/dist/RouterProvider.d.ts.map +1 -0
- package/dist/SearchField.d.ts +23 -21
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +48 -7
- package/dist/Select.d.ts.map +1 -1
- package/dist/SelectionIndicator.d.ts +30 -0
- package/dist/SelectionIndicator.d.ts.map +1 -0
- package/dist/Separator.d.ts +9 -3
- package/dist/Separator.d.ts.map +1 -1
- package/dist/SharedElementTransition.d.ts +41 -0
- package/dist/SharedElementTransition.d.ts.map +1 -0
- package/dist/Slider.d.ts +15 -8
- package/dist/Slider.d.ts.map +1 -1
- package/dist/StepList.d.ts +90 -0
- package/dist/StepList.d.ts.map +1 -0
- package/dist/Switch.d.ts +11 -5
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Table.d.ts +222 -19
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +47 -10
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +22 -10
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/Text.d.ts +10 -0
- package/dist/Text.d.ts.map +1 -0
- package/dist/TextField.d.ts +19 -11
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +32 -7
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/Toast.d.ts +29 -14
- package/dist/Toast.d.ts.map +1 -1
- package/dist/ToggleButton.d.ts +36 -0
- package/dist/ToggleButton.d.ts.map +1 -0
- package/dist/ToggleButtonGroup.d.ts +33 -0
- package/dist/ToggleButtonGroup.d.ts.map +1 -0
- package/dist/Toolbar.d.ts +7 -3
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +58 -7
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +102 -11
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Virtualizer.d.ts +61 -0
- package/dist/Virtualizer.d.ts.map +1 -0
- package/dist/VirtualizerLayouts.d.ts +82 -0
- package/dist/VirtualizerLayouts.d.ts.map +1 -0
- package/dist/VisuallyHidden.d.ts +4 -2
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +6 -1
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +73 -39
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23342 -10644
- package/dist/index.js.map +1 -7
- package/dist/index.jsx +18110 -0
- package/dist/index.jsx.map +1 -0
- package/dist/useDragAndDrop.d.ts +93 -0
- package/dist/useDragAndDrop.d.ts.map +1 -0
- package/dist/utils.d.ts +8 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/virtualizer/Layout.d.ts +79 -0
- package/dist/virtualizer/Layout.d.ts.map +1 -0
- package/package.json +33 -32
- package/src/ActionBar.tsx +251 -0
- package/src/ActionGroup.tsx +277 -0
- package/src/Alert.tsx +152 -0
- package/src/Autocomplete.tsx +39 -44
- package/src/Breadcrumbs.tsx +227 -72
- package/src/Button.tsx +315 -74
- package/src/Calendar.tsx +347 -141
- package/src/Checkbox.tsx +414 -123
- package/src/Collection.tsx +350 -0
- package/src/Color.tsx +1325 -284
- package/src/ColorEditor.tsx +213 -0
- package/src/ComboBox.tsx +644 -245
- package/src/ContextualHelpTrigger.tsx +195 -0
- package/src/DateField.tsx +274 -106
- package/src/DatePicker.tsx +892 -111
- package/src/DateRangePickerContext.tsx +44 -0
- package/src/Dialog.tsx +173 -104
- package/src/Disclosure.tsx +158 -105
- package/src/DragAndDrop.tsx +340 -0
- package/src/DragPreview.tsx +47 -0
- package/src/DropZone.tsx +233 -0
- package/src/FieldError.tsx +89 -0
- package/src/FileTrigger.tsx +83 -0
- package/src/Focusable.tsx +103 -0
- package/src/Form.tsx +140 -0
- package/src/GridList.tsx +542 -128
- package/src/HiddenDateInput.tsx +153 -0
- package/src/HiddenTimeInput.tsx +133 -0
- package/src/Icon.tsx +133 -0
- package/src/Keyboard.tsx +26 -0
- package/src/Landmark.tsx +37 -63
- package/src/Link.tsx +132 -69
- package/src/ListBox.tsx +656 -106
- package/src/ListDropTargetDelegate.ts +283 -0
- package/src/Menu.tsx +1234 -132
- package/src/Meter.tsx +44 -58
- package/src/Modal.tsx +262 -166
- package/src/NumberField.tsx +267 -151
- package/src/Popover.tsx +452 -343
- package/src/Pressable.tsx +108 -0
- package/src/ProgressBar.tsx +54 -59
- package/src/RadioGroup.tsx +533 -121
- package/src/RangeCalendar.tsx +249 -150
- package/src/RouterProvider.tsx +223 -0
- package/src/SearchField.tsx +460 -133
- package/src/Select.tsx +804 -233
- package/src/SelectionIndicator.tsx +108 -0
- package/src/Separator.tsx +47 -49
- package/src/SharedElementTransition.tsx +264 -0
- package/src/Slider.tsx +148 -98
- package/src/StepList.tsx +272 -0
- package/src/Switch.tsx +93 -46
- package/src/Table.tsx +1551 -225
- package/src/Tabs.tsx +377 -123
- package/src/TagGroup.tsx +233 -135
- package/src/Text.tsx +18 -0
- package/src/TextField.tsx +413 -86
- package/src/TimeField.tsx +232 -222
- package/src/Toast.tsx +306 -160
- package/src/ToggleButton.tsx +169 -0
- package/src/ToggleButtonGroup.tsx +141 -0
- package/src/Toolbar.tsx +61 -70
- package/src/Tooltip.tsx +473 -116
- package/src/Tree.tsx +1514 -175
- package/src/Virtualizer.tsx +730 -0
- package/src/VirtualizerLayouts.ts +280 -0
- package/src/VisuallyHidden.tsx +32 -38
- package/src/contexts.ts +29 -36
- package/src/index.ts +972 -620
- package/src/useDragAndDrop.ts +367 -0
- package/src/utils.tsx +69 -50
- package/src/virtualizer/Layout.ts +192 -0
- package/dist/index.ssr.js +0 -9785
- package/dist/index.ssr.js.map +0 -7
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drag and drop compatibility hook for collection components.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors RAC's `useDragAndDrop` shape while delegating to Solid
|
|
5
|
+
* state and aria primitives.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Accessor, JSX } from "solid-js";
|
|
9
|
+
import { DragPreview } from "./DragPreview";
|
|
10
|
+
import { ListDropTargetDelegate } from "./ListDropTargetDelegate";
|
|
11
|
+
import {
|
|
12
|
+
createDraggableCollection,
|
|
13
|
+
createDraggableItem,
|
|
14
|
+
createDroppableCollection,
|
|
15
|
+
createDroppableItem,
|
|
16
|
+
getGlobalDraggingCollectionRef,
|
|
17
|
+
getGlobalDraggingKeys,
|
|
18
|
+
type DraggableCollectionOptions,
|
|
19
|
+
type DraggableCollectionAria,
|
|
20
|
+
type DraggableItemOptions,
|
|
21
|
+
type DraggableItemAria,
|
|
22
|
+
type DroppableCollectionOptions,
|
|
23
|
+
type DroppableCollectionAria,
|
|
24
|
+
type DroppableItemOptions,
|
|
25
|
+
type DroppableItemAria,
|
|
26
|
+
type DropTargetDelegate as AriaDropTargetDelegate,
|
|
27
|
+
} from "@proyecto-viviana/solidaria";
|
|
28
|
+
import {
|
|
29
|
+
createDraggableCollectionState,
|
|
30
|
+
createDroppableCollectionState,
|
|
31
|
+
type DragItem,
|
|
32
|
+
type DragPreviewRenderer,
|
|
33
|
+
type DraggableCollectionProps,
|
|
34
|
+
type DraggableCollectionState,
|
|
35
|
+
type DraggableCollectionStateOptions,
|
|
36
|
+
type DropTarget,
|
|
37
|
+
type DroppableCollectionProps,
|
|
38
|
+
type DroppableCollectionState,
|
|
39
|
+
type DroppableCollectionStateOptions,
|
|
40
|
+
} from "@proyecto-viviana/solid-stately";
|
|
41
|
+
|
|
42
|
+
interface DraggableCollectionStateOpts<T = object> extends Omit<
|
|
43
|
+
DraggableCollectionStateOptions<T>,
|
|
44
|
+
"getItems"
|
|
45
|
+
> {
|
|
46
|
+
items?: T[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface DragHooks<T = object> {
|
|
50
|
+
useDraggableCollectionState?: (
|
|
51
|
+
props: DraggableCollectionStateOpts<T>,
|
|
52
|
+
) => DraggableCollectionState;
|
|
53
|
+
useDraggableCollection?: (
|
|
54
|
+
props: Omit<DraggableCollectionOptions, "ref">,
|
|
55
|
+
state: DraggableCollectionState,
|
|
56
|
+
ref: Accessor<HTMLElement | null>,
|
|
57
|
+
) => DraggableCollectionAria;
|
|
58
|
+
useDraggableItem?: (
|
|
59
|
+
props: DraggableItemOptions,
|
|
60
|
+
state: DraggableCollectionState,
|
|
61
|
+
) => DraggableItemAria;
|
|
62
|
+
DragPreview?: typeof DragPreview;
|
|
63
|
+
renderDragPreview?: DragAndDropOptions<T>["renderDragPreview"];
|
|
64
|
+
isVirtualDragging?: () => boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface DropHooks {
|
|
68
|
+
useDroppableCollectionState?: (
|
|
69
|
+
props: DroppableCollectionStateOptions,
|
|
70
|
+
) => DroppableCollectionState;
|
|
71
|
+
useDroppableCollection?: (
|
|
72
|
+
props: Omit<DroppableCollectionOptions, "ref">,
|
|
73
|
+
state: DroppableCollectionState,
|
|
74
|
+
ref: Accessor<HTMLElement | null>,
|
|
75
|
+
) => DroppableCollectionAria;
|
|
76
|
+
useDroppableItem?: (
|
|
77
|
+
options: Omit<DroppableItemOptions, "ref">,
|
|
78
|
+
state: DroppableCollectionState,
|
|
79
|
+
ref: Accessor<HTMLElement | null>,
|
|
80
|
+
) => DroppableItemAria;
|
|
81
|
+
useDropIndicator?: (
|
|
82
|
+
props: { target: DropTarget },
|
|
83
|
+
state: DroppableCollectionState,
|
|
84
|
+
ref: Accessor<HTMLElement | null>,
|
|
85
|
+
) => {
|
|
86
|
+
dropIndicatorProps: JSX.HTMLAttributes<HTMLElement>;
|
|
87
|
+
isDropTarget: boolean;
|
|
88
|
+
isHidden: boolean;
|
|
89
|
+
};
|
|
90
|
+
renderDropIndicator?: (target: DropTarget) => JSX.Element;
|
|
91
|
+
dropTargetDelegate?: AriaDropTargetDelegate;
|
|
92
|
+
ListDropTargetDelegate?: typeof ListDropTargetDelegate;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type DragAndDropHooks<T = object> = DragHooks<T> & DropHooks;
|
|
96
|
+
|
|
97
|
+
export interface DragAndDrop<T = object> {
|
|
98
|
+
/** Drag and drop hooks for the collection element. */
|
|
99
|
+
dragAndDropHooks: DragAndDropHooks<T>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface DragAndDropOptions<T = object>
|
|
103
|
+
extends Partial<Omit<DraggableCollectionProps<T>, "preview">>, Partial<DroppableCollectionProps> {
|
|
104
|
+
/**
|
|
105
|
+
* Optional keyboard delegate forwarded to the collection droppable hook.
|
|
106
|
+
*/
|
|
107
|
+
keyboardDelegate?: DroppableCollectionOptions["keyboardDelegate"];
|
|
108
|
+
/**
|
|
109
|
+
* Optional keydown handler composed with collection droppable keyboard behavior.
|
|
110
|
+
*/
|
|
111
|
+
onKeyDown?: DroppableCollectionOptions["onKeyDown"];
|
|
112
|
+
/**
|
|
113
|
+
* A function that returns the items being dragged.
|
|
114
|
+
* If omitted, draggable hooks are not added.
|
|
115
|
+
*/
|
|
116
|
+
getItems?: (keys: Set<string | number>, items: T[]) => DragItem[];
|
|
117
|
+
/**
|
|
118
|
+
* Optional custom drag preview renderer.
|
|
119
|
+
*/
|
|
120
|
+
renderDragPreview?: (
|
|
121
|
+
items: DragItem[],
|
|
122
|
+
) => JSX.Element | { element: JSX.Element; x: number; y: number };
|
|
123
|
+
/**
|
|
124
|
+
* Optional drop indicator renderer for collection components.
|
|
125
|
+
*/
|
|
126
|
+
renderDropIndicator?: (target: DropTarget) => JSX.Element;
|
|
127
|
+
/**
|
|
128
|
+
* Optional custom drop target delegate.
|
|
129
|
+
*/
|
|
130
|
+
dropTargetDelegate?: AriaDropTargetDelegate;
|
|
131
|
+
/**
|
|
132
|
+
* Optional drag preview ref.
|
|
133
|
+
*/
|
|
134
|
+
preview?: { current: DragPreviewRenderer | null };
|
|
135
|
+
/**
|
|
136
|
+
* Optional item snapshot used by draggable state `getItems`.
|
|
137
|
+
*/
|
|
138
|
+
items?: T[];
|
|
139
|
+
/**
|
|
140
|
+
* Disable both drag and drop behavior.
|
|
141
|
+
*/
|
|
142
|
+
isDisabled?: boolean;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Provides hooks to enable drag-and-drop behavior for collection components.
|
|
147
|
+
*/
|
|
148
|
+
export function useDragAndDrop<T = object>(options: DragAndDropOptions<T> = {}): DragAndDrop<T> {
|
|
149
|
+
const {
|
|
150
|
+
getItems,
|
|
151
|
+
onDrop,
|
|
152
|
+
onInsert,
|
|
153
|
+
onItemDrop,
|
|
154
|
+
onReorder,
|
|
155
|
+
onMove,
|
|
156
|
+
onRootDrop,
|
|
157
|
+
renderDragPreview,
|
|
158
|
+
renderDropIndicator,
|
|
159
|
+
dropTargetDelegate,
|
|
160
|
+
} = options;
|
|
161
|
+
|
|
162
|
+
const isDraggable = typeof getItems === "function";
|
|
163
|
+
const isDroppable = Boolean(
|
|
164
|
+
onDrop || onInsert || onItemDrop || onReorder || onMove || onRootDrop,
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const hooks: DragAndDropHooks<T> = {};
|
|
168
|
+
const hasDom = typeof HTMLElement !== "undefined";
|
|
169
|
+
const isElementNode = (value: unknown): value is HTMLElement => {
|
|
170
|
+
if (!value) return false;
|
|
171
|
+
if (hasDom && value instanceof HTMLElement) return true;
|
|
172
|
+
return typeof value === "object" && (value as { nodeType?: number }).nodeType === 1;
|
|
173
|
+
};
|
|
174
|
+
const resolvedPreview =
|
|
175
|
+
options.preview ??
|
|
176
|
+
(renderDragPreview
|
|
177
|
+
? {
|
|
178
|
+
current: (
|
|
179
|
+
items: DragItem[],
|
|
180
|
+
callback: (node: HTMLElement | null, x?: number, y?: number) => void,
|
|
181
|
+
) => {
|
|
182
|
+
const rendered = renderDragPreview(items);
|
|
183
|
+
if (!rendered) {
|
|
184
|
+
callback(null);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (typeof rendered === "object" && rendered !== null && "element" in rendered) {
|
|
188
|
+
const previewValue = rendered as { element: unknown; x?: number; y?: number };
|
|
189
|
+
callback(
|
|
190
|
+
isElementNode(previewValue.element) ? previewValue.element : null,
|
|
191
|
+
previewValue.x,
|
|
192
|
+
previewValue.y,
|
|
193
|
+
);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
callback(isElementNode(rendered) ? rendered : null);
|
|
197
|
+
},
|
|
198
|
+
}
|
|
199
|
+
: undefined);
|
|
200
|
+
|
|
201
|
+
if (isDraggable && getItems) {
|
|
202
|
+
hooks.useDraggableCollectionState = (props: DraggableCollectionStateOpts<T>) => {
|
|
203
|
+
return createDraggableCollectionState<T>(() => ({
|
|
204
|
+
onDragStart: options.onDragStart ?? props.onDragStart,
|
|
205
|
+
onDragMove: options.onDragMove ?? props.onDragMove,
|
|
206
|
+
onDragEnd: options.onDragEnd ?? props.onDragEnd,
|
|
207
|
+
getAllowedDropOperations:
|
|
208
|
+
options.getAllowedDropOperations ?? props.getAllowedDropOperations,
|
|
209
|
+
isDisabled: options.isDisabled ?? props.isDisabled,
|
|
210
|
+
preview: resolvedPreview ?? props.preview,
|
|
211
|
+
getItems: (keys) => {
|
|
212
|
+
const sourceItems = props.items ?? options.items ?? [];
|
|
213
|
+
return getItems(keys, sourceItems);
|
|
214
|
+
},
|
|
215
|
+
}));
|
|
216
|
+
};
|
|
217
|
+
hooks.useDraggableCollection = (
|
|
218
|
+
props: Omit<DraggableCollectionOptions, "ref">,
|
|
219
|
+
state: DraggableCollectionState,
|
|
220
|
+
ref: Accessor<HTMLElement | null>,
|
|
221
|
+
) => createDraggableCollection({ ...props, ref }, state);
|
|
222
|
+
hooks.useDraggableItem = (props, state) => createDraggableItem(() => props, state);
|
|
223
|
+
hooks.DragPreview = DragPreview;
|
|
224
|
+
hooks.renderDragPreview = renderDragPreview;
|
|
225
|
+
hooks.isVirtualDragging = () =>
|
|
226
|
+
getGlobalDraggingCollectionRef() != null || getGlobalDraggingKeys().size > 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (isDroppable) {
|
|
230
|
+
hooks.useDroppableCollectionState = (props: DroppableCollectionStateOptions) => {
|
|
231
|
+
return createDroppableCollectionState(() => ({
|
|
232
|
+
acceptedDragTypes: options.acceptedDragTypes ?? props.acceptedDragTypes,
|
|
233
|
+
getDropOperation: options.getDropOperation ?? props.getDropOperation,
|
|
234
|
+
onDropEnter: options.onDropEnter ?? props.onDropEnter,
|
|
235
|
+
onDropActivate: options.onDropActivate ?? props.onDropActivate,
|
|
236
|
+
onDropExit: options.onDropExit ?? props.onDropExit,
|
|
237
|
+
onDrop: options.onDrop ?? props.onDrop,
|
|
238
|
+
onInsert: options.onInsert ?? props.onInsert,
|
|
239
|
+
onRootDrop: options.onRootDrop ?? props.onRootDrop,
|
|
240
|
+
onItemDrop: options.onItemDrop ?? props.onItemDrop,
|
|
241
|
+
onReorder: options.onReorder ?? props.onReorder,
|
|
242
|
+
onMove: options.onMove ?? props.onMove,
|
|
243
|
+
shouldAcceptItemDrop: options.shouldAcceptItemDrop ?? props.shouldAcceptItemDrop,
|
|
244
|
+
isDisabled: options.isDisabled ?? props.isDisabled,
|
|
245
|
+
}));
|
|
246
|
+
};
|
|
247
|
+
hooks.useDroppableCollection = (
|
|
248
|
+
props: Omit<DroppableCollectionOptions, "ref">,
|
|
249
|
+
state: DroppableCollectionState,
|
|
250
|
+
ref: Accessor<HTMLElement | null>,
|
|
251
|
+
) => {
|
|
252
|
+
const acceptedDragTypes = options.acceptedDragTypes ?? props.acceptedDragTypes;
|
|
253
|
+
const normalizedAcceptedDragTypes =
|
|
254
|
+
acceptedDragTypes === "all"
|
|
255
|
+
? "all"
|
|
256
|
+
: acceptedDragTypes?.filter(
|
|
257
|
+
(type): type is string | symbol =>
|
|
258
|
+
typeof type === "string" || typeof type === "symbol",
|
|
259
|
+
);
|
|
260
|
+
return createDroppableCollection(
|
|
261
|
+
() => ({
|
|
262
|
+
ref,
|
|
263
|
+
dropTargetDelegate: options.dropTargetDelegate ?? props.dropTargetDelegate,
|
|
264
|
+
keyboardDelegate: options.keyboardDelegate ?? props.keyboardDelegate,
|
|
265
|
+
onKeyDown: options.onKeyDown ?? props.onKeyDown,
|
|
266
|
+
acceptedDragTypes: normalizedAcceptedDragTypes,
|
|
267
|
+
isDisabled: options.isDisabled ?? props.isDisabled,
|
|
268
|
+
onDropActivate: (e) => {
|
|
269
|
+
(options.onDropActivate ?? props.onDropActivate)?.({
|
|
270
|
+
type: "dropactivate",
|
|
271
|
+
target: e.target,
|
|
272
|
+
x: e.x,
|
|
273
|
+
y: e.y,
|
|
274
|
+
});
|
|
275
|
+
},
|
|
276
|
+
onDrop: (e) => {
|
|
277
|
+
(options.onDrop ?? props.onDrop)?.({
|
|
278
|
+
type: "drop",
|
|
279
|
+
target: e.target,
|
|
280
|
+
x: e.x,
|
|
281
|
+
y: e.y,
|
|
282
|
+
items: e.items,
|
|
283
|
+
dropOperation: e.dropOperation,
|
|
284
|
+
});
|
|
285
|
+
},
|
|
286
|
+
onRootDrop: options.onRootDrop ?? props.onRootDrop,
|
|
287
|
+
onItemDrop: (e) => {
|
|
288
|
+
if (e.target.type === "item") {
|
|
289
|
+
(options.onItemDrop ?? props.onItemDrop)?.({
|
|
290
|
+
items: e.items,
|
|
291
|
+
target: e.target,
|
|
292
|
+
dropOperation: e.dropOperation,
|
|
293
|
+
isInternal: e.isInternal,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
onInsert: (e) => {
|
|
298
|
+
if (e.target.type === "item") {
|
|
299
|
+
(options.onInsert ?? props.onInsert)?.({
|
|
300
|
+
items: e.items,
|
|
301
|
+
target: e.target,
|
|
302
|
+
dropOperation: e.dropOperation,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
onReorder: (e) => {
|
|
307
|
+
if (e.target.type === "item") {
|
|
308
|
+
(options.onReorder ?? props.onReorder)?.({
|
|
309
|
+
keys: e.keys,
|
|
310
|
+
target: e.target,
|
|
311
|
+
dropOperation: e.dropOperation,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
onMove: (e) => {
|
|
316
|
+
if (e.target.type === "item") {
|
|
317
|
+
(options.onMove ?? props.onMove)?.({
|
|
318
|
+
keys: e.keys,
|
|
319
|
+
target: e.target,
|
|
320
|
+
dropOperation: e.dropOperation,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
}),
|
|
325
|
+
state,
|
|
326
|
+
);
|
|
327
|
+
};
|
|
328
|
+
hooks.useDroppableItem = (
|
|
329
|
+
props: Omit<DroppableItemOptions, "ref">,
|
|
330
|
+
state: DroppableCollectionState,
|
|
331
|
+
ref: Accessor<HTMLElement | null>,
|
|
332
|
+
) => createDroppableItem(() => ({ ...props, ref }), state);
|
|
333
|
+
hooks.useDropIndicator = (
|
|
334
|
+
props: { target: DropTarget },
|
|
335
|
+
state: DroppableCollectionState,
|
|
336
|
+
_ref: Accessor<HTMLElement | null>,
|
|
337
|
+
) => {
|
|
338
|
+
const target = props.target;
|
|
339
|
+
const activeTarget = state.target;
|
|
340
|
+
const isDropTarget =
|
|
341
|
+
activeTarget?.type === target.type &&
|
|
342
|
+
(target.type === "root" ||
|
|
343
|
+
(activeTarget.type === "item" &&
|
|
344
|
+
target.type === "item" &&
|
|
345
|
+
activeTarget.key === target.key &&
|
|
346
|
+
activeTarget.dropPosition === target.dropPosition));
|
|
347
|
+
return {
|
|
348
|
+
dropIndicatorProps: {
|
|
349
|
+
role: "option",
|
|
350
|
+
"aria-disabled": true,
|
|
351
|
+
"aria-hidden": isDropTarget ? undefined : "true",
|
|
352
|
+
tabIndex: -1,
|
|
353
|
+
"data-drop-target": isDropTarget ? "" : undefined,
|
|
354
|
+
},
|
|
355
|
+
isDropTarget,
|
|
356
|
+
isHidden: !isDropTarget,
|
|
357
|
+
};
|
|
358
|
+
};
|
|
359
|
+
hooks.renderDropIndicator = renderDropIndicator;
|
|
360
|
+
hooks.dropTargetDelegate = dropTargetDelegate;
|
|
361
|
+
hooks.ListDropTargetDelegate = ListDropTargetDelegate;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return {
|
|
365
|
+
dragAndDropHooks: hooks,
|
|
366
|
+
};
|
|
367
|
+
}
|
package/src/utils.tsx
CHANGED
|
@@ -7,18 +7,15 @@ import {
|
|
|
7
7
|
type JSX,
|
|
8
8
|
type Accessor,
|
|
9
9
|
type FlowComponent,
|
|
10
|
+
type ParentComponent,
|
|
10
11
|
createContext,
|
|
11
12
|
useContext,
|
|
12
13
|
createMemo,
|
|
13
14
|
createSignal,
|
|
14
15
|
onMount,
|
|
15
16
|
Show,
|
|
16
|
-
} from
|
|
17
|
-
import { isServer } from
|
|
18
|
-
|
|
19
|
-
// ============================================
|
|
20
|
-
// TYPES
|
|
21
|
-
// ============================================
|
|
17
|
+
} from "solid-js";
|
|
18
|
+
import { isServer } from "solid-js/web";
|
|
22
19
|
|
|
23
20
|
/**
|
|
24
21
|
* Render props pattern - children can be a function that receives state
|
|
@@ -55,9 +52,7 @@ export interface SlotProps {
|
|
|
55
52
|
slot?: string;
|
|
56
53
|
}
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
// RENDER PROPS
|
|
60
|
-
// ============================================
|
|
55
|
+
export const DEFAULT_SLOT = "default";
|
|
61
56
|
|
|
62
57
|
/**
|
|
63
58
|
* Return type for useRenderProps
|
|
@@ -95,44 +90,54 @@ export interface RenderPropsResult<T> {
|
|
|
95
90
|
*/
|
|
96
91
|
export function useRenderProps<T extends object>(
|
|
97
92
|
props: RenderPropsBase<T> & { defaultClassName?: string },
|
|
98
|
-
values: Accessor<T
|
|
93
|
+
values: Accessor<T>,
|
|
99
94
|
): RenderPropsResult<T> {
|
|
100
|
-
|
|
95
|
+
// Don't destructure children — access lazily to avoid eager evaluation
|
|
96
|
+
// that would trigger child component creation before context providers mount.
|
|
97
|
+
const { class: className, style, defaultClassName = "" } = props;
|
|
101
98
|
|
|
102
99
|
// Compute class and style eagerly (they don't depend on context)
|
|
103
100
|
const computedClass = createMemo(() => {
|
|
104
101
|
const currentValues = values();
|
|
105
|
-
return typeof className ===
|
|
102
|
+
return typeof className === "function"
|
|
106
103
|
? className(currentValues)
|
|
107
|
-
: className ?? defaultClassName;
|
|
104
|
+
: (className ?? defaultClassName);
|
|
108
105
|
});
|
|
109
106
|
|
|
110
107
|
const computedStyle = createMemo(() => {
|
|
111
108
|
const currentValues = values();
|
|
112
|
-
return typeof style ===
|
|
113
|
-
? style(currentValues)
|
|
114
|
-
: style;
|
|
109
|
+
return typeof style === "function" ? style(currentValues) : style;
|
|
115
110
|
});
|
|
116
111
|
|
|
117
112
|
// Return object with explicit function for rendering children
|
|
118
|
-
//
|
|
113
|
+
// Children are accessed lazily during render (inside context providers)
|
|
119
114
|
return {
|
|
120
115
|
class: computedClass,
|
|
121
116
|
style: computedStyle,
|
|
122
117
|
renderChildren: () => {
|
|
123
118
|
const currentValues = values();
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
const children = props.children;
|
|
120
|
+
return typeof children === "function" ? children(currentValues) : children;
|
|
121
|
+
},
|
|
122
|
+
get children() {
|
|
123
|
+
return props.children;
|
|
127
124
|
},
|
|
128
|
-
children,
|
|
129
125
|
values,
|
|
130
126
|
};
|
|
131
127
|
}
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
export function composeRenderProps<T extends object>(
|
|
130
|
+
base: RenderPropsBase<T> | undefined,
|
|
131
|
+
override: RenderPropsBase<T> | undefined,
|
|
132
|
+
): RenderPropsBase<T> {
|
|
133
|
+
if (!base) return override ?? {};
|
|
134
|
+
if (!override) return base;
|
|
135
|
+
return {
|
|
136
|
+
children: override.children ?? base.children,
|
|
137
|
+
class: override.class ?? base.class,
|
|
138
|
+
style: override.style ?? base.style,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
136
141
|
|
|
137
142
|
/**
|
|
138
143
|
* Context value that can be null or the actual value
|
|
@@ -149,32 +154,45 @@ export function createSlottedContext<T>() {
|
|
|
149
154
|
/**
|
|
150
155
|
* Use context with null check
|
|
151
156
|
*/
|
|
152
|
-
export function useSlottedContext<T>(
|
|
157
|
+
export function useSlottedContext<T>(
|
|
158
|
+
context: ReturnType<typeof createContext<T | null>>,
|
|
159
|
+
): T | null {
|
|
153
160
|
return useContext(context);
|
|
154
161
|
}
|
|
155
162
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
163
|
+
export function useContextProps<TProps extends object, TRef>(
|
|
164
|
+
props: TProps,
|
|
165
|
+
ref: TRef,
|
|
166
|
+
context?: ContextValue<Partial<TProps>>,
|
|
167
|
+
): [TProps, TRef] {
|
|
168
|
+
if (!context) return [props, ref];
|
|
169
|
+
return [{ ...(context as TProps), ...props }, ref];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export const Provider: ParentComponent<{
|
|
173
|
+
values: Array<[ReturnType<typeof createContext<unknown>>, unknown]>;
|
|
174
|
+
}> = (props) => {
|
|
175
|
+
return props.children;
|
|
176
|
+
};
|
|
159
177
|
|
|
160
178
|
/**
|
|
161
179
|
* Converts boolean state values to data attributes
|
|
162
180
|
*/
|
|
163
|
-
export function dataAttr(value: boolean | undefined):
|
|
164
|
-
return value ?
|
|
181
|
+
export function dataAttr(value: boolean | undefined): "" | undefined {
|
|
182
|
+
return value ? "" : undefined;
|
|
165
183
|
}
|
|
166
184
|
|
|
167
185
|
/**
|
|
168
186
|
* Creates data attributes from render props
|
|
169
187
|
*/
|
|
170
188
|
export function createDataAttributes<T extends Record<string, boolean | string | undefined>>(
|
|
171
|
-
values: T
|
|
189
|
+
values: T,
|
|
172
190
|
): Record<string, string | undefined> {
|
|
173
191
|
const result: Record<string, string | undefined> = {};
|
|
174
192
|
|
|
175
193
|
for (const [key, value] of Object.entries(values)) {
|
|
176
|
-
if (typeof value ===
|
|
177
|
-
result[`data-${camelToKebab(key)}`] = value ?
|
|
194
|
+
if (typeof value === "boolean") {
|
|
195
|
+
result[`data-${camelToKebab(key)}`] = value ? "" : undefined;
|
|
178
196
|
} else if (value !== undefined) {
|
|
179
197
|
result[`data-${camelToKebab(key)}`] = value;
|
|
180
198
|
}
|
|
@@ -184,13 +202,9 @@ export function createDataAttributes<T extends Record<string, boolean | string |
|
|
|
184
202
|
}
|
|
185
203
|
|
|
186
204
|
function camelToKebab(str: string): string {
|
|
187
|
-
return str.replace(/([a-z])([A-Z])/g,
|
|
205
|
+
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
188
206
|
}
|
|
189
207
|
|
|
190
|
-
// ============================================
|
|
191
|
-
// PROPS UTILITIES
|
|
192
|
-
// ============================================
|
|
193
|
-
|
|
194
208
|
/**
|
|
195
209
|
* Remove data attributes from props (for internal use)
|
|
196
210
|
*/
|
|
@@ -198,7 +212,7 @@ export function removeDataAttributes<T extends Record<string, unknown>>(props: T
|
|
|
198
212
|
const result: Record<string, unknown> = {};
|
|
199
213
|
|
|
200
214
|
for (const [key, value] of Object.entries(props)) {
|
|
201
|
-
if (!key.startsWith(
|
|
215
|
+
if (!key.startsWith("data-")) {
|
|
202
216
|
result[key] = value;
|
|
203
217
|
}
|
|
204
218
|
}
|
|
@@ -215,14 +229,25 @@ export function removeDataAttributes<T extends Record<string, unknown>>(props: T
|
|
|
215
229
|
*/
|
|
216
230
|
export function filterDOMProps<R extends object = Record<string, unknown>>(
|
|
217
231
|
props: object,
|
|
218
|
-
options: { global?: boolean } = {}
|
|
232
|
+
options: { global?: boolean } = {},
|
|
219
233
|
): R {
|
|
220
234
|
const { global = false } = options;
|
|
221
235
|
const result: Record<string, unknown> = {};
|
|
222
236
|
|
|
223
237
|
const globalAttrs = new Set([
|
|
224
|
-
|
|
225
|
-
|
|
238
|
+
"id",
|
|
239
|
+
"class",
|
|
240
|
+
"style",
|
|
241
|
+
"tabIndex",
|
|
242
|
+
"role",
|
|
243
|
+
"title",
|
|
244
|
+
"lang",
|
|
245
|
+
"dir",
|
|
246
|
+
"hidden",
|
|
247
|
+
"draggable",
|
|
248
|
+
"accessKey",
|
|
249
|
+
"contentEditable",
|
|
250
|
+
"spellcheck",
|
|
226
251
|
]);
|
|
227
252
|
|
|
228
253
|
const ariaAttrs = /^aria-/;
|
|
@@ -232,12 +257,10 @@ export function filterDOMProps<R extends object = Record<string, unknown>>(
|
|
|
232
257
|
for (const key in props) {
|
|
233
258
|
if (
|
|
234
259
|
Object.prototype.hasOwnProperty.call(props, key) &&
|
|
235
|
-
(
|
|
236
|
-
(global && globalAttrs.has(key)) ||
|
|
260
|
+
((global && globalAttrs.has(key)) ||
|
|
237
261
|
ariaAttrs.test(key) ||
|
|
238
262
|
dataAttrs.test(key) ||
|
|
239
|
-
eventHandlers.test(key)
|
|
240
|
-
)
|
|
263
|
+
eventHandlers.test(key))
|
|
241
264
|
) {
|
|
242
265
|
result[key] = (props as Record<string, unknown>)[key];
|
|
243
266
|
}
|
|
@@ -246,10 +269,6 @@ export function filterDOMProps<R extends object = Record<string, unknown>>(
|
|
|
246
269
|
return result as R;
|
|
247
270
|
}
|
|
248
271
|
|
|
249
|
-
// ============================================
|
|
250
|
-
// CLIENT-ONLY UTILITIES
|
|
251
|
-
// ============================================
|
|
252
|
-
|
|
253
272
|
export interface ClientOnlyProps {
|
|
254
273
|
/** The children to render only on the client */
|
|
255
274
|
children: JSX.Element;
|