@proyecto-viviana/solidaria 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/dist/autocomplete/createAutocomplete.d.ts +2 -2
  2. package/dist/autocomplete/createAutocomplete.d.ts.map +1 -1
  3. package/dist/index.js +233 -234
  4. package/dist/index.js.map +2 -2
  5. package/dist/index.ssr.js +233 -234
  6. package/dist/index.ssr.js.map +2 -2
  7. package/dist/interactions/PressEvent.d.ts +13 -10
  8. package/dist/interactions/PressEvent.d.ts.map +1 -1
  9. package/dist/interactions/createPress.d.ts.map +1 -1
  10. package/dist/interactions/index.d.ts +1 -1
  11. package/dist/interactions/index.d.ts.map +1 -1
  12. package/dist/select/createHiddenSelect.d.ts.map +1 -1
  13. package/dist/toolbar/createToolbar.d.ts.map +1 -1
  14. package/dist/tooltip/createTooltipTrigger.d.ts.map +1 -1
  15. package/package.json +9 -7
  16. package/src/autocomplete/createAutocomplete.ts +341 -0
  17. package/src/autocomplete/index.ts +9 -0
  18. package/src/breadcrumbs/createBreadcrumbs.ts +196 -0
  19. package/src/breadcrumbs/index.ts +8 -0
  20. package/src/button/createButton.ts +142 -0
  21. package/src/button/createToggleButton.ts +101 -0
  22. package/src/button/index.ts +4 -0
  23. package/src/button/types.ts +78 -0
  24. package/src/calendar/createCalendar.ts +138 -0
  25. package/src/calendar/createCalendarCell.ts +187 -0
  26. package/src/calendar/createCalendarGrid.ts +140 -0
  27. package/src/calendar/createRangeCalendar.ts +136 -0
  28. package/src/calendar/createRangeCalendarCell.ts +186 -0
  29. package/src/calendar/index.ts +34 -0
  30. package/src/checkbox/createCheckbox.ts +135 -0
  31. package/src/checkbox/createCheckboxGroup.ts +137 -0
  32. package/src/checkbox/createCheckboxGroupItem.ts +117 -0
  33. package/src/checkbox/createCheckboxGroupState.ts +193 -0
  34. package/src/checkbox/index.ts +13 -0
  35. package/src/color/createColorArea.ts +314 -0
  36. package/src/color/createColorField.ts +137 -0
  37. package/src/color/createColorSlider.ts +197 -0
  38. package/src/color/createColorSwatch.ts +40 -0
  39. package/src/color/createColorWheel.ts +208 -0
  40. package/src/color/index.ts +24 -0
  41. package/src/color/types.ts +116 -0
  42. package/src/combobox/createComboBox.ts +647 -0
  43. package/src/combobox/index.ts +6 -0
  44. package/src/combobox/intl/en-US.json +7 -0
  45. package/src/combobox/intl/es-ES.json +7 -0
  46. package/src/combobox/intl/index.ts +23 -0
  47. package/src/datepicker/createDateField.ts +154 -0
  48. package/src/datepicker/createDatePicker.ts +206 -0
  49. package/src/datepicker/createDateSegment.ts +229 -0
  50. package/src/datepicker/createTimeField.ts +154 -0
  51. package/src/datepicker/index.ts +28 -0
  52. package/src/dialog/createDialog.ts +120 -0
  53. package/src/dialog/index.ts +2 -0
  54. package/src/dialog/types.ts +19 -0
  55. package/src/disclosure/createDisclosure.ts +131 -0
  56. package/src/disclosure/createDisclosureGroup.ts +62 -0
  57. package/src/disclosure/index.ts +11 -0
  58. package/src/dnd/createDrag.ts +209 -0
  59. package/src/dnd/createDraggableCollection.ts +63 -0
  60. package/src/dnd/createDraggableItem.ts +243 -0
  61. package/src/dnd/createDrop.ts +321 -0
  62. package/src/dnd/createDroppableCollection.ts +293 -0
  63. package/src/dnd/createDroppableItem.ts +213 -0
  64. package/src/dnd/index.ts +47 -0
  65. package/src/dnd/types.ts +89 -0
  66. package/src/dnd/utils.ts +294 -0
  67. package/src/focus/FocusScope.tsx +408 -0
  68. package/src/focus/createAutoFocus.ts +321 -0
  69. package/src/focus/createFocusRestore.ts +313 -0
  70. package/src/focus/createVirtualFocus.ts +396 -0
  71. package/src/focus/index.ts +35 -0
  72. package/src/form/createFormReset.ts +51 -0
  73. package/src/form/createFormValidation.ts +224 -0
  74. package/src/form/index.ts +11 -0
  75. package/src/grid/GridKeyboardDelegate.ts +429 -0
  76. package/src/grid/createGrid.ts +261 -0
  77. package/src/grid/createGridCell.ts +182 -0
  78. package/src/grid/createGridRow.ts +153 -0
  79. package/src/grid/index.ts +18 -0
  80. package/src/grid/types.ts +133 -0
  81. package/src/gridlist/createGridList.ts +185 -0
  82. package/src/gridlist/createGridListItem.ts +180 -0
  83. package/src/gridlist/createGridListSelectionCheckbox.ts +59 -0
  84. package/src/gridlist/index.ts +16 -0
  85. package/src/gridlist/types.ts +81 -0
  86. package/src/i18n/NumberFormatter.ts +266 -0
  87. package/src/i18n/createCollator.ts +79 -0
  88. package/src/i18n/createDateFormatter.ts +83 -0
  89. package/src/i18n/createFilter.ts +131 -0
  90. package/src/i18n/createNumberFormatter.ts +52 -0
  91. package/src/i18n/createStringFormatter.ts +87 -0
  92. package/src/i18n/index.ts +40 -0
  93. package/src/i18n/locale.tsx +188 -0
  94. package/src/i18n/utils.ts +99 -0
  95. package/src/index.ts +670 -0
  96. package/src/interactions/FocusableProvider.tsx +44 -0
  97. package/src/interactions/PressEvent.ts +126 -0
  98. package/src/interactions/createFocus.ts +163 -0
  99. package/src/interactions/createFocusRing.ts +89 -0
  100. package/src/interactions/createFocusWithin.ts +206 -0
  101. package/src/interactions/createFocusable.ts +168 -0
  102. package/src/interactions/createHover.ts +254 -0
  103. package/src/interactions/createInteractionModality.ts +424 -0
  104. package/src/interactions/createKeyboard.ts +82 -0
  105. package/src/interactions/createLongPress.ts +174 -0
  106. package/src/interactions/createMove.ts +289 -0
  107. package/src/interactions/createPress.ts +834 -0
  108. package/src/interactions/index.ts +78 -0
  109. package/src/label/createField.ts +145 -0
  110. package/src/label/createLabel.ts +117 -0
  111. package/src/label/createLabels.ts +50 -0
  112. package/src/label/index.ts +19 -0
  113. package/src/landmark/createLandmark.ts +377 -0
  114. package/src/landmark/index.ts +8 -0
  115. package/src/link/createLink.ts +182 -0
  116. package/src/link/index.ts +1 -0
  117. package/src/listbox/createListBox.ts +269 -0
  118. package/src/listbox/createOption.ts +151 -0
  119. package/src/listbox/index.ts +12 -0
  120. package/src/live-announcer/announce.ts +322 -0
  121. package/src/live-announcer/index.ts +9 -0
  122. package/src/menu/createMenu.ts +396 -0
  123. package/src/menu/createMenuItem.ts +149 -0
  124. package/src/menu/createMenuTrigger.ts +88 -0
  125. package/src/menu/index.ts +18 -0
  126. package/src/meter/createMeter.ts +75 -0
  127. package/src/meter/index.ts +1 -0
  128. package/src/numberfield/createNumberField.ts +268 -0
  129. package/src/numberfield/index.ts +5 -0
  130. package/src/overlays/ariaHideOutside.ts +219 -0
  131. package/src/overlays/createInteractOutside.ts +149 -0
  132. package/src/overlays/createModal.tsx +202 -0
  133. package/src/overlays/createOverlay.ts +155 -0
  134. package/src/overlays/createOverlayTrigger.ts +85 -0
  135. package/src/overlays/createPreventScroll.ts +266 -0
  136. package/src/overlays/index.ts +44 -0
  137. package/src/popover/calculatePosition.ts +766 -0
  138. package/src/popover/createOverlayPosition.ts +356 -0
  139. package/src/popover/createPopover.ts +170 -0
  140. package/src/popover/index.ts +24 -0
  141. package/src/progress/createProgressBar.ts +128 -0
  142. package/src/progress/index.ts +5 -0
  143. package/src/radio/createRadio.ts +287 -0
  144. package/src/radio/createRadioGroup.ts +189 -0
  145. package/src/radio/createRadioGroupState.ts +201 -0
  146. package/src/radio/index.ts +23 -0
  147. package/src/searchfield/createSearchField.ts +186 -0
  148. package/src/searchfield/index.ts +2 -0
  149. package/src/select/createHiddenSelect.tsx +236 -0
  150. package/src/select/createSelect.ts +395 -0
  151. package/src/select/index.ts +14 -0
  152. package/src/selection/createTypeSelect.ts +201 -0
  153. package/src/selection/index.ts +6 -0
  154. package/src/separator/createSeparator.ts +82 -0
  155. package/src/separator/index.ts +6 -0
  156. package/src/slider/createSlider.ts +349 -0
  157. package/src/slider/index.ts +2 -0
  158. package/src/ssr/index.tsx +370 -0
  159. package/src/switch/createSwitch.ts +70 -0
  160. package/src/switch/index.ts +1 -0
  161. package/src/table/createTable.ts +526 -0
  162. package/src/table/createTableCell.ts +147 -0
  163. package/src/table/createTableColumnHeader.ts +115 -0
  164. package/src/table/createTableHeaderRow.ts +40 -0
  165. package/src/table/createTableRow.ts +155 -0
  166. package/src/table/createTableRowGroup.ts +32 -0
  167. package/src/table/createTableSelectAllCheckbox.ts +73 -0
  168. package/src/table/createTableSelectionCheckbox.ts +59 -0
  169. package/src/table/index.ts +30 -0
  170. package/src/table/types.ts +165 -0
  171. package/src/tabs/createTabs.ts +472 -0
  172. package/src/tabs/index.ts +14 -0
  173. package/src/tag/createTag.ts +194 -0
  174. package/src/tag/createTagGroup.ts +154 -0
  175. package/src/tag/index.ts +12 -0
  176. package/src/textfield/createTextField.ts +198 -0
  177. package/src/textfield/index.ts +5 -0
  178. package/src/toast/createToast.ts +118 -0
  179. package/src/toast/createToastRegion.ts +100 -0
  180. package/src/toast/index.ts +11 -0
  181. package/src/toggle/createToggle.ts +223 -0
  182. package/src/toggle/createToggleState.ts +94 -0
  183. package/src/toggle/index.ts +7 -0
  184. package/src/toolbar/createToolbar.ts +369 -0
  185. package/src/toolbar/index.ts +6 -0
  186. package/src/tooltip/createTooltip.ts +79 -0
  187. package/src/tooltip/createTooltipTrigger.ts +222 -0
  188. package/src/tooltip/index.ts +6 -0
  189. package/src/tree/createTree.ts +246 -0
  190. package/src/tree/createTreeItem.ts +233 -0
  191. package/src/tree/createTreeSelectionCheckbox.ts +68 -0
  192. package/src/tree/index.ts +16 -0
  193. package/src/tree/types.ts +87 -0
  194. package/src/utils/createDescription.ts +137 -0
  195. package/src/utils/dom.ts +327 -0
  196. package/src/utils/env.ts +54 -0
  197. package/src/utils/events.ts +106 -0
  198. package/src/utils/filterDOMProps.ts +116 -0
  199. package/src/utils/focus.ts +151 -0
  200. package/src/utils/geometry.ts +115 -0
  201. package/src/utils/globalListeners.ts +142 -0
  202. package/src/utils/index.ts +80 -0
  203. package/src/utils/mergeProps.ts +52 -0
  204. package/src/utils/platform.ts +52 -0
  205. package/src/utils/reactivity.ts +36 -0
  206. package/src/utils/textSelection.ts +114 -0
  207. package/src/visually-hidden/createVisuallyHidden.ts +124 -0
  208. package/src/visually-hidden/index.ts +6 -0
  209. package/dist/index.jsx +0 -15845
  210. package/dist/index.jsx.map +0 -7
@@ -0,0 +1,209 @@
1
+ /**
2
+ * createDrag - ARIA hook for drag operations.
3
+ *
4
+ * Provides accessibility props for draggable elements with support for
5
+ * mouse, touch, and keyboard interactions.
6
+ */
7
+
8
+ import { createMemo, type Accessor } from 'solid-js';
9
+ import { createDragState } from '@proyecto-viviana/solid-stately';
10
+ import type { AriaDragOptions, DragAria } from './types';
11
+ import {
12
+ writeToDataTransfer,
13
+ DROP_OPERATION,
14
+ EFFECT_ALLOWED,
15
+ DROP_EFFECT_TO_DROP_OPERATION,
16
+ setGlobalAllowedDropOperations,
17
+ setGlobalDropEffect,
18
+ getGlobalDropEffect,
19
+ } from './utils';
20
+
21
+ /**
22
+ * Creates ARIA props for a draggable element.
23
+ *
24
+ * @param props - Accessor returning drag options
25
+ * @returns Drag ARIA props and state
26
+ */
27
+ export function createDrag(props: Accessor<AriaDragOptions>): DragAria {
28
+ const getProps = createMemo(() => props());
29
+
30
+ // Create drag state
31
+ const state = createDragState(() => ({
32
+ getItems: getProps().getItems,
33
+ getAllowedDropOperations: getProps().getAllowedDropOperations,
34
+ onDragStart: getProps().onDragStart,
35
+ onDragMove: getProps().onDragMove,
36
+ onDragEnd: getProps().onDragEnd,
37
+ isDisabled: getProps().isDisabled,
38
+ hasDragButton: getProps().hasDragButton,
39
+ preview: getProps().preview,
40
+ }));
41
+
42
+ // Track position for drag move
43
+ let lastX = 0;
44
+ let lastY = 0;
45
+
46
+ const onDragStart = (e: DragEvent) => {
47
+ if (e.defaultPrevented) return;
48
+ e.stopPropagation();
49
+
50
+ const p = getProps();
51
+
52
+ // Call state handler
53
+ state.startDrag(e.clientX, e.clientY);
54
+
55
+ // Get items and write to data transfer
56
+ const items = state.getItems();
57
+ e.dataTransfer?.clearData?.();
58
+ if (e.dataTransfer) {
59
+ writeToDataTransfer(e.dataTransfer, items);
60
+ }
61
+
62
+ // Set allowed drop operations
63
+ let allowed = DROP_OPERATION.all;
64
+ const allowedOps = state.getAllowedDropOperations();
65
+ if (allowedOps.length > 0) {
66
+ allowed = DROP_OPERATION.none;
67
+ for (const op of allowedOps) {
68
+ allowed |= DROP_OPERATION[op] || DROP_OPERATION.none;
69
+ }
70
+ }
71
+
72
+ setGlobalAllowedDropOperations(allowed);
73
+ const effectAllowed = EFFECT_ALLOWED[allowed] || 'none';
74
+ if (e.dataTransfer) {
75
+ e.dataTransfer.effectAllowed =
76
+ (effectAllowed === 'cancel' ? 'none' : effectAllowed) as DataTransfer['effectAllowed'];
77
+ }
78
+
79
+ // Handle custom preview
80
+ if (typeof p.preview?.current === 'function' && e.dataTransfer) {
81
+ p.preview.current(items, (node, userX, userY) => {
82
+ if (!node || !e.dataTransfer) return;
83
+
84
+ const size = node.getBoundingClientRect();
85
+ const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
86
+ let defaultX = e.clientX - rect.x;
87
+ let defaultY = e.clientY - rect.y;
88
+
89
+ if (defaultX > size.width || defaultY > size.height) {
90
+ defaultX = size.width / 2;
91
+ defaultY = size.height / 2;
92
+ }
93
+
94
+ let offsetX = typeof userX === 'number' ? userX : defaultX;
95
+ let offsetY = typeof userY === 'number' ? userY : defaultY;
96
+
97
+ offsetX = Math.max(0, Math.min(offsetX, size.width));
98
+ offsetY = Math.max(0, Math.min(offsetY, size.height));
99
+
100
+ e.dataTransfer.setDragImage(node, offsetX, offsetY);
101
+ });
102
+ }
103
+
104
+ lastX = e.clientX;
105
+ lastY = e.clientY;
106
+ };
107
+
108
+ const onDrag = (e: DragEvent) => {
109
+ e.stopPropagation();
110
+
111
+ if (e.clientX === lastX && e.clientY === lastY) {
112
+ return;
113
+ }
114
+
115
+ state.moveDrag(e.clientX, e.clientY);
116
+
117
+ lastX = e.clientX;
118
+ lastY = e.clientY;
119
+ };
120
+
121
+ const onDragEnd = (e: DragEvent) => {
122
+ e.stopPropagation();
123
+
124
+ let dropEffect: string = e.dataTransfer?.dropEffect ?? 'none';
125
+ // Chrome Android fix - use global drop effect
126
+ if (getGlobalDropEffect()) {
127
+ dropEffect = getGlobalDropEffect()!;
128
+ }
129
+
130
+ const dropOperation = DROP_EFFECT_TO_DROP_OPERATION[dropEffect];
131
+ state.endDrag(e.clientX, e.clientY, dropOperation);
132
+
133
+ setGlobalAllowedDropOperations(DROP_OPERATION.none);
134
+ setGlobalDropEffect(undefined);
135
+ };
136
+
137
+ // Keyboard/screen reader drag initiation
138
+ const onKeyDown = (e: KeyboardEvent) => {
139
+ if (e.key === 'Enter' && e.target === e.currentTarget) {
140
+ e.preventDefault();
141
+ e.stopPropagation();
142
+ }
143
+ };
144
+
145
+ const onKeyUp = (e: KeyboardEvent) => {
146
+ if (e.key === 'Enter' && e.target === e.currentTarget) {
147
+ e.preventDefault();
148
+ e.stopPropagation();
149
+ // Would initiate keyboard-based drag mode
150
+ // This is a simplified version - full implementation needs DragManager
151
+ const rect = (e.target as HTMLElement).getBoundingClientRect();
152
+ state.startDrag(rect.x + rect.width / 2, rect.y + rect.height / 2);
153
+ }
154
+ };
155
+
156
+ const dragProps = createMemo(() => {
157
+ const p = getProps();
158
+
159
+ if (p.isDisabled) {
160
+ return {
161
+ draggable: false as const,
162
+ };
163
+ }
164
+
165
+ const baseProps: Record<string, unknown> = {
166
+ draggable: true as const,
167
+ onDragStart,
168
+ onDrag,
169
+ onDragEnd,
170
+ };
171
+
172
+ // Add keyboard handlers if no separate drag button
173
+ if (!p.hasDragButton) {
174
+ baseProps.onKeyDown = onKeyDown;
175
+ baseProps.onKeyUp = onKeyUp;
176
+ }
177
+
178
+ return baseProps;
179
+ });
180
+
181
+ const dragButtonProps = createMemo(() => {
182
+ const p = getProps();
183
+
184
+ if (p.isDisabled) {
185
+ return {
186
+ disabled: true,
187
+ };
188
+ }
189
+
190
+ return {
191
+ type: 'button' as const,
192
+ 'aria-label': 'Drag',
193
+ onKeyDown,
194
+ onKeyUp,
195
+ };
196
+ });
197
+
198
+ return {
199
+ get dragProps() {
200
+ return dragProps() as DragAria['dragProps'];
201
+ },
202
+ get dragButtonProps() {
203
+ return dragButtonProps() as DragAria['dragButtonProps'];
204
+ },
205
+ get isDragging() {
206
+ return state.isDragging;
207
+ },
208
+ };
209
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * createDraggableCollection - ARIA hook for draggable collection items.
3
+ *
4
+ * Provides accessibility support for dragging items from a collection
5
+ * component like ListBox, GridList, or Table.
6
+ */
7
+
8
+ import { createMemo, createEffect, onCleanup, type Accessor } from 'solid-js';
9
+ import type { DraggableCollectionState } from '@proyecto-viviana/solid-stately';
10
+
11
+ // Global state for tracking the dragging collection
12
+ let globalDraggingCollectionRef: HTMLElement | null = null;
13
+
14
+ export function setGlobalDraggingCollectionRef(ref: HTMLElement | null): void {
15
+ globalDraggingCollectionRef = ref;
16
+ }
17
+
18
+ export function getGlobalDraggingCollectionRef(): HTMLElement | null {
19
+ return globalDraggingCollectionRef;
20
+ }
21
+
22
+ export interface DraggableCollectionOptions {
23
+ /** Reference to the collection element. */
24
+ ref: Accessor<HTMLElement | null>;
25
+ }
26
+
27
+ export interface DraggableCollectionAria {
28
+ /** The draggable collection state. */
29
+ state: DraggableCollectionState;
30
+ }
31
+
32
+ /**
33
+ * Creates ARIA support for a draggable collection.
34
+ *
35
+ * @param _options - Collection options
36
+ * @param state - Draggable collection state
37
+ * @returns Draggable collection ARIA result
38
+ */
39
+ export function createDraggableCollection(
40
+ options: DraggableCollectionOptions,
41
+ state: DraggableCollectionState
42
+ ): DraggableCollectionAria {
43
+ const ref = createMemo(() => options.ref());
44
+
45
+ // Track dragging state globally
46
+ createEffect(() => {
47
+ const currentRef = ref();
48
+ if (state.draggingKeys.size > 0 && globalDraggingCollectionRef !== currentRef) {
49
+ setGlobalDraggingCollectionRef(currentRef);
50
+ }
51
+ });
52
+
53
+ // Clean up on unmount
54
+ onCleanup(() => {
55
+ if (globalDraggingCollectionRef === ref()) {
56
+ setGlobalDraggingCollectionRef(null);
57
+ }
58
+ });
59
+
60
+ return {
61
+ state,
62
+ };
63
+ }
@@ -0,0 +1,243 @@
1
+ /**
2
+ * createDraggableItem - ARIA hook for draggable items within a collection.
3
+ *
4
+ * Provides accessibility props for items that can be dragged from a collection.
5
+ */
6
+
7
+ import { createMemo, type Accessor } from 'solid-js';
8
+ import type { JSX } from 'solid-js';
9
+ import type {
10
+ DraggableCollectionState,
11
+ DragPreviewRenderer,
12
+ } from '@proyecto-viviana/solid-stately';
13
+ import {
14
+ writeToDataTransfer,
15
+ DROP_OPERATION,
16
+ EFFECT_ALLOWED,
17
+ DROP_EFFECT_TO_DROP_OPERATION,
18
+ setGlobalAllowedDropOperations,
19
+ setGlobalDropEffect,
20
+ getGlobalDropEffect,
21
+ } from './utils';
22
+
23
+ export interface DraggableItemOptions {
24
+ /** The unique key of the item. */
25
+ key: string | number;
26
+ /** Whether the item has a separate drag button affordance. */
27
+ hasDragButton?: boolean;
28
+ /** Whether this item is disabled for dragging. */
29
+ isDisabled?: boolean;
30
+ /** Preview renderer function ref. */
31
+ preview?: { current: DragPreviewRenderer | null };
32
+ }
33
+
34
+ export interface DraggableItemAria {
35
+ /** Props for the draggable item element. */
36
+ dragProps: JSX.HTMLAttributes<HTMLElement>;
37
+ /** Props for the explicit drag button affordance, if any. */
38
+ dragButtonProps: JSX.ButtonHTMLAttributes<HTMLButtonElement>;
39
+ /** Whether the item is currently being dragged. */
40
+ isDragging: boolean;
41
+ }
42
+
43
+ /**
44
+ * Creates ARIA props for a draggable item within a collection.
45
+ *
46
+ * @param options - Accessor returning item options
47
+ * @param state - Draggable collection state
48
+ * @returns Draggable item ARIA props
49
+ */
50
+ export function createDraggableItem(
51
+ options: Accessor<DraggableItemOptions>,
52
+ state: DraggableCollectionState
53
+ ): DraggableItemAria {
54
+ const getOptions = createMemo(() => options());
55
+
56
+ // Track position for drag move
57
+ let lastX = 0;
58
+ let lastY = 0;
59
+
60
+ const isDragging = createMemo(() => {
61
+ const key = getOptions().key;
62
+ return state.draggingKeys.has(key);
63
+ });
64
+
65
+ const getKeysForDrag = (): Set<string | number> => {
66
+ const { key } = getOptions();
67
+ // If the key is not selected, only drag that item
68
+ // If it is selected, drag all selected items
69
+ // For now, just return the single key
70
+ return new Set([key]);
71
+ };
72
+
73
+ const onDragStart = (e: DragEvent) => {
74
+ if (e.defaultPrevented) return;
75
+ e.stopPropagation();
76
+
77
+ const opts = getOptions();
78
+ if (opts.isDisabled || state.isDisabled) return;
79
+
80
+ const keys = getKeysForDrag();
81
+
82
+ // Start drag state
83
+ state.startDrag(keys, e.clientX, e.clientY);
84
+
85
+ // Get items and write to data transfer
86
+ const items = state.getItems(keys);
87
+ e.dataTransfer?.clearData?.();
88
+ if (e.dataTransfer) {
89
+ writeToDataTransfer(e.dataTransfer, items);
90
+ }
91
+
92
+ // Set allowed drop operations
93
+ let allowed = DROP_OPERATION.all;
94
+ const allowedOps = state.getAllowedDropOperations();
95
+ if (allowedOps.length > 0) {
96
+ allowed = DROP_OPERATION.none;
97
+ for (const op of allowedOps) {
98
+ allowed |= DROP_OPERATION[op] || DROP_OPERATION.none;
99
+ }
100
+ }
101
+
102
+ setGlobalAllowedDropOperations(allowed);
103
+ const effectAllowed = EFFECT_ALLOWED[allowed] || 'none';
104
+ if (e.dataTransfer) {
105
+ e.dataTransfer.effectAllowed =
106
+ (effectAllowed === 'cancel' ? 'none' : effectAllowed) as DataTransfer['effectAllowed'];
107
+ }
108
+
109
+ // Handle custom preview
110
+ if (typeof opts.preview?.current === 'function' && e.dataTransfer) {
111
+ opts.preview.current(items, (node, userX, userY) => {
112
+ if (!node || !e.dataTransfer) return;
113
+
114
+ const size = node.getBoundingClientRect();
115
+ const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
116
+ let defaultX = e.clientX - rect.x;
117
+ let defaultY = e.clientY - rect.y;
118
+
119
+ if (defaultX > size.width || defaultY > size.height) {
120
+ defaultX = size.width / 2;
121
+ defaultY = size.height / 2;
122
+ }
123
+
124
+ let offsetX = typeof userX === 'number' ? userX : defaultX;
125
+ let offsetY = typeof userY === 'number' ? userY : defaultY;
126
+
127
+ offsetX = Math.max(0, Math.min(offsetX, size.width));
128
+ offsetY = Math.max(0, Math.min(offsetY, size.height));
129
+
130
+ e.dataTransfer.setDragImage(node, offsetX, offsetY);
131
+ });
132
+ }
133
+
134
+ lastX = e.clientX;
135
+ lastY = e.clientY;
136
+ };
137
+
138
+ const onDrag = (e: DragEvent) => {
139
+ e.stopPropagation();
140
+
141
+ if (e.clientX === lastX && e.clientY === lastY) {
142
+ return;
143
+ }
144
+
145
+ state.moveDrag(e.clientX, e.clientY);
146
+
147
+ lastX = e.clientX;
148
+ lastY = e.clientY;
149
+ };
150
+
151
+ const onDragEnd = (e: DragEvent) => {
152
+ e.stopPropagation();
153
+
154
+ let dropEffect: string = e.dataTransfer?.dropEffect ?? 'none';
155
+ // Chrome Android fix - use global drop effect
156
+ if (getGlobalDropEffect()) {
157
+ dropEffect = getGlobalDropEffect()!;
158
+ }
159
+
160
+ const dropOperation = DROP_EFFECT_TO_DROP_OPERATION[dropEffect];
161
+ const isInternal = false; // Would check global state
162
+ state.endDrag(e.clientX, e.clientY, dropOperation, isInternal);
163
+
164
+ setGlobalAllowedDropOperations(DROP_OPERATION.none);
165
+ setGlobalDropEffect(undefined);
166
+ };
167
+
168
+ // Keyboard/screen reader drag initiation
169
+ const onKeyDown = (e: KeyboardEvent) => {
170
+ if (e.key === 'Enter' && e.target === e.currentTarget) {
171
+ e.preventDefault();
172
+ e.stopPropagation();
173
+ }
174
+ };
175
+
176
+ const onKeyUp = (e: KeyboardEvent) => {
177
+ if (e.key === 'Enter' && e.target === e.currentTarget) {
178
+ e.preventDefault();
179
+ e.stopPropagation();
180
+
181
+ const opts = getOptions();
182
+ if (opts.isDisabled || state.isDisabled) return;
183
+
184
+ const keys = getKeysForDrag();
185
+ const rect = (e.target as HTMLElement).getBoundingClientRect();
186
+ state.startDrag(keys, rect.x + rect.width / 2, rect.y + rect.height / 2);
187
+ }
188
+ };
189
+
190
+ const dragProps = createMemo(() => {
191
+ const opts = getOptions();
192
+
193
+ if (opts.isDisabled || state.isDisabled) {
194
+ return {
195
+ draggable: false as const,
196
+ };
197
+ }
198
+
199
+ const baseProps: Record<string, unknown> = {
200
+ draggable: true as const,
201
+ onDragStart,
202
+ onDrag,
203
+ onDragEnd,
204
+ };
205
+
206
+ // Add keyboard handlers if no separate drag button
207
+ if (!opts.hasDragButton) {
208
+ baseProps.onKeyDown = onKeyDown;
209
+ baseProps.onKeyUp = onKeyUp;
210
+ }
211
+
212
+ return baseProps;
213
+ });
214
+
215
+ const dragButtonProps = createMemo(() => {
216
+ const opts = getOptions();
217
+
218
+ if (opts.isDisabled || state.isDisabled) {
219
+ return {
220
+ disabled: true,
221
+ };
222
+ }
223
+
224
+ return {
225
+ type: 'button' as const,
226
+ 'aria-label': 'Drag',
227
+ onKeyDown,
228
+ onKeyUp,
229
+ };
230
+ });
231
+
232
+ return {
233
+ get dragProps() {
234
+ return dragProps() as DraggableItemAria['dragProps'];
235
+ },
236
+ get dragButtonProps() {
237
+ return dragButtonProps() as DraggableItemAria['dragButtonProps'];
238
+ },
239
+ get isDragging() {
240
+ return isDragging();
241
+ },
242
+ };
243
+ }