@hkdigital/lib-sveltekit 0.1.75 → 0.1.77

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 (33) hide show
  1. package/dist/assets/autospuiten/car-paint-picker.d.ts +7 -7
  2. package/dist/components/drag-drop/Draggable.svelte +217 -0
  3. package/dist/components/drag-drop/Draggable.svelte.d.ts +74 -0
  4. package/dist/components/drag-drop/Dropzone.svelte +320 -0
  5. package/dist/components/drag-drop/Dropzone.svelte.d.ts +112 -0
  6. package/dist/components/drag-drop/Dropzone.svelte__ +282 -0
  7. package/dist/components/drag-drop/drag-state.svelte.d.ts +6 -0
  8. package/dist/components/drag-drop/drag-state.svelte.js +19 -0
  9. package/dist/components/drag-drop/index.d.ts +2 -0
  10. package/dist/components/drag-drop/index.js +2 -0
  11. package/dist/config/imagetools.d.ts +14 -13
  12. package/dist/constants/state-labels/drag-states.d.ts +5 -0
  13. package/dist/constants/state-labels/drag-states.js +6 -0
  14. package/dist/constants/state-labels/drop-states.d.ts +6 -0
  15. package/dist/constants/state-labels/drop-states.js +6 -0
  16. package/dist/themes/hkdev/components/drag-drop/draggable.css +51 -0
  17. package/dist/themes/hkdev/components/drag-drop/dropzone.css +73 -0
  18. package/dist/themes/hkdev/components.css +6 -0
  19. package/dist/typedef/drag.d.ts +20 -0
  20. package/dist/typedef/drag.js +9 -0
  21. package/dist/typedef/drop.d.ts +20 -0
  22. package/dist/typedef/drop.js +9 -0
  23. package/dist/{config/typedef.d.ts → typedef/image.d.ts} +4 -0
  24. package/dist/{config/typedef.js → typedef/image.js} +5 -0
  25. package/dist/typedef/index.d.ts +3 -0
  26. package/dist/typedef/index.js +3 -0
  27. package/dist/util/geo/index.d.ts +10 -0
  28. package/dist/util/geo/index.js +26 -0
  29. package/dist/util/image/index.d.ts +1 -1
  30. package/dist/widgets/image-box/ImageBox.svelte +1 -1
  31. package/dist/widgets/image-box/ImageBox.svelte.d.ts +2 -2
  32. package/dist/widgets/image-box/index.d.ts +1 -1
  33. package/package.json +1 -1
@@ -1,11 +1,11 @@
1
1
  export const carPaintImages: {
2
- rusty: import("../../config/typedef.js").ImageMeta[];
3
- "army-green": import("../../config/typedef.js").ImageMeta[];
4
- "electric-blue": import("../../config/typedef.js").ImageMeta[];
5
- "lemon-yellow": import("../../config/typedef.js").ImageMeta[];
6
- "opaque-purple": import("../../config/typedef.js").ImageMeta[];
7
- "sunset-orange": import("../../config/typedef.js").ImageMeta[];
8
- "tomato-red": import("../../config/typedef.js").ImageMeta[];
2
+ rusty: import("../../typedef/image.js").ImageMeta[];
3
+ "army-green": import("../../typedef/image.js").ImageMeta[];
4
+ "electric-blue": import("../../typedef/image.js").ImageMeta[];
5
+ "lemon-yellow": import("../../typedef/image.js").ImageMeta[];
6
+ "opaque-purple": import("../../typedef/image.js").ImageMeta[];
7
+ "sunset-orange": import("../../typedef/image.js").ImageMeta[];
8
+ "tomato-red": import("../../typedef/image.js").ImageMeta[];
9
9
  };
10
10
  import Rusty from './car-paint-picker/rusty.jpg?preset=render&responsive';
11
11
  import ArmyGreen from './car-paint-picker/army-green.jpg?preset=render&responsive';
@@ -0,0 +1,217 @@
1
+ <script>
2
+ import { toStateClasses } from '../../util/design-system/index.js';
3
+ import { useDragState } from './drag-state.svelte.js';
4
+
5
+ import {
6
+ IDLE,
7
+ DRAGGING,
8
+ DRAG_PREVIEW,
9
+ DROPPING,
10
+ DRAG_DISABLED
11
+ } from '../../constants/state-labels/drag-states.js';
12
+
13
+ const dragState = useDragState();
14
+
15
+ /**
16
+ * @type {{
17
+ * item: any,
18
+ * group?: string,
19
+ * source?: string,
20
+ * disabled?: boolean,
21
+ * dragDelay?: number,
22
+ * base?: string,
23
+ * classes?: string,
24
+ * children: import('svelte').Snippet,
25
+ * isDragging?: boolean,
26
+ * isDropping?: boolean,
27
+ * isDragPreview?: boolean,
28
+ * onDragStart?: (detail: {
29
+ * event: DragEvent,
30
+ * item: any,
31
+ * source: string,
32
+ * group: string
33
+ * }) => void,
34
+ * onDragging?: (detail: {
35
+ * event: DragEvent,
36
+ * item: any
37
+ * }) => void,
38
+ * onDragEnd?: (detail: {
39
+ * event: DragEvent,
40
+ * item: any,
41
+ * wasDropped: boolean
42
+ * }) => void,
43
+ * onDrop?: (detail: {
44
+ * event: DragEvent,
45
+ * item: any,
46
+ * wasDropped: boolean
47
+ * }) => void,
48
+ * canDrag?: (item: any) => boolean,
49
+ * [key: string]: any
50
+ * }}
51
+ */
52
+ let {
53
+ item,
54
+ group = 'default',
55
+ source = 'default',
56
+ disabled = false,
57
+ dragDelay = 0,
58
+ base = '',
59
+ classes = '',
60
+ children,
61
+ isDragging = $bindable(false),
62
+ isDropping = $bindable(false),
63
+ isDragPreview = $bindable(false),
64
+ onDragStart,
65
+ onDragging,
66
+ onDragEnd,
67
+ onDrop,
68
+ canDrag = () => true,
69
+ ...attrs
70
+ } = $props();
71
+
72
+ let dragTimeout = null;
73
+ let currentState = $state(IDLE);
74
+
75
+ // Computed state object for CSS classes
76
+ let stateObject = $derived({
77
+ idle: currentState === IDLE,
78
+ dragging: currentState === DRAGGING,
79
+ 'drag-preview': currentState === DRAG_PREVIEW,
80
+ dropping: currentState === DROPPING,
81
+ 'drag-disabled': disabled || !canDrag(item)
82
+ });
83
+
84
+ let stateClasses = $derived(toStateClasses(stateObject));
85
+
86
+ // Update bindable props
87
+ $effect(() => {
88
+ isDragging = currentState === DRAGGING;
89
+ isDropping = currentState === DROPPING;
90
+ isDragPreview = currentState === DRAG_PREVIEW;
91
+ });
92
+
93
+ /**
94
+ * Handle drag start
95
+ * @param {DragEvent} event
96
+ */
97
+ function handleDragStart(event) {
98
+ if (disabled || !canDrag(item)) {
99
+ event.preventDefault();
100
+ return;
101
+ }
102
+
103
+ // Handle drag delay
104
+ if (dragDelay > 0) {
105
+ event.preventDefault();
106
+ currentState = DRAG_PREVIEW;
107
+
108
+ dragTimeout = setTimeout(() => {
109
+ currentState = DRAGGING;
110
+ startDrag(event);
111
+ }, dragDelay);
112
+ return;
113
+ }
114
+
115
+ currentState = DRAGGING;
116
+ startDrag(event);
117
+ }
118
+
119
+ /**
120
+ * Start the drag operation
121
+ * @param {DragEvent} event
122
+ */
123
+ function startDrag(event) {
124
+ const dragData = {
125
+ item,
126
+ source,
127
+ group,
128
+ metadata: { timestamp: Date.now() }
129
+ };
130
+
131
+ // Set global drag state
132
+ dragState.start(item, source, group);
133
+
134
+ event.dataTransfer.effectAllowed = 'move';
135
+ event.dataTransfer.setData('application/json', JSON.stringify(dragData));
136
+
137
+ // Set custom drag image if needed
138
+ if (event.dataTransfer.setDragImage) {
139
+ // Could set custom drag image here
140
+ }
141
+
142
+ onDragStart?.({ event, item, source, group });
143
+ }
144
+
145
+ /**
146
+ * Handle during drag
147
+ * @param {DragEvent} event
148
+ */
149
+ function handleDrag(event) {
150
+ if (currentState === DRAGGING) {
151
+ onDragging?.({ event, item });
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Handle drag end
157
+ * @param {DragEvent} event
158
+ */
159
+ function handleDragEnd(event) {
160
+ clearTimeout(dragTimeout);
161
+
162
+ // Clear global drag state
163
+ dragState.end();
164
+
165
+ // Check if drop was successful
166
+ const wasDropped = event.dataTransfer.dropEffect !== 'none';
167
+
168
+ if (wasDropped) {
169
+ currentState = DROPPING;
170
+ onDrop?.({ event, item, wasDropped: true });
171
+
172
+ // Brief dropping state before returning to idle
173
+ setTimeout(() => {
174
+ currentState = IDLE;
175
+ }, 100);
176
+ } else {
177
+ currentState = IDLE;
178
+ }
179
+
180
+ onDragEnd?.({ event, item, wasDropped });
181
+ }
182
+
183
+ /**
184
+ * Handle mouse down for drag delay
185
+ * @param {MouseEvent} event
186
+ */
187
+ function handleMouseDown(event) {
188
+ if (dragDelay > 0 && !disabled && canDrag(item)) {
189
+ // Could add visual feedback here
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Handle mouse up to cancel drag delay
195
+ * @param {MouseEvent} event
196
+ */
197
+ function handleMouseUp(event) {
198
+ if (dragTimeout) {
199
+ clearTimeout(dragTimeout);
200
+ currentState = IDLE;
201
+ }
202
+ }
203
+ </script>
204
+
205
+ <div
206
+ data-component="draggable"
207
+ draggable={!disabled && canDrag(item)}
208
+ ondragstart={handleDragStart}
209
+ ondrag={handleDrag}
210
+ ondragend={handleDragEnd}
211
+ onmousedown={handleMouseDown}
212
+ onmouseup={handleMouseUp}
213
+ class="{base} {classes} {stateClasses}"
214
+ {...attrs}
215
+ >
216
+ {@render children()}
217
+ </div>
@@ -0,0 +1,74 @@
1
+ export default Draggable;
2
+ type Draggable = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<{
5
+ [key: string]: any;
6
+ item: any;
7
+ group?: string;
8
+ source?: string;
9
+ disabled?: boolean;
10
+ dragDelay?: number;
11
+ base?: string;
12
+ classes?: string;
13
+ children: Snippet<[]>;
14
+ isDragging?: boolean;
15
+ isDropping?: boolean;
16
+ isDragPreview?: boolean;
17
+ onDragStart?: (detail: {
18
+ event: DragEvent;
19
+ item: any;
20
+ source: string;
21
+ group: string;
22
+ }) => void;
23
+ onDragging?: (detail: {
24
+ event: DragEvent;
25
+ item: any;
26
+ }) => void;
27
+ onDragEnd?: (detail: {
28
+ event: DragEvent;
29
+ item: any;
30
+ wasDropped: boolean;
31
+ }) => void;
32
+ onDrop?: (detail: {
33
+ event: DragEvent;
34
+ item: any;
35
+ wasDropped: boolean;
36
+ }) => void;
37
+ canDrag?: (item: any) => boolean;
38
+ }>): void;
39
+ };
40
+ declare const Draggable: import("svelte").Component<{
41
+ [key: string]: any;
42
+ item: any;
43
+ group?: string;
44
+ source?: string;
45
+ disabled?: boolean;
46
+ dragDelay?: number;
47
+ base?: string;
48
+ classes?: string;
49
+ children: import("svelte").Snippet;
50
+ isDragging?: boolean;
51
+ isDropping?: boolean;
52
+ isDragPreview?: boolean;
53
+ onDragStart?: (detail: {
54
+ event: DragEvent;
55
+ item: any;
56
+ source: string;
57
+ group: string;
58
+ }) => void;
59
+ onDragging?: (detail: {
60
+ event: DragEvent;
61
+ item: any;
62
+ }) => void;
63
+ onDragEnd?: (detail: {
64
+ event: DragEvent;
65
+ item: any;
66
+ wasDropped: boolean;
67
+ }) => void;
68
+ onDrop?: (detail: {
69
+ event: DragEvent;
70
+ item: any;
71
+ wasDropped: boolean;
72
+ }) => void;
73
+ canDrag?: (item: any) => boolean;
74
+ }, {}, "isDragging" | "isDropping" | "isDragPreview">;
@@ -0,0 +1,320 @@
1
+ <script>
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import { toStateClasses } from '../../util/design-system/index.js';
4
+ import { useDragState } from './drag-state.svelte.js';
5
+
6
+ import {
7
+ READY,
8
+ DRAG_OVER,
9
+ CAN_DROP,
10
+ CANNOT_DROP,
11
+ DROP_DISABLED,
12
+ ACTIVE_DROP
13
+ } from '../../constants/state-labels/drop-states.js';
14
+
15
+ const dragState = useDragState();
16
+
17
+ /**
18
+ * @type {{
19
+ * zone?: string,
20
+ * group?: string,
21
+ * disabled?: boolean,
22
+ * accepts?: (item: any) => boolean,
23
+ * maxItems?: number,
24
+ * base?: string,
25
+ * classes?: string,
26
+ * children?: import('svelte').Snippet,
27
+ * empty?: import('svelte').Snippet,
28
+ * preview?: import('svelte').Snippet<[{
29
+ * item: any,
30
+ * source: string,
31
+ * group: string,
32
+ * metadata?: any
33
+ * }]>,
34
+ * isDragOver?: boolean,
35
+ * canDrop?: boolean,
36
+ * isDropping?: boolean,
37
+ * itemCount?: number,
38
+ * onDragEnter?: (detail: {
39
+ * event: DragEvent,
40
+ * zone: string,
41
+ * canDrop: boolean
42
+ * }) => void,
43
+ * onDragOver?: (detail: {
44
+ * event: DragEvent,
45
+ * zone: string
46
+ * }) => void,
47
+ * onDragLeave?: (detail: {
48
+ * event: DragEvent,
49
+ * zone: string
50
+ * }) => void,
51
+ * onDrop?: (detail: {
52
+ * event: DragEvent,
53
+ * zone: string,
54
+ * item: any,
55
+ * source: string,
56
+ * metadata?: any
57
+ * }) => any | Promise<any>,
58
+ * onDropStart?: (detail: {
59
+ * event: DragEvent,
60
+ * zone: string,
61
+ * data: any
62
+ * }) => void,
63
+ * onDropEnd?: (detail: {
64
+ * event: DragEvent,
65
+ * zone: string,
66
+ * data: any,
67
+ * success: boolean,
68
+ * error?: Error
69
+ * }) => void,
70
+ * [key: string]: any
71
+ * }}
72
+ */
73
+ let {
74
+ zone = 'default',
75
+ group = 'default',
76
+ disabled = false,
77
+ accepts = () => true,
78
+ maxItems = Infinity,
79
+ base = '',
80
+ classes = '',
81
+ children,
82
+ empty,
83
+ preview,
84
+ isDragOver = $bindable(false),
85
+ canDrop = $bindable(false),
86
+ isDropping = $bindable(false),
87
+ itemCount = $bindable(0),
88
+ onDragEnter,
89
+ onDragOver,
90
+ onDragLeave,
91
+ onDrop,
92
+ onDropStart,
93
+ onDropEnd,
94
+ ...attrs
95
+ } = $props();
96
+
97
+ let currentState = $state(READY);
98
+ let dropzoneElement; // Reference to the dropzone DOM element
99
+
100
+ // We'll use a flag to track if we're currently in the dropzone
101
+ // without relying on a counter approach
102
+ let isCurrentlyOver = $state(false);
103
+
104
+ // Cleanup function
105
+ let cleanup;
106
+
107
+ onMount(() => {
108
+ // Global dragend listener to ensure state cleanup
109
+ const handleGlobalDragEnd = () => {
110
+ isCurrentlyOver = false;
111
+ currentState = READY;
112
+ };
113
+
114
+ document.addEventListener('dragend', handleGlobalDragEnd);
115
+
116
+ cleanup = () => {
117
+ document.removeEventListener('dragend', handleGlobalDragEnd);
118
+ };
119
+ });
120
+
121
+ onDestroy(() => {
122
+ cleanup?.();
123
+ });
124
+
125
+ // Computed state object for CSS classes
126
+ let stateObject = $derived({
127
+ ready: currentState === READY,
128
+ 'drag-over': currentState === DRAG_OVER,
129
+ 'can-drop': currentState === CAN_DROP,
130
+ 'cannot-drop': currentState === CANNOT_DROP,
131
+ 'drop-disabled': disabled,
132
+ 'active-drop': currentState === ACTIVE_DROP
133
+ });
134
+
135
+ let stateClasses = $derived(toStateClasses(stateObject));
136
+
137
+ // Update bindable props
138
+ $effect(() => {
139
+ isDragOver = [
140
+ DRAG_OVER,
141
+ CAN_DROP,
142
+ CANNOT_DROP
143
+ ].includes(currentState);
144
+
145
+ canDrop = currentState === CAN_DROP;
146
+ isDropping = currentState === ACTIVE_DROP;
147
+ });
148
+
149
+ /**
150
+ * Check if we can accept the dragged item
151
+ * @param {Object} data
152
+ * @returns {boolean}
153
+ */
154
+ function canAcceptDrop(data) {
155
+ if (disabled) return false;
156
+ if (!data) return false;
157
+ if (data.group !== group) return false;
158
+ if (!accepts(data.item)) return false;
159
+ if (itemCount >= maxItems) return false;
160
+ return true;
161
+ }
162
+
163
+ /**
164
+ * Handle drag enter with improved DOM traversal check
165
+ * @param {DragEvent} event
166
+ */
167
+ function handleDragEnter(event) {
168
+ // Prevent default to allow drop
169
+ event.preventDefault();
170
+
171
+ // If we're already in a drag-over state, don't reset anything
172
+ if (isCurrentlyOver) return;
173
+
174
+ // Now we're over this dropzone
175
+ isCurrentlyOver = true;
176
+
177
+ // Get the current drag data
178
+ const dragData = dragState.current;
179
+
180
+ // Update state based on acceptance
181
+ if (dragData) {
182
+ currentState = canAcceptDrop(dragData)
183
+ ? CAN_DROP
184
+ : CANNOT_DROP;
185
+ } else {
186
+ currentState = DRAG_OVER;
187
+ }
188
+
189
+ // Notify listeners
190
+ onDragEnter?.({ event, zone, canDrop: currentState === CAN_DROP });
191
+ }
192
+
193
+ /**
194
+ * Handle drag over
195
+ * @param {DragEvent} event
196
+ */
197
+ function handleDragOver(event) {
198
+ // Prevent default to allow drop
199
+ event.preventDefault();
200
+
201
+ // If we're not currently over this dropzone (despite dragover firing),
202
+ // treat it as an enter event
203
+ if (!isCurrentlyOver) {
204
+ handleDragEnter(event);
205
+ return;
206
+ }
207
+
208
+ // Re-evaluate acceptance on each dragover in case state changed
209
+ const dragData = dragState.current;
210
+
211
+ if (dragData && [DRAG_OVER, CAN_DROP, CANNOT_DROP].includes(currentState)) {
212
+ currentState = canAcceptDrop(dragData)
213
+ ? CAN_DROP
214
+ : CANNOT_DROP;
215
+ }
216
+
217
+ // Set visual feedback based on drop acceptance
218
+ if (currentState === CAN_DROP) {
219
+ event.dataTransfer.dropEffect = 'move';
220
+ } else if (currentState === CANNOT_DROP) {
221
+ event.dataTransfer.dropEffect = 'none';
222
+ }
223
+
224
+ // Notify listeners
225
+ onDragOver?.({ event, zone });
226
+ }
227
+
228
+ /**
229
+ * Handle drag leave with improved DOM traversal check
230
+ * @param {DragEvent} event
231
+ */
232
+ function handleDragLeave(event) {
233
+ // We need to check if we're actually leaving the dropzone or just
234
+ // entering a child element within the dropzone
235
+
236
+ // relatedTarget is the element we're moving to
237
+ const relatedTarget = event.relatedTarget;
238
+
239
+ // If relatedTarget is null or outside our dropzone, we're truly leaving
240
+ const isActuallyLeaving = !relatedTarget ||
241
+ !dropzoneElement.contains(relatedTarget);
242
+
243
+ if (isActuallyLeaving) {
244
+ isCurrentlyOver = false;
245
+ currentState = READY;
246
+ onDragLeave?.({ event, zone });
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Handle drop
252
+ * @param {DragEvent} event
253
+ */
254
+ function handleDrop(event) {
255
+ // Prevent default browser actions
256
+ event.preventDefault();
257
+
258
+ // Reset our tracking state
259
+ isCurrentlyOver = false;
260
+
261
+ try {
262
+ // Parse the JSON data from the dataTransfer object
263
+ const data = JSON.parse(event.dataTransfer.getData('application/json'));
264
+
265
+ // Check if we can accept this drop
266
+ if (canAcceptDrop(data)) {
267
+ // Update state and notify listeners
268
+ currentState = ACTIVE_DROP;
269
+ onDropStart?.({ event, zone, data });
270
+
271
+ // Call the onDrop handler and handle Promise resolution
272
+ const dropResult = onDrop?.({
273
+ event,
274
+ zone,
275
+ item: data.item,
276
+ source: data.source,
277
+ metadata: data.metadata
278
+ });
279
+
280
+ // Handle async or sync results
281
+ Promise.resolve(dropResult).then(() => {
282
+ currentState = READY;
283
+ onDropEnd?.({ event, zone, data, success: true });
284
+ }).catch((error) => {
285
+ currentState = READY;
286
+ onDropEnd?.({ event, zone, data, success: false, error });
287
+ });
288
+ } else {
289
+ // Not a valid drop, reset state
290
+ currentState = READY;
291
+ }
292
+ } catch (error) {
293
+ // Handle parsing errors
294
+ console.error('Drop error:', error);
295
+ currentState = READY;
296
+ }
297
+ }
298
+ </script>
299
+
300
+ <div
301
+ data-component="dropzone"
302
+ bind:this={dropzoneElement}
303
+ ondragenter={handleDragEnter}
304
+ ondragover={handleDragOver}
305
+ ondragleave={handleDragLeave}
306
+ ondrop={handleDrop}
307
+ class="{base} {classes} {stateClasses}"
308
+ data-zone={zone}
309
+ {...attrs}
310
+ >
311
+ {#if children}
312
+ {@render children()}
313
+ {:else if currentState === CAN_DROP && preview}
314
+ {@render preview(dragState.current)}
315
+ {:else if itemCount === 0 && empty}
316
+ {@render empty()}
317
+ {:else}
318
+ <div data-element="drop-zone-empty">Drop items here</div>
319
+ {/if}
320
+ </div>