@hkdigital/lib-sveltekit 0.2.6 → 0.2.8

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 (243) hide show
  1. package/README.md +135 -135
  2. package/dist/assets/autospuiten/car-paint-picker.js +41 -41
  3. package/dist/assets/autospuiten/labels.js +7 -7
  4. package/dist/classes/cache/IndexedDbCache.js +1407 -1407
  5. package/dist/classes/cache/MemoryResponseCache.js +138 -138
  6. package/dist/classes/cache/index.js +5 -5
  7. package/dist/classes/cache/typedef.js +41 -41
  8. package/dist/classes/data/IterableTree.js +243 -243
  9. package/dist/classes/data/Selector.js +190 -190
  10. package/dist/classes/data/index.js +2 -2
  11. package/dist/classes/events/EventEmitter.js +275 -275
  12. package/dist/classes/events/index.js +2 -2
  13. package/dist/classes/index.js +4 -4
  14. package/dist/classes/logging/Logger.js +158 -158
  15. package/dist/classes/logging/constants.js +18 -18
  16. package/dist/classes/logging/index.js +4 -4
  17. package/dist/classes/promise/HkPromise.js +377 -377
  18. package/dist/classes/promise/index.js +1 -1
  19. package/dist/classes/services/ServiceBase.js +409 -409
  20. package/dist/classes/services/ServiceManager.js +1114 -1114
  21. package/dist/classes/services/constants.js +12 -12
  22. package/dist/classes/services/index.js +5 -5
  23. package/dist/classes/stores/SubscribersCount.js +107 -107
  24. package/dist/classes/stores/index.js +1 -1
  25. package/dist/classes/streams/LogTransformStream.js +19 -19
  26. package/dist/classes/streams/ServerEventsStore.js +110 -110
  27. package/dist/classes/streams/TimeStampSource.js +26 -26
  28. package/dist/classes/streams/index.js +3 -3
  29. package/dist/classes/svelte/audio/AudioLoader.svelte.js +58 -58
  30. package/dist/classes/svelte/audio/AudioScene.svelte.js +324 -324
  31. package/dist/classes/svelte/audio/mocks.js +35 -35
  32. package/dist/classes/svelte/finite-state-machine/FiniteStateMachine.svelte.js +133 -133
  33. package/dist/classes/svelte/finite-state-machine/index.js +1 -1
  34. package/dist/classes/svelte/image/ImageLoader.svelte.js +45 -45
  35. package/dist/classes/svelte/image/ImageScene.svelte.js +249 -249
  36. package/dist/classes/svelte/image/ImageVariantsLoader.svelte.js +152 -152
  37. package/dist/classes/svelte/image/index.js +4 -4
  38. package/dist/classes/svelte/image/mocks.js +35 -35
  39. package/dist/classes/svelte/image/typedef.js +8 -8
  40. package/dist/classes/svelte/index.js +14 -14
  41. package/dist/classes/svelte/loading-state-machine/LoadingStateMachine.svelte.js +109 -109
  42. package/dist/classes/svelte/loading-state-machine/constants.js +16 -16
  43. package/dist/classes/svelte/loading-state-machine/index.js +3 -3
  44. package/dist/classes/svelte/network-loader/NetworkLoader.svelte.js +338 -338
  45. package/dist/classes/svelte/network-loader/constants.js +3 -3
  46. package/dist/classes/svelte/network-loader/index.js +3 -3
  47. package/dist/classes/svelte/network-loader/mocks.js +30 -30
  48. package/dist/classes/svelte/network-loader/typedef.js +8 -8
  49. package/dist/components/area/HkArea.svelte +49 -49
  50. package/dist/components/area/HkGridArea.svelte +77 -77
  51. package/dist/components/area/index.js +2 -2
  52. package/dist/components/buttons/button/Button.svelte +82 -82
  53. package/dist/components/buttons/button-icon-steeze/SteezeIconButton.svelte +30 -30
  54. package/dist/components/buttons/button-text/TextButton.svelte +21 -21
  55. package/dist/components/buttons/index.js +3 -3
  56. package/dist/components/debug/debug-panel-design-scaling/DebugPanelDesignScaling.svelte +146 -146
  57. package/dist/components/debug/index.js +1 -1
  58. package/dist/components/drag-drop/DragController.d.ts +0 -20
  59. package/dist/components/drag-drop/DragController.js +44 -113
  60. package/dist/components/drag-drop/DragDropContext.svelte +110 -103
  61. package/dist/components/drag-drop/Draggable.svelte +512 -492
  62. package/dist/components/drag-drop/Draggable.svelte.d.ts +8 -2
  63. package/dist/components/drag-drop/DropZoneArea.svelte +119 -119
  64. package/dist/components/drag-drop/DropZoneList.svelte +125 -125
  65. package/dist/components/drag-drop/{DropZone.svelte → Dropzone.svelte} +258 -258
  66. package/dist/components/drag-drop/drag-state.svelte.js +319 -323
  67. package/dist/components/drag-drop/index.js +7 -7
  68. package/dist/components/drag-drop/util.js +85 -85
  69. package/dist/components/hkdev/blocks/TextBlock.svelte +46 -46
  70. package/dist/components/hkdev/buttons/CheckButton.svelte +62 -62
  71. package/dist/components/icons/HkIcon.svelte +86 -86
  72. package/dist/components/icons/HkTabIcon.svelte +116 -116
  73. package/dist/components/icons/SteezeIcon.svelte +97 -97
  74. package/dist/components/icons/index.js +6 -6
  75. package/dist/components/icons/typedef.js +16 -16
  76. package/dist/components/index.js +2 -2
  77. package/dist/components/inputs/index.js +1 -1
  78. package/dist/components/inputs/text-input/TestTextInput.svelte__ +102 -102
  79. package/dist/components/inputs/text-input/TextInput.svelte +223 -223
  80. package/dist/components/inputs/text-input/TextInput.svelte___ +83 -83
  81. package/dist/components/inputs/text-input/assets/IconInvalid.svelte +14 -14
  82. package/dist/components/inputs/text-input/assets/IconValid.svelte +12 -12
  83. package/dist/components/layout/grid-layers/GridLayers.svelte +63 -63
  84. package/dist/components/layout/grid-layers/util.js +74 -74
  85. package/dist/components/layout/index.js +1 -1
  86. package/dist/components/panels/index.js +1 -1
  87. package/dist/components/panels/panel/Panel.svelte +43 -43
  88. package/dist/components/rows/index.js +3 -3
  89. package/dist/components/rows/panel-grid-row/PanelGridRow.svelte +104 -104
  90. package/dist/components/rows/panel-row-2/PanelRow2.svelte +40 -40
  91. package/dist/components/tab-bar/HkTabBar.state.svelte.js +149 -149
  92. package/dist/components/tab-bar/HkTabBar.svelte +74 -74
  93. package/dist/components/tab-bar/HkTabBarSelector.state.svelte.js +93 -93
  94. package/dist/components/tab-bar/HkTabBarSelector.svelte +49 -49
  95. package/dist/components/tab-bar/index.js +17 -17
  96. package/dist/components/tab-bar/typedef.js +11 -11
  97. package/dist/config/imagetools-config.js +189 -189
  98. package/dist/config/imagetools.d.ts +72 -72
  99. package/dist/constants/bases.js +13 -13
  100. package/dist/constants/errors/api.js +9 -9
  101. package/dist/constants/errors/generic.js +5 -5
  102. package/dist/constants/errors/index.js +3 -3
  103. package/dist/constants/errors/jwt.js +5 -5
  104. package/dist/constants/http/headers.js +6 -6
  105. package/dist/constants/http/index.js +2 -2
  106. package/dist/constants/http/methods.js +2 -2
  107. package/dist/constants/index.js +3 -3
  108. package/dist/constants/mime/application.js +5 -5
  109. package/dist/constants/mime/audio.js +13 -13
  110. package/dist/constants/mime/image.js +3 -3
  111. package/dist/constants/mime/index.js +4 -4
  112. package/dist/constants/mime/text.js +2 -2
  113. package/dist/constants/regexp/index.js +31 -31
  114. package/dist/constants/regexp/inspiratie.js__ +95 -95
  115. package/dist/constants/regexp/text.js +49 -49
  116. package/dist/constants/regexp/user.js +32 -32
  117. package/dist/constants/regexp/web.js +3 -3
  118. package/dist/constants/state-labels/drag-states.js +6 -6
  119. package/dist/constants/state-labels/drop-states.js +6 -6
  120. package/dist/constants/state-labels/input-states.js +11 -11
  121. package/dist/constants/state-labels/submit-states.js +4 -4
  122. package/dist/constants/time.js +28 -28
  123. package/dist/css/utilities.css +43 -43
  124. package/dist/design/design-config.js +73 -73
  125. package/dist/design/tailwind-theme-extend.js +158 -158
  126. package/dist/features/button-group/ButtonGroup.svelte +82 -82
  127. package/dist/features/button-group/typedef.js +10 -10
  128. package/dist/features/compare-left-right/CompareLeftRight.svelte +179 -179
  129. package/dist/features/compare-left-right/index.js +1 -1
  130. package/dist/features/game-box/GameBox.svelte +577 -577
  131. package/dist/features/game-box/gamebox.util.js +83 -83
  132. package/dist/features/hk-app-layout/HkAppLayout.state.svelte.js +25 -25
  133. package/dist/features/hk-app-layout/HkAppLayout.svelte +251 -251
  134. package/dist/features/image-box/ImageBox.svelte +210 -210
  135. package/dist/features/image-box/index.js +5 -5
  136. package/dist/features/image-box/typedef.js +32 -32
  137. package/dist/features/index.js +23 -23
  138. package/dist/features/presenter/ImageSlide.svelte +64 -64
  139. package/dist/features/presenter/Presenter.state.svelte.js +638 -638
  140. package/dist/features/presenter/Presenter.svelte +142 -142
  141. package/dist/features/presenter/constants.js +7 -7
  142. package/dist/features/presenter/index.js +10 -10
  143. package/dist/features/presenter/typedef.js +106 -106
  144. package/dist/features/presenter/util.js +210 -210
  145. package/dist/features/virtual-viewport/VirtualViewport.svelte +196 -196
  146. package/dist/schemas/index.js +1 -1
  147. package/dist/schemas/validate-url.js +180 -180
  148. package/dist/server/index.js +1 -1
  149. package/dist/server/logger.js +94 -94
  150. package/dist/states/index.js +1 -1
  151. package/dist/states/navigation.svelte.js +55 -55
  152. package/dist/stores/index.js +1 -1
  153. package/dist/stores/theme.js +80 -80
  154. package/dist/themes/hkdev/components/blocks/text-block.css +41 -41
  155. package/dist/themes/hkdev/components/boxes/game-box.css +12 -12
  156. package/dist/themes/hkdev/components/buttons/button-icon-steeze.css +22 -22
  157. package/dist/themes/hkdev/components/buttons/button-text.css +32 -32
  158. package/dist/themes/hkdev/components/buttons/button.css +146 -146
  159. package/dist/themes/hkdev/components/buttons/skip-button.css +6 -6
  160. package/dist/themes/hkdev/components/drag-drop/draggable.css +73 -73
  161. package/dist/themes/hkdev/components/drag-drop/drop-zone.css +48 -48
  162. package/dist/themes/hkdev/components/icons/icon-steeze.css +22 -22
  163. package/dist/themes/hkdev/components/inputs/text-input.css +104 -104
  164. package/dist/themes/hkdev/components/panels/panel.css +27 -27
  165. package/dist/themes/hkdev/components/rows/panel-grid-row.css +6 -6
  166. package/dist/themes/hkdev/components/rows/panel-row-2.css +7 -7
  167. package/dist/themes/hkdev/components.css +53 -53
  168. package/dist/themes/hkdev/debug.css +1 -1
  169. package/dist/themes/hkdev/global/layout.css +39 -39
  170. package/dist/themes/hkdev/global/on-colors.css +53 -53
  171. package/dist/themes/hkdev/globals.css +11 -11
  172. package/dist/themes/hkdev/responsive.css +12 -12
  173. package/dist/themes/hkdev/theme-ext.js +15 -15
  174. package/dist/themes/hkdev/theme.js +235 -235
  175. package/dist/themes/index.js +1 -1
  176. package/dist/typedef/context.js +6 -6
  177. package/dist/typedef/drag.js +25 -25
  178. package/dist/typedef/drop.js +12 -12
  179. package/dist/typedef/image.js +38 -38
  180. package/dist/typedef/index.js +4 -4
  181. package/dist/util/array/index.js +436 -436
  182. package/dist/util/bases/base58.js +262 -262
  183. package/dist/util/bases/index.js +1 -1
  184. package/dist/util/compare/index.js +247 -247
  185. package/dist/util/css/css-vars.js +83 -83
  186. package/dist/util/css/index.js +1 -1
  187. package/dist/util/design-system/components/states.js +22 -22
  188. package/dist/util/design-system/css/clamp.js +66 -66
  189. package/dist/util/design-system/css/root-design-vars.js +102 -102
  190. package/dist/util/design-system/index.js +5 -5
  191. package/dist/util/design-system/layout/scaling.js +228 -228
  192. package/dist/util/design-system/skeleton.js +208 -208
  193. package/dist/util/design-system/tailwind.js +288 -288
  194. package/dist/util/env/index.js +9 -9
  195. package/dist/util/expect/arrays.js +47 -47
  196. package/dist/util/expect/index.js +259 -259
  197. package/dist/util/expect/primitives.js +55 -55
  198. package/dist/util/expect/url.js +60 -60
  199. package/dist/util/function/index.js +218 -218
  200. package/dist/util/geo/index.js +26 -26
  201. package/dist/util/http/caching.js +263 -263
  202. package/dist/util/http/errors.js +97 -97
  203. package/dist/util/http/headers.js +75 -75
  204. package/dist/util/http/http-request.js +379 -379
  205. package/dist/util/http/index.js +22 -22
  206. package/dist/util/http/json-request.js +224 -224
  207. package/dist/util/http/mocks.js +65 -65
  208. package/dist/util/http/response.js +294 -294
  209. package/dist/util/http/typedef.js +93 -93
  210. package/dist/util/http/url.js +52 -52
  211. package/dist/util/image/index.js +86 -86
  212. package/dist/util/index.js +2 -2
  213. package/dist/util/is/index.js +140 -140
  214. package/dist/util/iterate/index.js +234 -234
  215. package/dist/util/object/index.js +1361 -1361
  216. package/dist/util/singleton/index.js +97 -97
  217. package/dist/util/string/array-path.js +75 -75
  218. package/dist/util/string/convert.js +54 -54
  219. package/dist/util/string/fs.js +226 -226
  220. package/dist/util/string/index.js +5 -5
  221. package/dist/util/string/interpolate.js +61 -61
  222. package/dist/util/string/pad.js +10 -10
  223. package/dist/util/svelte/index.js +4 -4
  224. package/dist/util/svelte/loading/loading-tracker.svelte.js +108 -108
  225. package/dist/util/svelte/observe/index.js +49 -49
  226. package/dist/util/svelte/state-context/index.js +117 -117
  227. package/dist/util/svelte/wait/index.js +38 -38
  228. package/dist/util/sveltekit/index.js +1 -1
  229. package/dist/util/sveltekit/route-folders/index.js +101 -101
  230. package/dist/util/time/index.js +323 -323
  231. package/dist/util/unique/index.js +249 -249
  232. package/dist/valibot/date.js__ +10 -10
  233. package/dist/valibot/index.js +9 -9
  234. package/dist/valibot/url.js +95 -95
  235. package/dist/valibot/user.js +23 -23
  236. package/dist/zod/all.js +33 -33
  237. package/dist/zod/generic.js +11 -11
  238. package/dist/zod/javascript.js +32 -32
  239. package/dist/zod/user.js +16 -16
  240. package/dist/zod/web.js +52 -52
  241. package/package.json +112 -112
  242. package/dist/components/layout/grid-layers/GridLayers.svelte__heightFrom__ +0 -372
  243. package/dist/util/http/test-data__/content-length-test-hkdigital-small.V4HfZyBQ.avif +0 -0
@@ -1,492 +1,512 @@
1
- <script>
2
- import { toStateClasses } from '../../util/design-system/index.js';
3
- import { createOrGetDragState } from './drag-state.svelte.js';
4
- import { DragController } from './DragController.js';
5
- import { generateLocalId } from '../../util/unique';
6
- import { onDestroy } from 'svelte';
7
- import {
8
- IDLE,
9
- DRAGGING,
10
- DRAG_PREVIEW,
11
- DROPPING
12
- } from '../../constants/state-labels/drag-states.js';
13
-
14
-
15
- /** @typedef {import('../../typedef').SimulatedDragEvent} SimulatedDragEvent */
16
-
17
- /**
18
- * @type {{
19
- * item: any,
20
- * group?: string,
21
- * source?: string,
22
- * disabled?: boolean,
23
- * dragDelay?: number,
24
- * base?: string,
25
- * classes?: string,
26
- * children: import('svelte').Snippet,
27
- * draggingSnippet?: import('svelte').Snippet<[{
28
- * element: HTMLElement,
29
- * rect: DOMRect
30
- * }]>,
31
- * contextKey?: import('../../typedef').ContextKey,
32
- * isDragging?: boolean,
33
- * isDropping?: boolean,
34
- * isDragPreview?: boolean,
35
- * onDragStart?: (detail: {
36
- * event: DragEvent,
37
- * item: any,
38
- * source: string,
39
- * group: string,
40
- * getController: () => DragController
41
- * }) => void,
42
- * onDragging?: (detail: {
43
- * event: DragEvent,
44
- * item: any
45
- * }) => void,
46
- * onDragEnd?: (detail: {
47
- * event: DragEvent,
48
- * item: any,
49
- * wasDropped: boolean
50
- * }) => void,
51
- * onDrop?: (detail: {
52
- * event: DragEvent,
53
- * item: any,
54
- * wasDropped: boolean
55
- * }) => void,
56
- * canDrag?: (item: any) => boolean,
57
- * [key: string]: any
58
- * }}
59
- */
60
- let {
61
- item,
62
- group = 'default',
63
- source = 'default',
64
- disabled = false,
65
- dragDelay = 0,
66
- base = '',
67
- classes = '',
68
- children,
69
- draggingSnippet,
70
- contextKey,
71
- isDragging = $bindable(false),
72
- isDropping = $bindable(false),
73
- isDragPreview = $bindable(false),
74
- onDragStart,
75
- onDragging,
76
- onDragEnd,
77
- onDrop,
78
- canDrag = () => true,
79
- ...attrs
80
- } = $props();
81
-
82
- const dragState = createOrGetDragState(contextKey);
83
-
84
- const draggableId = generateLocalId();
85
-
86
- // svelte-ignore non_reactive_update
87
- let draggableElement;
88
-
89
- let dragTimeout = null;
90
- let currentState = $state(IDLE);
91
-
92
- // Custom preview follower state
93
- let showPreview = $state(false);
94
- let previewX = $state(0);
95
- let previewY = $state(0);
96
- let dragOffsetX = $state(0);
97
- let dragOffsetY = $state(0);
98
- let customPreviewSet = $state(false);
99
- let elementRect = $state(null);
100
-
101
- // Track if current draggable can drop in the active zone
102
- let canDropInActiveZone = $derived.by(() => {
103
- if (currentState !== DRAGGING || !dragState.activeDropZone) return false;
104
-
105
- const activeZone = dragState.dropZones.get(dragState.activeDropZone);
106
- return activeZone?.canDrop || false;
107
- });
108
-
109
- // Computed state object for CSS classes
110
- let stateObject = $derived({
111
- idle: currentState === IDLE,
112
- dragging: currentState === DRAGGING,
113
- 'drag-preview': currentState === DRAG_PREVIEW,
114
- dropping: currentState === DROPPING,
115
- 'drag-disabled': disabled || !canDrag(item),
116
- 'can-drop': currentState === DRAGGING && canDropInActiveZone,
117
- 'cannot-drop': currentState === DRAGGING && dragState.activeDropZone && !canDropInActiveZone
118
- });
119
-
120
- let stateClasses = $derived(toStateClasses(stateObject));
121
-
122
- // Update bindable props
123
- $effect(() => {
124
- isDragging = currentState === DRAGGING;
125
- isDropping = currentState === DROPPING;
126
- isDragPreview = currentState === DRAG_PREVIEW;
127
- });
128
-
129
- // Clean up on component destroy
130
- onDestroy(() => {
131
- if (showPreview) {
132
- document.removeEventListener('dragover', handleDocumentDragOver);
133
- }
134
- });
135
-
136
- /**
137
- * Handle document level dragover to ensure we get position updates
138
- * @param {DragEvent} event
139
- */
140
- function handleDocumentDragOver(event) {
141
- if (showPreview && currentState === DRAGGING) {
142
- // Update position for the custom preview
143
- previewX = event.clientX - dragOffsetX;
144
- previewY = event.clientY - dragOffsetY;
145
-
146
- // Prevent default to allow drop
147
- event.preventDefault();
148
- }
149
- }
150
-
151
- /**
152
- * Handle drag start
153
- * @param {DragEvent} event
154
- */
155
- function handleDragStart(event) {
156
- if (disabled || !canDrag(item)) {
157
- event.preventDefault();
158
- return;
159
- }
160
-
161
- // Handle drag delay
162
- if (dragDelay > 0) {
163
- event.preventDefault();
164
- currentState = DRAG_PREVIEW;
165
-
166
- dragTimeout = setTimeout(() => {
167
- currentState = DRAGGING;
168
- startDrag(event);
169
- }, dragDelay);
170
- return;
171
- }
172
-
173
- currentState = DRAGGING;
174
- startDrag(event);
175
- }
176
-
177
- /**
178
- * Start the drag operation
179
- * @param {DragEvent} event - The drag event
180
- */
181
- function startDrag(event) {
182
- // Get the element's bounding rectangle
183
- const rect = draggableElement.getBoundingClientRect();
184
-
185
- // Calculate grab offsets - this is where the user grabbed the element
186
- dragOffsetX = event.clientX - rect.left;
187
- dragOffsetY = event.clientY - rect.top;
188
-
189
- // Create drag data with draggableId included
190
- const dragData = {
191
- draggableId,
192
- offsetX: dragOffsetX,
193
- offsetY: dragOffsetY,
194
- item,
195
- source,
196
- group
197
- };
198
-
199
- // Set shared drag state
200
- dragState.start(draggableId, dragData);
201
-
202
- // Set minimal data transfer for browser drag and drop API
203
- event.dataTransfer.effectAllowed = 'move';
204
- event.dataTransfer.setData(
205
- 'application/json',
206
- JSON.stringify({ draggableId })
207
- );
208
-
209
- // Create the preview controller
210
- const previewController = new DragController(event);
211
-
212
- // Function to get the preview controller
213
- const getController = () => previewController;
214
-
215
- // Call onDragStart with the getController function
216
- onDragStart?.({ event, item, source, group, getController });
217
-
218
- // Apply drag preview if available
219
- if (draggingSnippet && !previewController.hasCustomPreview()) {
220
- try {
221
- // Store rectangle information for the snippet
222
- elementRect = rect;
223
-
224
- // These offsets represent where the user grabbed the element relative to its top-left corner
225
- dragOffsetX = event.clientX - rect.left;
226
- dragOffsetY = event.clientY - rect.top;
227
-
228
- // Set initial position - this places the preview at the element's original position
229
- previewX = rect.left;
230
- previewY = rect.top;
231
-
232
- // Set a transparent 1x1 pixel image to hide browser's default preview
233
- const emptyImg = new Image();
234
- emptyImg.src =
235
- 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
236
- event.dataTransfer.setDragImage(emptyImg, 0, 0);
237
-
238
- // Add document level event listener to track mouse movement
239
- document.addEventListener('dragover', handleDocumentDragOver);
240
-
241
- // Show custom preview
242
- showPreview = true;
243
- customPreviewSet = true;
244
- } catch (err) {
245
- console.error('Error setting up custom preview:', err);
246
- // Fallback to default preview
247
- previewController.applyDefaultPreview();
248
- }
249
- } else if (!previewController.hasCustomPreview()) {
250
- // Apply default preview if no custom preview was set
251
- previewController.applyDefaultPreview();
252
- }
253
- }
254
-
255
- /**
256
- * Handle during drag
257
- * @param {DragEvent} event
258
- */
259
- function handleDrag(event) {
260
- if (currentState === DRAGGING) {
261
- onDragging?.({ event, item });
262
- }
263
- }
264
-
265
- /**
266
- * Handle drag end
267
- * @param {DragEvent} event
268
- */
269
- function handleDragEnd(event) {
270
- clearTimeout(dragTimeout);
271
-
272
- // Clear global drag state
273
- dragState.end(draggableId);
274
-
275
- // Clean up document event listener
276
- if (customPreviewSet) {
277
- document.removeEventListener('dragover', handleDocumentDragOver);
278
- showPreview = false;
279
- customPreviewSet = false;
280
- elementRect = null;
281
- }
282
-
283
- // Check if drop was successful
284
- const wasDropped = event.dataTransfer.dropEffect !== 'none';
285
-
286
- if (wasDropped) {
287
- currentState = DROPPING;
288
- onDrop?.({ event, item, wasDropped: true });
289
-
290
- // Brief dropping state before returning to idle
291
- setTimeout(() => {
292
- currentState = IDLE;
293
- }, 100);
294
- } else {
295
- currentState = IDLE;
296
- }
297
-
298
- onDragEnd?.({ event, item, wasDropped });
299
- }
300
-
301
- /**
302
- * Handle mouse down for drag delay
303
- * @param {MouseEvent} event
304
- */
305
- function handleMouseDown(event) {
306
- if (dragDelay > 0 && !disabled && canDrag(item)) {
307
- // Could add visual feedback here
308
- }
309
- }
310
-
311
- /**
312
- * Handle mouse up to cancel drag delay
313
- * @param {MouseEvent} event
314
- */
315
- function handleMouseUp(event) {
316
- if (dragTimeout) {
317
- clearTimeout(dragTimeout);
318
- currentState = IDLE;
319
- }
320
- }
321
-
322
- // Add these variables for touch handling
323
- let touchDragging = $state(false);
324
- let touchStartX = 0;
325
- let touchStartY = 0;
326
- let touchPreviewElement = null;
327
-
328
- /**
329
- * Handle touch start
330
- * @param {TouchEvent} event
331
- */
332
- function handleTouchStart(event) {
333
- if (disabled || !canDrag(item)) return;
334
-
335
- const touch = event.touches[0];
336
- touchStartX = touch.clientX;
337
- touchStartY = touch.clientY;
338
-
339
- // Start drag after a small delay to distinguish from scrolling
340
- dragTimeout = setTimeout(() => {
341
- touchDragging = true;
342
- currentState = DRAGGING;
343
-
344
- // Create drag data
345
- const rect = draggableElement.getBoundingClientRect();
346
- dragOffsetX = touch.clientX - rect.left;
347
- dragOffsetY = touch.clientY - rect.top;
348
-
349
- const dragData = {
350
- draggableId,
351
- offsetX: dragOffsetX,
352
- offsetY: dragOffsetY,
353
- item,
354
- source,
355
- group
356
- };
357
-
358
- dragState.start(draggableId, dragData);
359
-
360
- // Show preview
361
- if (draggingSnippet) {
362
- elementRect = rect;
363
- previewX = rect.left;
364
- previewY = rect.top;
365
- showPreview = true;
366
- }
367
-
368
- // Prevent scrolling while dragging
369
- event.preventDefault();
370
-
371
- // Add document-level touch handlers
372
- document.addEventListener('touchmove', handleTouchMove, {
373
- passive: false
374
- });
375
- document.addEventListener('touchend', handleTouchEnd);
376
- }, 150); // 150ms delay to distinguish from scrolling
377
- }
378
-
379
- /**
380
- * Handle touch move
381
- * @param {TouchEvent} event
382
- */
383
- function handleTouchMove(event) {
384
- if (!touchDragging) return;
385
-
386
- event.preventDefault();
387
- const touch = event.touches[0];
388
-
389
- // Update preview position
390
- if (showPreview) {
391
- previewX = touch.clientX - dragOffsetX;
392
- previewY = touch.clientY - dragOffsetY;
393
- }
394
-
395
- /** @type {SimulatedDragEvent} */
396
- const simulatedEvent = {
397
- type: 'dragover',
398
- clientX: touch.clientX,
399
- clientY: touch.clientY,
400
- dataTransfer: {
401
- types: ['application/json'],
402
- getData: () => JSON.stringify({ draggableId }),
403
- dropEffect: 'move',
404
- effectAllowed: 'move',
405
- files: []
406
- },
407
- preventDefault: () => {},
408
- stopPropagation: () => {}
409
- };
410
-
411
- // Update active dropzone in drag state
412
- dragState.updateActiveDropZone(touch.clientX, touch.clientY, simulatedEvent);
413
- }
414
-
415
- /**
416
- * Handle touch end
417
- * @param {TouchEvent} event
418
- */
419
- function handleTouchEnd(event) {
420
- clearTimeout(dragTimeout);
421
-
422
- if (!touchDragging) return;
423
-
424
- const touch = event.changedTouches[0];
425
-
426
- /** @type {SimulatedDragEvent} */
427
- const simulatedEvent = {
428
- type: 'drop',
429
- clientX: touch.clientX,
430
- clientY: touch.clientY,
431
- dataTransfer: {
432
- types: ['application/json'],
433
- getData: () => JSON.stringify({ draggableId }),
434
- dropEffect: 'move',
435
- effectAllowed: 'move',
436
- files: []
437
- },
438
- preventDefault: () => {}, // Add this!
439
- stopPropagation: () => {} // And this!
440
- };
441
-
442
- // Trigger drop at final touch position
443
- dragState.handleDropAtPoint(touch.clientX, touch.clientY, simulatedEvent);
444
-
445
- // Clean up
446
- touchDragging = false;
447
- currentState = IDLE;
448
- showPreview = false;
449
- dragState.end(draggableId);
450
-
451
- // Remove document handlers
452
- document.removeEventListener('touchmove', handleTouchMove);
453
- document.removeEventListener('touchend', handleTouchEnd);
454
- }
455
- </script>
456
-
457
- <div
458
- data-component="draggable"
459
- bind:this={draggableElement}
460
- draggable={!disabled && canDrag(item)}
461
- ondragstart={handleDragStart}
462
- ondrag={handleDrag}
463
- ondragend={handleDragEnd}
464
- onmousedown={handleMouseDown}
465
- onmouseup={handleMouseUp}
466
- ontouchstart={handleTouchStart}
467
- class="{base} {classes} {stateClasses}"
468
- style="touch-action: none;"
469
- {...attrs}
470
- >
471
- {@render children()}
472
- </div>
473
-
474
- {#if draggingSnippet && showPreview && elementRect}
475
- <div
476
- data-companion="drag-preview-follower"
477
- class={stateClasses}
478
- style="position: fixed; z-index: 9999; pointer-events: none;"
479
- style:left="{previewX}px"
480
- style:top="{previewY}px"
481
- >
482
- {@render draggingSnippet({ element: draggableElement, rect: elementRect })}
483
- </div>
484
- {/if}
485
-
486
- <style>
487
- [data-component='draggable'] {
488
- -webkit-touch-callout: none;
489
- -webkit-user-select: none;
490
- user-select: none;
491
- }
492
- </style>
1
+ <script>
2
+ import { toStateClasses } from '../../util/design-system/index.js';
3
+ import { createOrGetDragState } from './drag-state.svelte.js';
4
+ import { DragController } from './DragController.js';
5
+ import { generateLocalId } from '../../util/unique';
6
+ import { onDestroy } from 'svelte';
7
+ import {
8
+ IDLE,
9
+ DRAGGING,
10
+ DRAG_PREVIEW,
11
+ DROPPING
12
+ } from '../../constants/state-labels/drag-states.js';
13
+
14
+
15
+ /** @typedef {import('../../typedef').SimulatedDragEvent} SimulatedDragEvent */
16
+
17
+ /**
18
+ * @type {{
19
+ * item: any,
20
+ * group?: string,
21
+ * source?: string,
22
+ * disabled?: boolean,
23
+ * dragDelay?: number,
24
+ * base?: string,
25
+ * classes?: string,
26
+ * children: import('svelte').Snippet<[{
27
+ * element: HTMLElement,
28
+ * rect: DOMRect
29
+ * }]>,
30
+ * draggingSnippet?: import('svelte').Snippet<[{
31
+ * element: HTMLElement,
32
+ * rect: DOMRect
33
+ * }]>,
34
+ * contextKey?: import('../../typedef').ContextKey,
35
+ * isDragging?: boolean,
36
+ * isDropping?: boolean,
37
+ * isDragPreview?: boolean,
38
+ * onDragStart?: (detail: {
39
+ * event: DragEvent,
40
+ * item: any,
41
+ * source: string,
42
+ * group: string,
43
+ * getController: () => DragController
44
+ * }) => void,
45
+ * onDragging?: (detail: {
46
+ * event: DragEvent,
47
+ * item: any
48
+ * }) => void,
49
+ * onDragEnd?: (detail: {
50
+ * event: DragEvent,
51
+ * item: any,
52
+ * wasDropped: boolean
53
+ * }) => void,
54
+ * onDrop?: (detail: {
55
+ * event: DragEvent,
56
+ * item: any,
57
+ * wasDropped: boolean
58
+ * }) => void,
59
+ * canDrag?: (item: any) => boolean,
60
+ * [key: string]: any
61
+ * }}
62
+ */
63
+ let {
64
+ item,
65
+ group = 'default',
66
+ source = 'default',
67
+ disabled = false,
68
+ dragDelay = 0,
69
+ base = '',
70
+ classes = '',
71
+ children,
72
+ draggingSnippet,
73
+ contextKey,
74
+ isDragging = $bindable(false),
75
+ isDropping = $bindable(false),
76
+ isDragPreview = $bindable(false),
77
+ onDragStart,
78
+ onDragging,
79
+ onDragEnd,
80
+ onDrop,
81
+ canDrag = () => true,
82
+ ...attrs
83
+ } = $props();
84
+
85
+ const dragState = createOrGetDragState(contextKey);
86
+
87
+ const draggableId = generateLocalId();
88
+
89
+ // svelte-ignore non_reactive_update
90
+ let draggableElement;
91
+
92
+ let dragTimeout = null;
93
+ let currentState = $state(IDLE);
94
+
95
+ // Custom preview follower state
96
+ let showPreview = $state(false);
97
+ let previewX = $state(0);
98
+ let previewY = $state(0);
99
+ let dragOffsetX = $state(0);
100
+ let dragOffsetY = $state(0);
101
+ let customPreviewSet = $state(false);
102
+ let elementRect = $state(null);
103
+
104
+ // Track if current draggable can drop in the active zone
105
+ let canDropInActiveZone = $derived.by(() => {
106
+ if (currentState !== DRAGGING || !dragState.activeDropZone) return false;
107
+
108
+ const activeZone = dragState.dropZones.get(dragState.activeDropZone);
109
+ return activeZone?.canDrop || false;
110
+ });
111
+
112
+ // Computed state object for CSS classes
113
+ let stateObject = $derived({
114
+ idle: currentState === IDLE,
115
+ dragging: currentState === DRAGGING,
116
+ 'drag-preview': currentState === DRAG_PREVIEW,
117
+ dropping: currentState === DROPPING,
118
+ 'drag-disabled': disabled || !canDrag(item),
119
+ 'can-drop': currentState === DRAGGING && canDropInActiveZone,
120
+ 'cannot-drop': currentState === DRAGGING && dragState.activeDropZone && !canDropInActiveZone
121
+ });
122
+
123
+ let stateClasses = $derived(toStateClasses(stateObject));
124
+
125
+ // Update bindable props
126
+ $effect(() => {
127
+ isDragging = currentState === DRAGGING;
128
+ isDropping = currentState === DROPPING;
129
+ isDragPreview = currentState === DRAG_PREVIEW;
130
+ });
131
+
132
+ // Clean up on component destroy
133
+ onDestroy(() => {
134
+ if (showPreview) {
135
+ document.removeEventListener('dragover', handleDocumentDragOver);
136
+ }
137
+ });
138
+
139
+ /**
140
+ * Handle document level dragover to ensure we get position updates
141
+ * @param {DragEvent} event
142
+ */
143
+ function handleDocumentDragOver(event) {
144
+ if (showPreview && currentState === DRAGGING) {
145
+ // Update position for the custom preview
146
+ previewX = event.clientX - dragOffsetX;
147
+ previewY = event.clientY - dragOffsetY;
148
+
149
+ // Prevent default to allow drop
150
+ event.preventDefault();
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Handle drag start
156
+ * @param {DragEvent} event
157
+ */
158
+ function handleDragStart(event) {
159
+ if (disabled || !canDrag(item)) {
160
+ event.preventDefault();
161
+ return;
162
+ }
163
+
164
+ // Handle drag delay
165
+ if (dragDelay > 0) {
166
+ event.preventDefault();
167
+ currentState = DRAG_PREVIEW;
168
+
169
+ dragTimeout = setTimeout(() => {
170
+ currentState = DRAGGING;
171
+ startDrag(event);
172
+ }, dragDelay);
173
+ return;
174
+ }
175
+
176
+ currentState = DRAGGING;
177
+ startDrag(event);
178
+ }
179
+
180
+ /**
181
+ * Start the drag operation
182
+ * @param {DragEvent} event - The drag event
183
+ */
184
+ function startDrag(event) {
185
+ // Get the element's bounding rectangle
186
+ const rect = draggableElement.getBoundingClientRect();
187
+
188
+ // Calculate grab offsets - this is where the user grabbed the element
189
+ dragOffsetX = event.clientX - rect.left;
190
+ dragOffsetY = event.clientY - rect.top;
191
+
192
+ // Create drag data with draggableId included
193
+ const dragData = {
194
+ draggableId,
195
+ offsetX: dragOffsetX,
196
+ offsetY: dragOffsetY,
197
+ item,
198
+ source,
199
+ group
200
+ };
201
+
202
+ // Set shared drag state
203
+ dragState.start(draggableId, dragData);
204
+
205
+ // Set minimal data transfer for browser drag and drop API
206
+ event.dataTransfer.effectAllowed = 'move';
207
+ event.dataTransfer.setData(
208
+ 'application/json',
209
+ JSON.stringify({ draggableId })
210
+ );
211
+
212
+ // Chrome also likes to have text/plain
213
+ event.dataTransfer.setData('text/plain', draggableId);
214
+
215
+ // Create the preview controller
216
+ const previewController = new DragController(event);
217
+
218
+ // Function to get the preview controller
219
+ const getController = () => previewController;
220
+
221
+ // Call onDragStart with the getController function
222
+ onDragStart?.({ event, item, source, group, getController });
223
+
224
+ // Apply drag preview if available
225
+ // if (draggingSnippet) {
226
+ // try {
227
+ // Store rectangle information for the snippet
228
+ elementRect = rect;
229
+
230
+ // These offsets represent where the user grabbed the element relative to its top-left corner
231
+ dragOffsetX = event.clientX - rect.left;
232
+ dragOffsetY = event.clientY - rect.top;
233
+
234
+ // Set initial position - this places the preview at the element's original position
235
+ previewX = rect.left;
236
+ previewY = rect.top;
237
+
238
+ // Set a transparent 1x1 pixel image to hide browser's
239
+ // default preview
240
+ const emptyImg = new Image();
241
+ emptyImg.src =
242
+ 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
243
+
244
+ // Chrome needs the image to be loaded before setting it
245
+ emptyImg.onload = () => {
246
+ if (event.dataTransfer) {
247
+ event.dataTransfer.setDragImage(emptyImg, 0, 0);
248
+ }
249
+ };
250
+
251
+ // Fallback: try to set it immediately too
252
+ event.dataTransfer.setDragImage(emptyImg, 0, 0);
253
+
254
+ // Add document level event listener to track mouse movement
255
+ document.addEventListener('dragover', handleDocumentDragOver);
256
+
257
+ // Show custom preview
258
+ showPreview = true;
259
+ customPreviewSet = true;
260
+ // } catch (err) {
261
+ // console.error('Error setting up custom preview:', err);
262
+ // // Fallback to default preview
263
+ // previewController.applyDefaultPreview();
264
+ // }
265
+ // } else {
266
+ // // Apply default preview if no custom preview was set
267
+ // previewController.applyDefaultPreview();
268
+ // }
269
+ }
270
+
271
+ /**
272
+ * Handle during drag
273
+ * @param {DragEvent} event
274
+ */
275
+ function handleDrag(event) {
276
+ if (currentState === DRAGGING) {
277
+ onDragging?.({ event, item });
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Handle drag end
283
+ * @param {DragEvent} event
284
+ */
285
+ function handleDragEnd(event) {
286
+ clearTimeout(dragTimeout);
287
+
288
+ // Clear global drag state
289
+ dragState.end(draggableId);
290
+
291
+ // Clean up document event listener
292
+ if (customPreviewSet) {
293
+ document.removeEventListener('dragover', handleDocumentDragOver);
294
+ showPreview = false;
295
+ customPreviewSet = false;
296
+ elementRect = null;
297
+ }
298
+
299
+ // Check if drop was successful
300
+ const wasDropped = event.dataTransfer.dropEffect !== 'none';
301
+
302
+ if (wasDropped) {
303
+ currentState = DROPPING;
304
+ onDrop?.({ event, item, wasDropped: true });
305
+
306
+ // Brief dropping state before returning to idle
307
+ setTimeout(() => {
308
+ currentState = IDLE;
309
+ }, 100);
310
+ } else {
311
+ currentState = IDLE;
312
+ }
313
+
314
+ onDragEnd?.({ event, item, wasDropped });
315
+ }
316
+
317
+ /**
318
+ * Handle mouse down for drag delay
319
+ * @param {MouseEvent} event
320
+ */
321
+ function handleMouseDown(event) {
322
+ if (dragDelay > 0 && !disabled && canDrag(item)) {
323
+ // Could add visual feedback here
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Handle mouse up to cancel drag delay
329
+ * @param {MouseEvent} event
330
+ */
331
+ function handleMouseUp(event) {
332
+ if (dragTimeout) {
333
+ clearTimeout(dragTimeout);
334
+ currentState = IDLE;
335
+ }
336
+ }
337
+
338
+ // Add these variables for touch handling
339
+ let touchDragging = $state(false);
340
+ let touchStartX = 0;
341
+ let touchStartY = 0;
342
+ let touchPreviewElement = null;
343
+
344
+ /**
345
+ * Handle touch start
346
+ * @param {TouchEvent} event
347
+ */
348
+ function handleTouchStart(event) {
349
+ if (disabled || !canDrag(item)) return;
350
+
351
+ const touch = event.touches[0];
352
+ touchStartX = touch.clientX;
353
+ touchStartY = touch.clientY;
354
+
355
+ // Start drag after a small delay to distinguish from scrolling
356
+ dragTimeout = setTimeout(() => {
357
+ touchDragging = true;
358
+ currentState = DRAGGING;
359
+
360
+ // Create drag data
361
+ const rect = draggableElement.getBoundingClientRect();
362
+ dragOffsetX = touch.clientX - rect.left;
363
+ dragOffsetY = touch.clientY - rect.top;
364
+
365
+ const dragData = {
366
+ draggableId,
367
+ offsetX: dragOffsetX,
368
+ offsetY: dragOffsetY,
369
+ item,
370
+ source,
371
+ group
372
+ };
373
+
374
+ dragState.start(draggableId, dragData);
375
+
376
+ // Show preview
377
+ // if (draggingSnippet) {
378
+ elementRect = rect;
379
+ previewX = rect.left;
380
+ previewY = rect.top;
381
+ showPreview = true;
382
+ // }
383
+
384
+ // Prevent scrolling while dragging
385
+ event.preventDefault();
386
+
387
+ // Add document-level touch handlers
388
+ document.addEventListener('touchmove', handleTouchMove, {
389
+ passive: false
390
+ });
391
+ document.addEventListener('touchend', handleTouchEnd);
392
+ }, 150); // 150ms delay to distinguish from scrolling
393
+ }
394
+
395
+ /**
396
+ * Handle touch move
397
+ * @param {TouchEvent} event
398
+ */
399
+ function handleTouchMove(event) {
400
+ if (!touchDragging) return;
401
+
402
+ event.preventDefault();
403
+ const touch = event.touches[0];
404
+
405
+ // Update preview position
406
+ if (showPreview) {
407
+ previewX = touch.clientX - dragOffsetX;
408
+ previewY = touch.clientY - dragOffsetY;
409
+ }
410
+
411
+ /** @type {SimulatedDragEvent} */
412
+ const simulatedEvent = {
413
+ type: 'dragover',
414
+ clientX: touch.clientX,
415
+ clientY: touch.clientY,
416
+ dataTransfer: {
417
+ types: ['application/json', 'text/plain'],
418
+ getData: () => JSON.stringify({ draggableId }),
419
+ dropEffect: 'move',
420
+ effectAllowed: 'move',
421
+ files: []
422
+ },
423
+ preventDefault: () => {},
424
+ stopPropagation: () => {}
425
+ };
426
+
427
+ // Update active dropzone in drag state
428
+ dragState.updateActiveDropZone(touch.clientX, touch.clientY, simulatedEvent);
429
+ }
430
+
431
+ /**
432
+ * Handle touch end
433
+ * @param {TouchEvent} event
434
+ */
435
+ function handleTouchEnd(event) {
436
+ clearTimeout(dragTimeout);
437
+
438
+ if (!touchDragging) return;
439
+
440
+ const touch = event.changedTouches[0];
441
+
442
+ /** @type {SimulatedDragEvent} */
443
+ const simulatedEvent = {
444
+ type: 'drop',
445
+ clientX: touch.clientX,
446
+ clientY: touch.clientY,
447
+ dataTransfer: {
448
+ types: ['application/json', 'text'],
449
+ getData: () => JSON.stringify({ draggableId }),
450
+ dropEffect: 'move',
451
+ effectAllowed: 'move',
452
+ files: []
453
+ },
454
+ preventDefault: () => {}, // Add this!
455
+ stopPropagation: () => {} // And this!
456
+ };
457
+
458
+ // Trigger drop at final touch position
459
+ dragState.handleDropAtPoint(touch.clientX, touch.clientY, simulatedEvent);
460
+
461
+ // Clean up
462
+ touchDragging = false;
463
+ currentState = IDLE;
464
+ showPreview = false;
465
+ dragState.end(draggableId);
466
+
467
+ // Remove document handlers
468
+ document.removeEventListener('touchmove', handleTouchMove);
469
+ document.removeEventListener('touchend', handleTouchEnd);
470
+ }
471
+ </script>
472
+
473
+ <div
474
+ data-component="draggable"
475
+ bind:this={draggableElement}
476
+ draggable={!disabled && canDrag(item)}
477
+ ondragstart={handleDragStart}
478
+ ondrag={handleDrag}
479
+ ondragend={handleDragEnd}
480
+ onmousedown={handleMouseDown}
481
+ onmouseup={handleMouseUp}
482
+ ontouchstart={handleTouchStart}
483
+ class="{base} {classes} {stateClasses}"
484
+ style="touch-action: none;"
485
+ {...attrs}
486
+ >
487
+ {@render children({ element: draggableElement, rect: elementRect })}
488
+ </div>
489
+
490
+ {#if showPreview && elementRect}
491
+ <div
492
+ data-companion="drag-preview-follower"
493
+ class={stateClasses}
494
+ style="position: fixed; z-index: 9999; pointer-events: none;"
495
+ style:left="{previewX}px"
496
+ style:top="{previewY}px"
497
+ >
498
+ {#if draggingSnippet}
499
+ {@render draggingSnippet({ element: draggableElement, rect: elementRect })}
500
+ {:else}
501
+ {@render children({ element: draggableElement, rect: elementRect })}
502
+ {/if}
503
+ </div>
504
+ {/if}
505
+
506
+ <style>
507
+ [data-component='draggable'] {
508
+ -webkit-touch-callout: none;
509
+ -webkit-user-select: none;
510
+ user-select: none;
511
+ }
512
+ </style>