@proyecto-viviana/solidaria-components 0.2.5 → 0.2.9
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/dist/ActionBar.d.ts +71 -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/Breadcrumbs.d.ts +10 -2
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +4 -0
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +13 -0
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +2 -2
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +125 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/Color.d.ts +114 -2
- 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 +64 -0
- 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 +27 -2
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +67 -2
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Disclosure.d.ts +2 -0
- 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 +23 -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 +27 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/GridList.d.ts +40 -1
- package/dist/GridList.d.ts.map +1 -1
- 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/Link.d.ts.map +1 -1
- package/dist/ListBox.d.ts +43 -1
- 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 +20 -2
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +2 -2
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +2 -0
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +2 -0
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +4 -2
- 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 +2 -2
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RangeCalendar.d.ts +5 -0
- 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 +2 -3
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +11 -0
- 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/SharedElementTransition.d.ts +39 -0
- package/dist/SharedElementTransition.d.ts.map +1 -0
- package/dist/Slider.d.ts +6 -3
- package/dist/Slider.d.ts.map +1 -1
- package/dist/Table.d.ts +39 -0
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +4 -3
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +12 -2
- 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 +4 -0
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +26 -1
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/Toast.d.ts.map +1 -1
- package/dist/ToggleButton.d.ts +30 -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.map +1 -1
- package/dist/Tooltip.d.ts +9 -0
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +44 -2
- 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 +3 -1
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +1 -0
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +57 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13961 -5946
- package/dist/index.js.map +1 -7
- package/dist/index.ssr.js +9612 -2401
- package/dist/index.ssr.js.map +1 -7
- package/dist/useDragAndDrop.d.ts +93 -0
- package/dist/useDragAndDrop.d.ts.map +1 -0
- package/dist/utils.d.ts +7 -1
- 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 +8 -6
- package/src/ActionBar.tsx +248 -0
- package/src/ActionGroup.tsx +285 -0
- package/src/Alert.tsx +177 -0
- package/src/Autocomplete.tsx +1 -1
- package/src/Breadcrumbs.tsx +103 -17
- package/src/Button.tsx +65 -21
- package/src/Calendar.tsx +179 -53
- package/src/Checkbox.tsx +1 -2
- package/src/Collection.tsx +341 -0
- package/src/Color.tsx +652 -34
- package/src/ColorEditor.tsx +231 -0
- package/src/ComboBox.tsx +315 -81
- package/src/ContextualHelpTrigger.tsx +183 -0
- package/src/DateField.tsx +93 -19
- package/src/DatePicker.tsx +495 -25
- package/src/Dialog.tsx +40 -9
- package/src/Disclosure.tsx +33 -27
- package/src/DragAndDrop.tsx +334 -0
- package/src/DragPreview.tsx +45 -0
- package/src/DropZone.tsx +213 -0
- package/src/FieldError.tsx +67 -0
- package/src/FileTrigger.tsx +83 -0
- package/src/Focusable.tsx +106 -0
- package/src/Form.tsx +85 -0
- package/src/GridList.tsx +379 -41
- package/src/Icon.tsx +154 -0
- package/src/Keyboard.tsx +26 -0
- package/src/Link.tsx +14 -1
- package/src/ListBox.tsx +484 -33
- package/src/ListDropTargetDelegate.ts +282 -0
- package/src/Menu.tsx +388 -35
- package/src/Meter.tsx +7 -3
- package/src/Modal.tsx +32 -4
- package/src/NumberField.tsx +163 -43
- package/src/Popover.tsx +136 -180
- package/src/Pressable.tsx +108 -0
- package/src/ProgressBar.tsx +7 -3
- package/src/RadioGroup.tsx +35 -25
- package/src/RangeCalendar.tsx +100 -68
- package/src/RouterProvider.tsx +240 -0
- package/src/SearchField.tsx +142 -34
- package/src/Select.tsx +221 -73
- package/src/SelectionIndicator.tsx +105 -0
- package/src/SharedElementTransition.tsx +258 -0
- package/src/Slider.tsx +16 -6
- package/src/Table.tsx +417 -57
- package/src/Tabs.tsx +68 -35
- package/src/TagGroup.tsx +121 -36
- package/src/Text.tsx +18 -0
- package/src/TextField.tsx +25 -8
- package/src/TimeField.tsx +101 -151
- package/src/Toast.tsx +108 -14
- package/src/ToggleButton.tsx +159 -0
- package/src/ToggleButtonGroup.tsx +136 -0
- package/src/Toolbar.tsx +14 -8
- package/src/Tooltip.tsx +108 -19
- package/src/Tree.tsx +1143 -87
- package/src/Virtualizer.tsx +702 -0
- package/src/VirtualizerLayouts.ts +265 -0
- package/src/VisuallyHidden.tsx +15 -21
- package/src/contexts.ts +1 -0
- package/src/index.ts +1057 -620
- package/src/useDragAndDrop.ts +351 -0
- package/src/utils.tsx +37 -3
- package/src/virtualizer/Layout.ts +200 -0
|
@@ -0,0 +1,351 @@
|
|
|
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>
|
|
43
|
+
extends Omit<DraggableCollectionStateOptions<T>, 'getItems'> {
|
|
44
|
+
items?: T[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface DragHooks<T = object> {
|
|
48
|
+
useDraggableCollectionState?: (props: DraggableCollectionStateOpts<T>) => DraggableCollectionState;
|
|
49
|
+
useDraggableCollection?: (
|
|
50
|
+
props: Omit<DraggableCollectionOptions, 'ref'>,
|
|
51
|
+
state: DraggableCollectionState,
|
|
52
|
+
ref: Accessor<HTMLElement | null>
|
|
53
|
+
) => DraggableCollectionAria;
|
|
54
|
+
useDraggableItem?: (props: DraggableItemOptions, state: DraggableCollectionState) => DraggableItemAria;
|
|
55
|
+
DragPreview?: typeof DragPreview;
|
|
56
|
+
renderDragPreview?: DragAndDropOptions<T>['renderDragPreview'];
|
|
57
|
+
isVirtualDragging?: () => boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface DropHooks {
|
|
61
|
+
useDroppableCollectionState?: (props: DroppableCollectionStateOptions) => DroppableCollectionState;
|
|
62
|
+
useDroppableCollection?: (
|
|
63
|
+
props: Omit<DroppableCollectionOptions, 'ref'>,
|
|
64
|
+
state: DroppableCollectionState,
|
|
65
|
+
ref: Accessor<HTMLElement | null>
|
|
66
|
+
) => DroppableCollectionAria;
|
|
67
|
+
useDroppableItem?: (
|
|
68
|
+
options: Omit<DroppableItemOptions, 'ref'>,
|
|
69
|
+
state: DroppableCollectionState,
|
|
70
|
+
ref: Accessor<HTMLElement | null>
|
|
71
|
+
) => DroppableItemAria;
|
|
72
|
+
useDropIndicator?: (
|
|
73
|
+
props: { target: DropTarget },
|
|
74
|
+
state: DroppableCollectionState,
|
|
75
|
+
ref: Accessor<HTMLElement | null>
|
|
76
|
+
) => {
|
|
77
|
+
dropIndicatorProps: JSX.HTMLAttributes<HTMLElement>;
|
|
78
|
+
isDropTarget: boolean;
|
|
79
|
+
isHidden: boolean;
|
|
80
|
+
};
|
|
81
|
+
renderDropIndicator?: (target: DropTarget) => JSX.Element;
|
|
82
|
+
dropTargetDelegate?: AriaDropTargetDelegate;
|
|
83
|
+
ListDropTargetDelegate?: typeof ListDropTargetDelegate;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type DragAndDropHooks<T = object> = DragHooks<T> & DropHooks;
|
|
87
|
+
|
|
88
|
+
export interface DragAndDrop<T = object> {
|
|
89
|
+
/** Drag and drop hooks for the collection element. */
|
|
90
|
+
dragAndDropHooks: DragAndDropHooks<T>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface DragAndDropOptions<T = object>
|
|
94
|
+
extends Partial<Omit<DraggableCollectionProps<T>, 'preview'>>,
|
|
95
|
+
Partial<DroppableCollectionProps> {
|
|
96
|
+
/**
|
|
97
|
+
* Optional keyboard delegate forwarded to the collection droppable hook.
|
|
98
|
+
*/
|
|
99
|
+
keyboardDelegate?: DroppableCollectionOptions['keyboardDelegate'];
|
|
100
|
+
/**
|
|
101
|
+
* Optional keydown handler composed with collection droppable keyboard behavior.
|
|
102
|
+
*/
|
|
103
|
+
onKeyDown?: DroppableCollectionOptions['onKeyDown'];
|
|
104
|
+
/**
|
|
105
|
+
* A function that returns the items being dragged.
|
|
106
|
+
* If omitted, draggable hooks are not added.
|
|
107
|
+
*/
|
|
108
|
+
getItems?: (keys: Set<string | number>, items: T[]) => DragItem[];
|
|
109
|
+
/**
|
|
110
|
+
* Optional custom drag preview renderer.
|
|
111
|
+
*/
|
|
112
|
+
renderDragPreview?: (items: DragItem[]) => JSX.Element | { element: JSX.Element; x: number; y: number };
|
|
113
|
+
/**
|
|
114
|
+
* Optional drop indicator renderer for collection components.
|
|
115
|
+
*/
|
|
116
|
+
renderDropIndicator?: (target: DropTarget) => JSX.Element;
|
|
117
|
+
/**
|
|
118
|
+
* Optional custom drop target delegate.
|
|
119
|
+
*/
|
|
120
|
+
dropTargetDelegate?: AriaDropTargetDelegate;
|
|
121
|
+
/**
|
|
122
|
+
* Optional drag preview ref.
|
|
123
|
+
*/
|
|
124
|
+
preview?: { current: DragPreviewRenderer | null };
|
|
125
|
+
/**
|
|
126
|
+
* Optional item snapshot used by draggable state `getItems`.
|
|
127
|
+
*/
|
|
128
|
+
items?: T[];
|
|
129
|
+
/**
|
|
130
|
+
* Disable both drag and drop behavior.
|
|
131
|
+
*/
|
|
132
|
+
isDisabled?: boolean;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Provides hooks to enable drag-and-drop behavior for collection components.
|
|
137
|
+
*/
|
|
138
|
+
export function useDragAndDrop<T = object>(options: DragAndDropOptions<T> = {}): DragAndDrop<T> {
|
|
139
|
+
const {
|
|
140
|
+
getItems,
|
|
141
|
+
onDrop,
|
|
142
|
+
onInsert,
|
|
143
|
+
onItemDrop,
|
|
144
|
+
onReorder,
|
|
145
|
+
onMove,
|
|
146
|
+
onRootDrop,
|
|
147
|
+
renderDragPreview,
|
|
148
|
+
renderDropIndicator,
|
|
149
|
+
dropTargetDelegate,
|
|
150
|
+
} = options;
|
|
151
|
+
|
|
152
|
+
const isDraggable = typeof getItems === 'function';
|
|
153
|
+
const isDroppable = Boolean(onDrop || onInsert || onItemDrop || onReorder || onMove || onRootDrop);
|
|
154
|
+
|
|
155
|
+
const hooks: DragAndDropHooks<T> = {};
|
|
156
|
+
const hasDom = typeof HTMLElement !== 'undefined';
|
|
157
|
+
const isElementNode = (value: unknown): value is HTMLElement => {
|
|
158
|
+
if (!value) return false;
|
|
159
|
+
if (hasDom && value instanceof HTMLElement) return true;
|
|
160
|
+
return typeof value === 'object' && (value as { nodeType?: number }).nodeType === 1;
|
|
161
|
+
};
|
|
162
|
+
const resolvedPreview = options.preview ?? (
|
|
163
|
+
renderDragPreview
|
|
164
|
+
? {
|
|
165
|
+
current: (items: DragItem[], callback: (node: HTMLElement | null, x?: number, y?: number) => void) => {
|
|
166
|
+
const rendered = renderDragPreview(items);
|
|
167
|
+
if (!rendered) {
|
|
168
|
+
callback(null);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (
|
|
172
|
+
typeof rendered === 'object' &&
|
|
173
|
+
rendered !== null &&
|
|
174
|
+
'element' in rendered
|
|
175
|
+
) {
|
|
176
|
+
const previewValue = rendered as { element: unknown; x?: number; y?: number };
|
|
177
|
+
callback(isElementNode(previewValue.element) ? previewValue.element : null, previewValue.x, previewValue.y);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
callback(isElementNode(rendered) ? rendered : null);
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
: undefined
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
if (isDraggable && getItems) {
|
|
187
|
+
hooks.useDraggableCollectionState = (props: DraggableCollectionStateOpts<T>) => {
|
|
188
|
+
return createDraggableCollectionState<T>(() => ({
|
|
189
|
+
onDragStart: options.onDragStart ?? props.onDragStart,
|
|
190
|
+
onDragMove: options.onDragMove ?? props.onDragMove,
|
|
191
|
+
onDragEnd: options.onDragEnd ?? props.onDragEnd,
|
|
192
|
+
getAllowedDropOperations: options.getAllowedDropOperations ?? props.getAllowedDropOperations,
|
|
193
|
+
isDisabled: options.isDisabled ?? props.isDisabled,
|
|
194
|
+
preview: resolvedPreview ?? props.preview,
|
|
195
|
+
getItems: (keys) => {
|
|
196
|
+
const sourceItems = props.items ?? options.items ?? [];
|
|
197
|
+
return getItems(keys, sourceItems);
|
|
198
|
+
},
|
|
199
|
+
}));
|
|
200
|
+
};
|
|
201
|
+
hooks.useDraggableCollection = (
|
|
202
|
+
props: Omit<DraggableCollectionOptions, 'ref'>,
|
|
203
|
+
state: DraggableCollectionState,
|
|
204
|
+
ref: Accessor<HTMLElement | null>
|
|
205
|
+
) => createDraggableCollection({ ...props, ref }, state);
|
|
206
|
+
hooks.useDraggableItem = (props, state) => createDraggableItem(() => props, state);
|
|
207
|
+
hooks.DragPreview = DragPreview;
|
|
208
|
+
hooks.renderDragPreview = renderDragPreview;
|
|
209
|
+
hooks.isVirtualDragging = () =>
|
|
210
|
+
getGlobalDraggingCollectionRef() != null || getGlobalDraggingKeys().size > 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (isDroppable) {
|
|
214
|
+
hooks.useDroppableCollectionState = (props: DroppableCollectionStateOptions) => {
|
|
215
|
+
return createDroppableCollectionState(() => ({
|
|
216
|
+
acceptedDragTypes: options.acceptedDragTypes ?? props.acceptedDragTypes,
|
|
217
|
+
getDropOperation: options.getDropOperation ?? props.getDropOperation,
|
|
218
|
+
onDropEnter: options.onDropEnter ?? props.onDropEnter,
|
|
219
|
+
onDropActivate: options.onDropActivate ?? props.onDropActivate,
|
|
220
|
+
onDropExit: options.onDropExit ?? props.onDropExit,
|
|
221
|
+
onDrop: options.onDrop ?? props.onDrop,
|
|
222
|
+
onInsert: options.onInsert ?? props.onInsert,
|
|
223
|
+
onRootDrop: options.onRootDrop ?? props.onRootDrop,
|
|
224
|
+
onItemDrop: options.onItemDrop ?? props.onItemDrop,
|
|
225
|
+
onReorder: options.onReorder ?? props.onReorder,
|
|
226
|
+
onMove: options.onMove ?? props.onMove,
|
|
227
|
+
shouldAcceptItemDrop: options.shouldAcceptItemDrop ?? props.shouldAcceptItemDrop,
|
|
228
|
+
isDisabled: options.isDisabled ?? props.isDisabled,
|
|
229
|
+
}));
|
|
230
|
+
};
|
|
231
|
+
hooks.useDroppableCollection = (
|
|
232
|
+
props: Omit<DroppableCollectionOptions, 'ref'>,
|
|
233
|
+
state: DroppableCollectionState,
|
|
234
|
+
ref: Accessor<HTMLElement | null>
|
|
235
|
+
) => {
|
|
236
|
+
const acceptedDragTypes = (options.acceptedDragTypes ?? props.acceptedDragTypes);
|
|
237
|
+
const normalizedAcceptedDragTypes = acceptedDragTypes === 'all'
|
|
238
|
+
? 'all'
|
|
239
|
+
: acceptedDragTypes?.filter((type): type is string | symbol =>
|
|
240
|
+
typeof type === 'string' || typeof type === 'symbol');
|
|
241
|
+
return (
|
|
242
|
+
createDroppableCollection(
|
|
243
|
+
() => ({
|
|
244
|
+
ref,
|
|
245
|
+
dropTargetDelegate: options.dropTargetDelegate ?? props.dropTargetDelegate,
|
|
246
|
+
keyboardDelegate: options.keyboardDelegate ?? props.keyboardDelegate,
|
|
247
|
+
onKeyDown: options.onKeyDown ?? props.onKeyDown,
|
|
248
|
+
acceptedDragTypes: normalizedAcceptedDragTypes,
|
|
249
|
+
isDisabled: options.isDisabled ?? props.isDisabled,
|
|
250
|
+
onDropActivate: (e) => {
|
|
251
|
+
(options.onDropActivate ?? props.onDropActivate)?.({
|
|
252
|
+
type: 'dropactivate',
|
|
253
|
+
target: e.target,
|
|
254
|
+
x: e.x,
|
|
255
|
+
y: e.y,
|
|
256
|
+
});
|
|
257
|
+
},
|
|
258
|
+
onDrop: (e) => {
|
|
259
|
+
(options.onDrop ?? props.onDrop)?.({
|
|
260
|
+
type: 'drop',
|
|
261
|
+
target: e.target,
|
|
262
|
+
x: e.x,
|
|
263
|
+
y: e.y,
|
|
264
|
+
items: e.items,
|
|
265
|
+
dropOperation: e.dropOperation,
|
|
266
|
+
});
|
|
267
|
+
},
|
|
268
|
+
onRootDrop: options.onRootDrop ?? props.onRootDrop,
|
|
269
|
+
onItemDrop: (e) => {
|
|
270
|
+
if (e.target.type === 'item') {
|
|
271
|
+
(options.onItemDrop ?? props.onItemDrop)?.({
|
|
272
|
+
items: e.items,
|
|
273
|
+
target: e.target,
|
|
274
|
+
dropOperation: e.dropOperation,
|
|
275
|
+
isInternal: e.isInternal,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
onInsert: (e) => {
|
|
280
|
+
if (e.target.type === 'item') {
|
|
281
|
+
(options.onInsert ?? props.onInsert)?.({
|
|
282
|
+
items: e.items,
|
|
283
|
+
target: e.target,
|
|
284
|
+
dropOperation: e.dropOperation,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
onReorder: (e) => {
|
|
289
|
+
if (e.target.type === 'item') {
|
|
290
|
+
(options.onReorder ?? props.onReorder)?.({
|
|
291
|
+
keys: e.keys,
|
|
292
|
+
target: e.target,
|
|
293
|
+
dropOperation: e.dropOperation,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
onMove: (e) => {
|
|
298
|
+
if (e.target.type === 'item') {
|
|
299
|
+
(options.onMove ?? props.onMove)?.({
|
|
300
|
+
keys: e.keys,
|
|
301
|
+
target: e.target,
|
|
302
|
+
dropOperation: e.dropOperation,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
}),
|
|
307
|
+
state
|
|
308
|
+
));
|
|
309
|
+
};
|
|
310
|
+
hooks.useDroppableItem = (
|
|
311
|
+
props: Omit<DroppableItemOptions, 'ref'>,
|
|
312
|
+
state: DroppableCollectionState,
|
|
313
|
+
ref: Accessor<HTMLElement | null>
|
|
314
|
+
) => createDroppableItem(() => ({ ...props, ref }), state);
|
|
315
|
+
hooks.useDropIndicator = (
|
|
316
|
+
props: { target: DropTarget },
|
|
317
|
+
state: DroppableCollectionState,
|
|
318
|
+
_ref: Accessor<HTMLElement | null>
|
|
319
|
+
) => {
|
|
320
|
+
const target = props.target;
|
|
321
|
+
const activeTarget = state.target;
|
|
322
|
+
const isDropTarget =
|
|
323
|
+
activeTarget?.type === target.type &&
|
|
324
|
+
(target.type === 'root'
|
|
325
|
+
|| (
|
|
326
|
+
activeTarget.type === 'item' &&
|
|
327
|
+
target.type === 'item' &&
|
|
328
|
+
activeTarget.key === target.key &&
|
|
329
|
+
activeTarget.dropPosition === target.dropPosition
|
|
330
|
+
));
|
|
331
|
+
return {
|
|
332
|
+
dropIndicatorProps: {
|
|
333
|
+
role: 'option',
|
|
334
|
+
'aria-disabled': true,
|
|
335
|
+
'aria-hidden': isDropTarget ? undefined : 'true',
|
|
336
|
+
tabIndex: -1,
|
|
337
|
+
'data-drop-target': isDropTarget ? '' : undefined,
|
|
338
|
+
},
|
|
339
|
+
isDropTarget,
|
|
340
|
+
isHidden: !isDropTarget,
|
|
341
|
+
};
|
|
342
|
+
};
|
|
343
|
+
hooks.renderDropIndicator = renderDropIndicator;
|
|
344
|
+
hooks.dropTargetDelegate = dropTargetDelegate;
|
|
345
|
+
hooks.ListDropTargetDelegate = ListDropTargetDelegate;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
dragAndDropHooks: hooks,
|
|
350
|
+
};
|
|
351
|
+
}
|
package/src/utils.tsx
CHANGED
|
@@ -7,6 +7,7 @@ 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,
|
|
@@ -55,6 +56,8 @@ export interface SlotProps {
|
|
|
55
56
|
slot?: string;
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
export const DEFAULT_SLOT = 'default';
|
|
60
|
+
|
|
58
61
|
// ============================================
|
|
59
62
|
// RENDER PROPS
|
|
60
63
|
// ============================================
|
|
@@ -97,7 +100,9 @@ export function useRenderProps<T extends object>(
|
|
|
97
100
|
props: RenderPropsBase<T> & { defaultClassName?: string },
|
|
98
101
|
values: Accessor<T>
|
|
99
102
|
): RenderPropsResult<T> {
|
|
100
|
-
|
|
103
|
+
// Don't destructure children — access lazily to avoid eager evaluation
|
|
104
|
+
// that would trigger child component creation before context providers mount.
|
|
105
|
+
const { class: className, style, defaultClassName = '' } = props;
|
|
101
106
|
|
|
102
107
|
// Compute class and style eagerly (they don't depend on context)
|
|
103
108
|
const computedClass = createMemo(() => {
|
|
@@ -115,21 +120,35 @@ export function useRenderProps<T extends object>(
|
|
|
115
120
|
});
|
|
116
121
|
|
|
117
122
|
// Return object with explicit function for rendering children
|
|
118
|
-
//
|
|
123
|
+
// Children are accessed lazily during render (inside context providers)
|
|
119
124
|
return {
|
|
120
125
|
class: computedClass,
|
|
121
126
|
style: computedStyle,
|
|
122
127
|
renderChildren: () => {
|
|
123
128
|
const currentValues = values();
|
|
129
|
+
const children = props.children;
|
|
124
130
|
return typeof children === 'function'
|
|
125
131
|
? children(currentValues)
|
|
126
132
|
: children;
|
|
127
133
|
},
|
|
128
|
-
children,
|
|
134
|
+
get children() { return props.children; },
|
|
129
135
|
values,
|
|
130
136
|
};
|
|
131
137
|
}
|
|
132
138
|
|
|
139
|
+
export function composeRenderProps<T extends object>(
|
|
140
|
+
base: RenderPropsBase<T> | undefined,
|
|
141
|
+
override: RenderPropsBase<T> | undefined
|
|
142
|
+
): RenderPropsBase<T> {
|
|
143
|
+
if (!base) return override ?? {};
|
|
144
|
+
if (!override) return base;
|
|
145
|
+
return {
|
|
146
|
+
children: override.children ?? base.children,
|
|
147
|
+
class: override.class ?? base.class,
|
|
148
|
+
style: override.style ?? base.style,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
133
152
|
// ============================================
|
|
134
153
|
// CONTEXT UTILITIES
|
|
135
154
|
// ============================================
|
|
@@ -153,6 +172,21 @@ export function useSlottedContext<T>(context: ReturnType<typeof createContext<T
|
|
|
153
172
|
return useContext(context);
|
|
154
173
|
}
|
|
155
174
|
|
|
175
|
+
export function useContextProps<TProps extends object, TRef>(
|
|
176
|
+
props: TProps,
|
|
177
|
+
ref: TRef,
|
|
178
|
+
context?: ContextValue<Partial<TProps>>
|
|
179
|
+
): [TProps, TRef] {
|
|
180
|
+
if (!context) return [props, ref];
|
|
181
|
+
return [{ ...(context as TProps), ...props }, ref];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export const Provider: ParentComponent<{
|
|
185
|
+
values: Array<[ReturnType<typeof createContext<unknown>>, unknown]>;
|
|
186
|
+
}> = (props) => {
|
|
187
|
+
return props.children;
|
|
188
|
+
};
|
|
189
|
+
|
|
156
190
|
// ============================================
|
|
157
191
|
// DATA ATTRIBUTES
|
|
158
192
|
// ============================================
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import type { Key } from '@proyecto-viviana/solid-stately';
|
|
2
|
+
|
|
3
|
+
export interface InvalidationContext<O = unknown> {
|
|
4
|
+
contentChanged?: boolean;
|
|
5
|
+
offsetChanged?: boolean;
|
|
6
|
+
sizeChanged?: boolean;
|
|
7
|
+
itemSizeChanged?: boolean;
|
|
8
|
+
layoutOptionsChanged?: boolean;
|
|
9
|
+
layoutOptions?: O;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class Point {
|
|
13
|
+
constructor(public x = 0, public y = 0) {}
|
|
14
|
+
copy(): Point {
|
|
15
|
+
return new Point(this.x, this.y);
|
|
16
|
+
}
|
|
17
|
+
equals(point: Point): boolean {
|
|
18
|
+
return this.x === point.x && this.y === point.y;
|
|
19
|
+
}
|
|
20
|
+
isOrigin(): boolean {
|
|
21
|
+
return this.x === 0 && this.y === 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class Size {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
|
|
29
|
+
constructor(width = 0, height = 0) {
|
|
30
|
+
this.width = Math.max(0, width);
|
|
31
|
+
this.height = Math.max(0, height);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
copy(): Size {
|
|
35
|
+
return new Size(this.width, this.height);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
equals(other: Size): boolean {
|
|
39
|
+
return this.width === other.width && this.height === other.height;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get area(): number {
|
|
43
|
+
return this.width * this.height;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class Rect {
|
|
48
|
+
constructor(
|
|
49
|
+
public x = 0,
|
|
50
|
+
public y = 0,
|
|
51
|
+
public width = 0,
|
|
52
|
+
public height = 0
|
|
53
|
+
) {}
|
|
54
|
+
|
|
55
|
+
get maxX(): number {
|
|
56
|
+
return this.x + this.width;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get maxY(): number {
|
|
60
|
+
return this.y + this.height;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get area(): number {
|
|
64
|
+
return this.width * this.height;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get topLeft(): Point {
|
|
68
|
+
return new Point(this.x, this.y);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get topRight(): Point {
|
|
72
|
+
return new Point(this.maxX, this.y);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get bottomLeft(): Point {
|
|
76
|
+
return new Point(this.x, this.maxY);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get bottomRight(): Point {
|
|
80
|
+
return new Point(this.maxX, this.maxY);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
intersects(rect: Rect): boolean {
|
|
84
|
+
return (
|
|
85
|
+
this.x <= rect.maxX &&
|
|
86
|
+
rect.x <= this.maxX &&
|
|
87
|
+
this.y <= rect.maxY &&
|
|
88
|
+
rect.y <= this.maxY
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
containsRect(rect: Rect): boolean {
|
|
93
|
+
return (
|
|
94
|
+
this.x <= rect.x &&
|
|
95
|
+
this.y <= rect.y &&
|
|
96
|
+
this.maxX >= rect.maxX &&
|
|
97
|
+
this.maxY >= rect.maxY
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
containsPoint(point: Point): boolean {
|
|
102
|
+
return (
|
|
103
|
+
this.x <= point.x &&
|
|
104
|
+
this.y <= point.y &&
|
|
105
|
+
this.maxX >= point.x &&
|
|
106
|
+
this.maxY >= point.y
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
union(other: Rect): Rect {
|
|
111
|
+
const x = Math.min(this.x, other.x);
|
|
112
|
+
const y = Math.min(this.y, other.y);
|
|
113
|
+
const width = Math.max(this.maxX, other.maxX) - x;
|
|
114
|
+
const height = Math.max(this.maxY, other.maxY) - y;
|
|
115
|
+
return new Rect(x, y, width, height);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
intersection(other: Rect): Rect {
|
|
119
|
+
if (!this.intersects(other)) {
|
|
120
|
+
return new Rect(0, 0, 0, 0);
|
|
121
|
+
}
|
|
122
|
+
const x = Math.max(this.x, other.x);
|
|
123
|
+
const y = Math.max(this.y, other.y);
|
|
124
|
+
const width = Math.min(this.maxX, other.maxX) - x;
|
|
125
|
+
const height = Math.min(this.maxY, other.maxY) - y;
|
|
126
|
+
return new Rect(x, y, width, height);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
copy(): Rect {
|
|
130
|
+
return new Rect(this.x, this.y, this.width, this.height);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
equals(rect: Rect): boolean {
|
|
134
|
+
return (
|
|
135
|
+
this.x === rect.x &&
|
|
136
|
+
this.y === rect.y &&
|
|
137
|
+
this.width === rect.width &&
|
|
138
|
+
this.height === rect.height
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export class LayoutInfo {
|
|
144
|
+
parentKey: Key | null = null;
|
|
145
|
+
content: unknown = null;
|
|
146
|
+
estimatedSize = false;
|
|
147
|
+
isSticky = false;
|
|
148
|
+
opacity = 1;
|
|
149
|
+
transform: string | null = null;
|
|
150
|
+
zIndex = 0;
|
|
151
|
+
allowOverflow = false;
|
|
152
|
+
|
|
153
|
+
constructor(public type: string, public key: Key, public rect: Rect) {}
|
|
154
|
+
|
|
155
|
+
copy(): LayoutInfo {
|
|
156
|
+
const copy = new LayoutInfo(this.type, this.key, this.rect.copy());
|
|
157
|
+
copy.parentKey = this.parentKey;
|
|
158
|
+
copy.content = this.content;
|
|
159
|
+
copy.estimatedSize = this.estimatedSize;
|
|
160
|
+
copy.isSticky = this.isSticky;
|
|
161
|
+
copy.opacity = this.opacity;
|
|
162
|
+
copy.transform = this.transform;
|
|
163
|
+
copy.zIndex = this.zIndex;
|
|
164
|
+
copy.allowOverflow = this.allowOverflow;
|
|
165
|
+
return copy;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
interface VirtualizerLike {
|
|
170
|
+
visibleRect: Rect;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export abstract class Layout<T extends object = object, O = unknown> {
|
|
174
|
+
virtualizer: VirtualizerLike | null = null;
|
|
175
|
+
|
|
176
|
+
abstract getVisibleLayoutInfos(rect: Rect): LayoutInfo[];
|
|
177
|
+
abstract getLayoutInfo(key: Key): LayoutInfo | null;
|
|
178
|
+
abstract getContentSize(): Size;
|
|
179
|
+
|
|
180
|
+
shouldInvalidate(newRect: Rect, oldRect: Rect): boolean {
|
|
181
|
+
return newRect.width !== oldRect.width || newRect.height !== oldRect.height;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
shouldInvalidateLayoutOptions(newOptions: O, oldOptions: O): boolean {
|
|
185
|
+
return newOptions !== oldOptions;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
update(_context: InvalidationContext<O>): void {}
|
|
189
|
+
|
|
190
|
+
updateItemSize?(_key: Key, _size: Size): boolean;
|
|
191
|
+
getDropTargetLayoutInfo?(_target: unknown): LayoutInfo | null;
|
|
192
|
+
|
|
193
|
+
protected getItemRect(key: Key): Rect | null {
|
|
194
|
+
return this.getLayoutInfo(key)?.rect ?? null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
getVisibleRect(): Rect {
|
|
198
|
+
return this.virtualizer?.visibleRect ?? new Rect();
|
|
199
|
+
}
|
|
200
|
+
}
|