@hkdigital/lib-sveltekit 0.2.21 → 0.2.22

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