@warkypublic/svelix 0.1.44 → 0.1.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -33
- package/dist/components/BetterMenu/BetterMenu.svelte +21 -37
- package/dist/components/BetterMenu/BetterMenuAsyncButton.svelte +21 -31
- package/dist/components/BetterMenu/BetterMenuPreview.svelte +27 -29
- package/dist/components/BetterMenu/MenuRenderer.svelte +40 -51
- package/dist/components/Boxer/Boxer.svelte +488 -602
- package/dist/components/Boxer/BoxerTarget.svelte +6 -46
- package/dist/components/Boxer/BoxerTarget.svelte.d.ts +1 -0
- package/dist/components/Boxer/types.d.ts +0 -1
- package/dist/components/Button.svelte +19 -43
- package/dist/components/ButtonPreview.svelte +2 -11
- package/dist/components/CardGrid/CardGrid.svelte +1141 -0
- package/dist/components/CardGrid/CardGrid.svelte.d.ts +61 -0
- package/dist/components/CardGrid/CardGridFilterPanel.svelte +320 -0
- package/dist/components/CardGrid/CardGridFilterPanel.svelte.d.ts +11 -0
- package/dist/components/CardGrid/DefaultCard.svelte +287 -0
- package/dist/components/CardGrid/DefaultCard.svelte.d.ts +10 -0
- package/dist/components/CardGrid/ImageCardStory.svelte +308 -0
- package/dist/components/CardGrid/ImageCardStory.svelte.d.ts +18 -0
- package/dist/components/CardGrid/cardGrid.d.ts +33 -0
- package/dist/components/CardGrid/cardGrid.js +21 -0
- package/dist/components/CardGrid/index.d.ts +4 -0
- package/dist/components/CardGrid/index.js +4 -0
- package/dist/components/ContentEditor/CollaboraInsertTextDemo.svelte +5 -10
- package/dist/components/ContentEditor/ContentEditor.svelte +24 -50
- package/dist/components/ContentEditor/subcomponents/AudioPlayer.svelte +17 -17
- package/dist/components/ContentEditor/subcomponents/CollaboraEditor.svelte +244 -309
- package/dist/components/ContentEditor/subcomponents/EmailViewer.svelte +2 -3
- package/dist/components/ContentEditor/subcomponents/ImageViewer.svelte +14 -15
- package/dist/components/ContentEditor/subcomponents/MarkdownViewer.svelte +74 -90
- package/dist/components/ContentEditor/subcomponents/MonacoEditor.svelte +75 -103
- package/dist/components/ContentEditor/subcomponents/Office365Editor.svelte +234 -297
- package/dist/components/ContentEditor/subcomponents/PdfViewer.svelte +14 -20
- package/dist/components/ContentEditor/subcomponents/TextEditor.svelte +122 -150
- package/dist/components/ContentEditor/subcomponents/UnknownFile.svelte +105 -126
- package/dist/components/ContentEditor/subcomponents/VideoPlayer.svelte +17 -17
- package/dist/components/ContentEditor/subcomponents/ZipViewer.svelte +2 -3
- package/dist/components/ErrorBoundary/ErrorBoundary.svelte +41 -58
- package/dist/components/ErrorBoundary/ErrorBoundaryPreview.svelte +8 -16
- package/dist/components/Former/Former.svelte +306 -424
- package/dist/components/Former/FormerButtonArea.svelte +17 -68
- package/dist/components/Former/FormerDrawer.svelte +26 -78
- package/dist/components/Former/FormerDrawerPreview.svelte +99 -89
- package/dist/components/Former/FormerModal.svelte +24 -70
- package/dist/components/Former/FormerModalPreview.svelte +99 -89
- package/dist/components/Former/FormerPreview.svelte +76 -78
- package/dist/components/Former/FormerRestApiPreview.svelte +55 -48
- package/dist/components/FormerControllers/ButtonCtrl.svelte +13 -44
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.svelte +280 -445
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlCalendar.svelte +95 -136
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlPickerPanel.svelte +3 -62
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlTimeFields.svelte +143 -217
- package/dist/components/FormerControllers/IconButtonCtrl.svelte +13 -42
- package/dist/components/FormerControllers/InlineWrapper.svelte +12 -41
- package/dist/components/FormerControllers/InlineWrapperPreview.svelte +4 -26
- package/dist/components/FormerControllers/NativeSelectCtrl.svelte +3 -29
- package/dist/components/FormerControllers/NumberInputCtrl.svelte +9 -35
- package/dist/components/FormerControllers/PasswordInputCtrl.svelte +4 -23
- package/dist/components/FormerControllers/SwitchCtrl.svelte +3 -20
- package/dist/components/FormerControllers/TextAreaCtrl.svelte +3 -24
- package/dist/components/FormerControllers/TextInputCtrl.svelte +3 -24
- package/dist/components/GlobalStateStore/GlobalStateStoreProvider.svelte +73 -120
- package/dist/components/Gridler/components/Gridler.svelte +338 -442
- package/dist/components/Gridler/components/GridlerCanvas.svelte +720 -1115
- package/dist/components/Gridler/components/GridlerEditor.svelte +2 -15
- package/dist/components/Gridler/components/GridlerFull.svelte +520 -841
- package/dist/components/Gridler/components/GridlerFull.svelte.d.ts +1 -1
- package/dist/components/Gridler/components/GridlerFullWithFormerPreview.svelte +194 -147
- package/dist/components/Gridler/components/GridlerSearch.svelte +7 -16
- package/dist/components/Gridler/components/GridlerSearchToggle.svelte +7 -19
- package/dist/components/Gridler/types.d.ts +1 -1
- package/dist/components/Icons/IconAdd.svelte +1 -3
- package/dist/components/Icons/IconAlertCircle.svelte +1 -3
- package/dist/components/Icons/IconAlertTriangle.svelte +1 -3
- package/dist/components/Icons/IconCamera.svelte +1 -3
- package/dist/components/Icons/IconClose.svelte +1 -3
- package/dist/components/Icons/IconEdit.svelte +1 -3
- package/dist/components/Icons/IconFilter.svelte +1 -3
- package/dist/components/Icons/IconSearch.svelte +1 -3
- package/dist/components/Icons/IconSort.svelte +1 -3
- package/dist/components/Icons/IconTrash.svelte +1 -3
- package/dist/components/Portal/Portal.svelte +14 -38
- package/dist/components/Screenshot/Screenshot.svelte +7 -13
- package/dist/components/Svark/Svark.svelte +680 -852
- package/dist/components/Svark/SvarkContextMenu.svelte +44 -63
- package/dist/components/Svark/SvarkInfiniteLoader.svelte +2 -6
- package/dist/components/Svark/SvarkPager.svelte +2 -28
- package/dist/components/Svark/SvarkSelectionDemo.svelte +4 -8
- package/dist/components/Svark/SvarkTopBar.svelte +9 -74
- package/dist/components/SvarkGrid/SvarkGrid.svelte +877 -1123
- package/dist/components/SvarkGrid/components/SvarkColumnFilterForm.svelte +45 -58
- package/dist/components/SvarkGrid/components/SvarkContextMenu.svelte +44 -63
- package/dist/components/SvarkGrid/components/SvarkHeaderFilterCell.svelte +41 -75
- package/dist/components/SvarkGrid/components/SvarkInfiniteLoader.svelte +2 -6
- package/dist/components/SvarkGrid/components/SvarkPager.svelte +2 -28
- package/dist/components/SvarkGrid/components/SvarkSearchPopover.svelte +8 -16
- package/dist/components/SvarkGrid/components/SvarkTopBar.svelte +6 -62
- package/dist/components/SvarkGrid/internal/SvarkGridView.svelte +345 -507
- package/dist/components/VTree/VTree.svelte +349 -431
- package/dist/components/VTree/VTreeContextMenu.svelte +21 -33
- package/dist/components/VTree/VTreeEventsDemo.svelte +48 -58
- package/dist/components/VTree/VTreeRow.svelte +13 -65
- package/dist/components/VTree/VTreeSearch.svelte +6 -13
- package/dist/components/VTree/VTreeVirtualViewport.svelte +37 -106
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/llm/COMPONENT_GUIDE.md +240 -0
- package/llm/plans/card_grid.plan.md +305 -0
- package/package.json +48 -46
|
@@ -1,605 +1,488 @@
|
|
|
1
|
-
<script lang="ts"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
}, 0);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
function onBackdropPointerDown(e: PointerEvent) {
|
|
490
|
-
// Consume the pointer sequence so it cannot activate elements behind the backdrop.
|
|
491
|
-
e.preventDefault();
|
|
492
|
-
e.stopPropagation();
|
|
493
|
-
store.setOpened(false);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
function onOptionPointerDown(e: PointerEvent, index: number) {
|
|
497
|
-
// Commit selection before blur/focusout closes the popover on some browsers.
|
|
498
|
-
e.preventDefault();
|
|
499
|
-
e.stopPropagation();
|
|
500
|
-
onOptionSubmit(index);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
function syncInsideDialogFlag() {
|
|
504
|
-
insideDialog = !!anchorEl?.closest('dialog, [role="dialog"]');
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// Public API via bind:this
|
|
508
|
-
export function clear() {
|
|
509
|
-
onClear();
|
|
510
|
-
}
|
|
511
|
-
export function close() {
|
|
512
|
-
store.setOpened(false);
|
|
513
|
-
activeOptionIndex = null;
|
|
514
|
-
}
|
|
515
|
-
export function focus() {
|
|
516
|
-
suppressOpenOnFocus = false;
|
|
517
|
-
targetRef?.focus();
|
|
518
|
-
}
|
|
519
|
-
export function getValue() {
|
|
520
|
-
return value;
|
|
521
|
-
}
|
|
522
|
-
export function open() {
|
|
523
|
-
if (disabled) return;
|
|
524
|
-
store.setOpened(true);
|
|
525
|
-
activeOptionIndex = null;
|
|
526
|
-
}
|
|
527
|
-
export function refetch() {
|
|
528
|
-
return store.refetch();
|
|
529
|
-
}
|
|
530
|
-
export function setValue(val: unknown) {
|
|
531
|
-
value = val;
|
|
532
|
-
onChange?.(val);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
$effect(() => {
|
|
536
|
-
if (!$store.opened || effectiveDisablePortal || disabled) {
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
updatePopoverPosition();
|
|
541
|
-
|
|
542
|
-
if (typeof window === "undefined") {
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
const onWindowChange = () => {
|
|
547
|
-
updatePopoverPosition();
|
|
548
|
-
};
|
|
549
|
-
|
|
550
|
-
window.addEventListener("resize", onWindowChange);
|
|
551
|
-
window.addEventListener("scroll", onWindowChange, true);
|
|
552
|
-
|
|
553
|
-
return () => {
|
|
554
|
-
window.removeEventListener("resize", onWindowChange);
|
|
555
|
-
window.removeEventListener("scroll", onWindowChange, true);
|
|
556
|
-
};
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
$effect(() => {
|
|
560
|
-
if (!$store.opened || disabled) {
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
const overlay = registerOverlay({
|
|
565
|
-
kind: "popover",
|
|
566
|
-
mount: effectiveDisablePortal ? "inline" : "portal",
|
|
567
|
-
});
|
|
568
|
-
backdropZ = overlay.layer.backdrop;
|
|
569
|
-
dropdownZ = overlay.layer.content;
|
|
570
|
-
|
|
571
|
-
return () => {
|
|
572
|
-
overlay.unregister();
|
|
573
|
-
backdropZ = 1090;
|
|
574
|
-
dropdownZ = 1100;
|
|
575
|
-
};
|
|
576
|
-
});
|
|
577
|
-
|
|
578
|
-
$effect(() => {
|
|
579
|
-
void anchorEl;
|
|
580
|
-
void storeOpened;
|
|
581
|
-
syncInsideDialogFlag();
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
$effect(() => {
|
|
585
|
-
if (!$store.opened || !effectiveDisablePortal || disabled || typeof window === "undefined") {
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
const onDocumentPointerDown = (event: PointerEvent) => {
|
|
590
|
-
const target = event.target as Node | null;
|
|
591
|
-
if (!target) return;
|
|
592
|
-
|
|
593
|
-
const insideAnchor = !!anchorEl?.contains(target);
|
|
594
|
-
const insideDropdown = !!dropdownEl?.contains(target);
|
|
595
|
-
if (!insideAnchor && !insideDropdown) {
|
|
596
|
-
store.setOpened(false);
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
|
|
600
|
-
window.addEventListener("pointerdown", onDocumentPointerDown, true);
|
|
601
|
-
return () => window.removeEventListener("pointerdown", onDocumentPointerDown, true);
|
|
602
|
-
});
|
|
1
|
+
<script lang="ts">/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import { untrack } from "svelte";
|
|
3
|
+
import { createVirtualizer } from "@tanstack/svelte-virtual";
|
|
4
|
+
import { registerOverlay } from "../OverlayStack";
|
|
5
|
+
import Portal from "../Portal/Portal.svelte";
|
|
6
|
+
import { createBoxerStore } from "./store";
|
|
7
|
+
import BoxerTarget from "./BoxerTarget.svelte";
|
|
8
|
+
let { adapter, clearable = true, data = [], dataSource: dataSourceProp = undefined, debounceMs = 300, disablePortal = false, disabled, error, id, label, leftSection, mah = 200, multiSelect, name, onAPICall: onAPICallProp = undefined, onBufferChange, onChange, onResolveValues: onResolveValuesProp = undefined, openOnClear, pageSize = 50, placeholder, rightSection, searchColumns, selectFirst, showAll, value = $bindable(undefined) } = $props();
|
|
9
|
+
const instanceId = `boxer-${Math.random().toString(36).slice(2, 10)}`;
|
|
10
|
+
// eslint-disable-next-line svelte/no-unused-svelte-ignore
|
|
11
|
+
// svelte-ignore state_referenced_locally -- id is intentionally captured once for a stable inputId
|
|
12
|
+
const inputId = id ?? `${instanceId}-input`;
|
|
13
|
+
const listboxId = `${instanceId}-listbox`;
|
|
14
|
+
// Derive effective dataSource, onAPICall, resolver from adapter when not explicitly provided.
|
|
15
|
+
// eslint-disable-next-line svelte/no-unused-svelte-ignore
|
|
16
|
+
// svelte-ignore state_referenced_locally -- adapter/dataSourceProp/onAPICallProp/onResolveValuesProp captured once at mount
|
|
17
|
+
const dataSource = dataSourceProp ?? (adapter ? "server" : "local");
|
|
18
|
+
// svelte-ignore state_referenced_locally
|
|
19
|
+
const onAPICall = onAPICallProp ?? (adapter ? (params) => adapter.fetch(params) : undefined);
|
|
20
|
+
// svelte-ignore state_referenced_locally
|
|
21
|
+
const onResolveValues = onResolveValuesProp ?? (adapter?.resolveByValue ? (values, signal) => adapter.resolveByValue(values, signal) : undefined);
|
|
22
|
+
// Create store once with initial props
|
|
23
|
+
// eslint-disable-next-line svelte/no-unused-svelte-ignore
|
|
24
|
+
// svelte-ignore state_referenced_locally -- all props captured at mount for store initialisation
|
|
25
|
+
const store = createBoxerStore({
|
|
26
|
+
clearable,
|
|
27
|
+
data,
|
|
28
|
+
dataSource,
|
|
29
|
+
disabled,
|
|
30
|
+
error,
|
|
31
|
+
label,
|
|
32
|
+
mah,
|
|
33
|
+
multiSelect,
|
|
34
|
+
onAPICall,
|
|
35
|
+
onBufferChange,
|
|
36
|
+
onChange,
|
|
37
|
+
onResolveValues,
|
|
38
|
+
openOnClear,
|
|
39
|
+
pageSize,
|
|
40
|
+
placeholder,
|
|
41
|
+
searchColumns,
|
|
42
|
+
selectFirst,
|
|
43
|
+
showAll,
|
|
44
|
+
value
|
|
45
|
+
});
|
|
46
|
+
// Fine-grained derived values so $effect blocks only re-run when the
|
|
47
|
+
// specific field they care about actually changes (not on every store update).
|
|
48
|
+
const storeSearch = $derived($store.search);
|
|
49
|
+
const storeOpened = $derived($store.opened);
|
|
50
|
+
const storeBoxerData = $derived($store.boxerData);
|
|
51
|
+
const storeSelectedItems = $derived($store.selectedItems);
|
|
52
|
+
const storeInput = $derived($store.input);
|
|
53
|
+
const boxerDataLength = $derived($store.boxerData.length);
|
|
54
|
+
// Sync value prop changes into store
|
|
55
|
+
$effect(() => {
|
|
56
|
+
store.updateProps({ value });
|
|
57
|
+
});
|
|
58
|
+
// Virtualizer
|
|
59
|
+
let parentEl = $state(undefined);
|
|
60
|
+
let targetRef = $state(undefined);
|
|
61
|
+
let anchorEl = $state(undefined);
|
|
62
|
+
let dropdownEl = $state(undefined);
|
|
63
|
+
let popupTop = $state(0);
|
|
64
|
+
let popupLeft = $state(0);
|
|
65
|
+
let popupWidth = $state(0);
|
|
66
|
+
let activeOptionIndex = $state(null);
|
|
67
|
+
let backdropZ = $state(1090);
|
|
68
|
+
let dropdownZ = $state(1100);
|
|
69
|
+
let pointerInteractingWithDropdown = $state(false);
|
|
70
|
+
let insideDialog = $state(false);
|
|
71
|
+
let suppressOpenOnFocus = $state(false);
|
|
72
|
+
const effectiveDisablePortal = $derived(disablePortal || insideDialog);
|
|
73
|
+
// Plain variable — NOT $state to avoid deep proxy on the complex virtualizer object.
|
|
74
|
+
let rawVirtualizer = null;
|
|
75
|
+
// Virtualizer outputs as $state — updated directly by the subscribe callback.
|
|
76
|
+
let virtualItems = $state.raw([]);
|
|
77
|
+
let totalSize = $state(0);
|
|
78
|
+
// Create virtualizer only when parentEl changes (dropdown mount/unmount).
|
|
79
|
+
$effect(() => {
|
|
80
|
+
if (!parentEl) {
|
|
81
|
+
rawVirtualizer = null;
|
|
82
|
+
virtualItems = [];
|
|
83
|
+
totalSize = 0;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const initialCount = untrack(() => boxerDataLength);
|
|
87
|
+
const v = createVirtualizer({
|
|
88
|
+
count: initialCount,
|
|
89
|
+
estimateSize: () => 36,
|
|
90
|
+
getScrollElement: () => parentEl
|
|
91
|
+
});
|
|
92
|
+
return v.subscribe((instance) => {
|
|
93
|
+
rawVirtualizer = instance;
|
|
94
|
+
virtualItems = instance.getVirtualItems();
|
|
95
|
+
totalSize = instance.getTotalSize();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
// Update virtualizer count when data length actually changes (preserves scroll).
|
|
99
|
+
$effect(() => {
|
|
100
|
+
const count = boxerDataLength;
|
|
101
|
+
if (rawVirtualizer && parentEl) {
|
|
102
|
+
rawVirtualizer.setOptions({
|
|
103
|
+
count,
|
|
104
|
+
estimateSize: () => 36,
|
|
105
|
+
getScrollElement: () => parentEl
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
// Debounced search — only reacts to actual search text changes.
|
|
110
|
+
let searchTimeout;
|
|
111
|
+
let didInitialFetch = false;
|
|
112
|
+
$effect(() => {
|
|
113
|
+
const search = storeSearch;
|
|
114
|
+
// Skip the initial tick: the initial-fetch effect below handles first load.
|
|
115
|
+
if (!didInitialFetch) return;
|
|
116
|
+
clearTimeout(searchTimeout);
|
|
117
|
+
searchTimeout = setTimeout(() => {
|
|
118
|
+
if (search !== undefined && storeOpened) {
|
|
119
|
+
store.fetchData(search, true);
|
|
120
|
+
parentEl?.scrollTo?.({ top: 0 });
|
|
121
|
+
}
|
|
122
|
+
}, debounceMs);
|
|
123
|
+
return () => clearTimeout(searchTimeout);
|
|
124
|
+
});
|
|
125
|
+
// Initial data fetch + resolve labels for preloaded value(s).
|
|
126
|
+
$effect(() => {
|
|
127
|
+
didInitialFetch = true;
|
|
128
|
+
store.fetchData("", true);
|
|
129
|
+
resolvePreloadedValue(value);
|
|
130
|
+
return () => {
|
|
131
|
+
clearTimeout(searchTimeout);
|
|
132
|
+
store.cancel();
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
let lastResolvedKey = null;
|
|
136
|
+
async function resolvePreloadedValue(val) {
|
|
137
|
+
if (val == null || val === "" || Array.isArray(val) && val.length === 0) return;
|
|
138
|
+
if (!onResolveValues) return;
|
|
139
|
+
const values = Array.isArray(val) ? val : [val];
|
|
140
|
+
const key = JSON.stringify(values);
|
|
141
|
+
if (key === lastResolvedKey) return;
|
|
142
|
+
lastResolvedKey = key;
|
|
143
|
+
try {
|
|
144
|
+
const items = await onResolveValues(values);
|
|
145
|
+
if (!items || items.length === 0) return;
|
|
146
|
+
if (multiSelect) {
|
|
147
|
+
store.setSelectedItems(items);
|
|
148
|
+
} else {
|
|
149
|
+
store.setSelectedItems(items.slice(0, 1));
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
console.error("Boxer resolveByValue error:", err);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// When value prop changes from outside, resolve any new labels we don't yet have.
|
|
156
|
+
$effect(() => {
|
|
157
|
+
void value;
|
|
158
|
+
untrack(() => {
|
|
159
|
+
if (value == null) {
|
|
160
|
+
store.clearSelectedItems();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const knownKeys = new Set($store.selectedItems.map((i) => JSON.stringify(i.value)));
|
|
164
|
+
const needed = (Array.isArray(value) ? value : [value]).filter((v) => !knownKeys.has(JSON.stringify(v)));
|
|
165
|
+
if (needed.length === 0) {
|
|
166
|
+
if (!multiSelect) {
|
|
167
|
+
// Keep the single-item list in sync with the chosen value.
|
|
168
|
+
const match = $store.selectedItems.find((i) => JSON.stringify(i.value) === JSON.stringify(value));
|
|
169
|
+
if (match) store.setSelectedItems([match]);
|
|
170
|
+
} else {
|
|
171
|
+
// Drop any selected items whose value is no longer in `value`.
|
|
172
|
+
const keep = new Set(value.map((v) => JSON.stringify(v)));
|
|
173
|
+
const filtered = $store.selectedItems.filter((i) => keep.has(JSON.stringify(i.value)));
|
|
174
|
+
if (filtered.length !== $store.selectedItems.length) {
|
|
175
|
+
store.setSelectedItems(filtered);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// Fall back to boxerData, then to the resolver.
|
|
181
|
+
const fromBoxer = $store.boxerData.filter((i) => needed.some((v) => JSON.stringify(v) === JSON.stringify(i.value)));
|
|
182
|
+
fromBoxer.forEach((i) => store.addSelectedItem(i));
|
|
183
|
+
const stillMissing = needed.filter((v) => !fromBoxer.some((i) => JSON.stringify(i.value) === JSON.stringify(v)));
|
|
184
|
+
if (stillMissing.length > 0) resolvePreloadedValue(stillMissing);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
// Sync displayed input + emit onBufferChange from selectedItems (single source of truth).
|
|
188
|
+
$effect(() => {
|
|
189
|
+
const selected = storeSelectedItems;
|
|
190
|
+
const opened = storeOpened;
|
|
191
|
+
const currentInput = storeInput;
|
|
192
|
+
if (multiSelect) {
|
|
193
|
+
const labels = selected.map((i) => i.label).join(", ");
|
|
194
|
+
if (!opened && currentInput !== labels) store.setInput(labels);
|
|
195
|
+
onBufferChange?.(selected);
|
|
196
|
+
} else {
|
|
197
|
+
const item = selected[0] ?? null;
|
|
198
|
+
if (item && currentInput !== item.label && !opened) {
|
|
199
|
+
store.setInput(item.label);
|
|
200
|
+
} else if (!item && !opened && currentInput !== "") {
|
|
201
|
+
store.setInput("");
|
|
202
|
+
}
|
|
203
|
+
onBufferChange?.(item);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
// When data arrives, opportunistically enrich selectedItems for multiselect
|
|
207
|
+
// (adds labels for items that just loaded).
|
|
208
|
+
$effect(() => {
|
|
209
|
+
const boxerData = storeBoxerData;
|
|
210
|
+
if (!multiSelect || !Array.isArray(value) || value.length === 0) return;
|
|
211
|
+
untrack(() => {
|
|
212
|
+
const known = new Set($store.selectedItems.map((i) => JSON.stringify(i.value)));
|
|
213
|
+
for (const v of value) {
|
|
214
|
+
if (known.has(JSON.stringify(v))) continue;
|
|
215
|
+
const match = boxerData.find((i) => JSON.stringify(i.value) === JSON.stringify(v));
|
|
216
|
+
if (match) store.addSelectedItem(match);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
// Select first
|
|
221
|
+
$effect(() => {
|
|
222
|
+
const boxerData = storeBoxerData;
|
|
223
|
+
if (selectFirst && boxerData.length > 0 && !multiSelect && !value) {
|
|
224
|
+
onOptionSubmit(0);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
function onOptionSubmit(index) {
|
|
228
|
+
const option = $store.boxerData?.[index];
|
|
229
|
+
if (!option) return;
|
|
230
|
+
activeOptionIndex = index;
|
|
231
|
+
if (multiSelect) {
|
|
232
|
+
const currentValues = Array.isArray(value) ? value : [];
|
|
233
|
+
const isSelected = currentValues.includes(option.value);
|
|
234
|
+
if (isSelected) {
|
|
235
|
+
value = currentValues.filter((v) => v !== option.value);
|
|
236
|
+
store.removeSelectedItem(option.value);
|
|
237
|
+
} else {
|
|
238
|
+
value = [...currentValues, option.value];
|
|
239
|
+
store.addSelectedItem(option);
|
|
240
|
+
}
|
|
241
|
+
onChange?.(value);
|
|
242
|
+
} else {
|
|
243
|
+
value = option.value;
|
|
244
|
+
store.setSelectedItems([option]);
|
|
245
|
+
onChange?.(option.value);
|
|
246
|
+
store.setSearch("");
|
|
247
|
+
store.setInput(option.label);
|
|
248
|
+
store.setOpened(false);
|
|
249
|
+
activeOptionIndex = null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function onClear() {
|
|
253
|
+
if (showAll && selectFirst) {
|
|
254
|
+
onOptionSubmit(0);
|
|
255
|
+
} else {
|
|
256
|
+
value = multiSelect ? [] : null;
|
|
257
|
+
store.clearSelectedItems();
|
|
258
|
+
onChange?.(value);
|
|
259
|
+
store.setSearch("");
|
|
260
|
+
store.setInput("");
|
|
261
|
+
activeOptionIndex = null;
|
|
262
|
+
targetRef?.focus();
|
|
263
|
+
}
|
|
264
|
+
if (openOnClear) {
|
|
265
|
+
store.setOpened(true);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function focusDropdownItem(index) {
|
|
269
|
+
const length = $store.boxerData.length;
|
|
270
|
+
if (length === 0) return;
|
|
271
|
+
const clamped = Math.max(0, Math.min(index, length - 1));
|
|
272
|
+
activeOptionIndex = clamped;
|
|
273
|
+
rawVirtualizer?.scrollToIndex(clamped, { align: "auto" });
|
|
274
|
+
requestAnimationFrame(() => {
|
|
275
|
+
const el = parentEl?.querySelector(`[data-index="${clamped}"]`);
|
|
276
|
+
if (el) {
|
|
277
|
+
el.scrollIntoView({ block: "nearest" });
|
|
278
|
+
el.focus();
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
function onInputKeydown(e) {
|
|
283
|
+
switch (e.key) {
|
|
284
|
+
case "ArrowDown":
|
|
285
|
+
e.preventDefault();
|
|
286
|
+
if (!$store.opened) store.setOpened(true);
|
|
287
|
+
requestAnimationFrame(() => {
|
|
288
|
+
if ($store.boxerData.length > 0) focusDropdownItem(0);
|
|
289
|
+
});
|
|
290
|
+
break;
|
|
291
|
+
case "Enter":
|
|
292
|
+
e.preventDefault();
|
|
293
|
+
if (!$store.opened) {
|
|
294
|
+
store.setOpened(true);
|
|
295
|
+
} else if (!multiSelect) {
|
|
296
|
+
const selectedIndex = $store.boxerData.findIndex((item) => item.value === value);
|
|
297
|
+
if (selectedIndex >= 0) {
|
|
298
|
+
store.setOpened(false);
|
|
299
|
+
activeOptionIndex = null;
|
|
300
|
+
} else {
|
|
301
|
+
onOptionSubmit(0);
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
store.setOpened(false);
|
|
305
|
+
activeOptionIndex = null;
|
|
306
|
+
}
|
|
307
|
+
break;
|
|
308
|
+
case "Escape":
|
|
309
|
+
if ($store.opened) {
|
|
310
|
+
e.preventDefault();
|
|
311
|
+
store.setOpened(false);
|
|
312
|
+
activeOptionIndex = null;
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
case "Tab":
|
|
316
|
+
if (multiSelect && $store.opened && $store.boxerData.length > 0) {
|
|
317
|
+
e.preventDefault();
|
|
318
|
+
onOptionSubmit(0);
|
|
319
|
+
}
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function onDropdownItemKeydown(e, index) {
|
|
324
|
+
const length = $store.boxerData.length;
|
|
325
|
+
const pageSizeNav = Math.max(1, Math.floor(mah / 36));
|
|
326
|
+
switch (e.key) {
|
|
327
|
+
case "ArrowDown":
|
|
328
|
+
e.preventDefault();
|
|
329
|
+
if (index < length - 1) focusDropdownItem(index + 1);
|
|
330
|
+
break;
|
|
331
|
+
case "ArrowUp":
|
|
332
|
+
e.preventDefault();
|
|
333
|
+
if (index === 0) {
|
|
334
|
+
activeOptionIndex = null;
|
|
335
|
+
targetRef?.focus();
|
|
336
|
+
} else {
|
|
337
|
+
focusDropdownItem(index - 1);
|
|
338
|
+
}
|
|
339
|
+
break;
|
|
340
|
+
case "Home":
|
|
341
|
+
e.preventDefault();
|
|
342
|
+
focusDropdownItem(0);
|
|
343
|
+
break;
|
|
344
|
+
case "End":
|
|
345
|
+
e.preventDefault();
|
|
346
|
+
focusDropdownItem(length - 1);
|
|
347
|
+
break;
|
|
348
|
+
case "PageDown":
|
|
349
|
+
e.preventDefault();
|
|
350
|
+
focusDropdownItem(Math.min(length - 1, index + pageSizeNav));
|
|
351
|
+
break;
|
|
352
|
+
case "PageUp":
|
|
353
|
+
e.preventDefault();
|
|
354
|
+
focusDropdownItem(Math.max(0, index - pageSizeNav));
|
|
355
|
+
break;
|
|
356
|
+
case "Enter":
|
|
357
|
+
case " ":
|
|
358
|
+
e.preventDefault();
|
|
359
|
+
onOptionSubmit(index);
|
|
360
|
+
if (!multiSelect) targetRef?.focus();
|
|
361
|
+
break;
|
|
362
|
+
case "Escape":
|
|
363
|
+
e.preventDefault();
|
|
364
|
+
store.setOpened(false);
|
|
365
|
+
activeOptionIndex = null;
|
|
366
|
+
suppressOpenOnFocus = true;
|
|
367
|
+
targetRef?.focus();
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function updatePopoverPosition() {
|
|
372
|
+
if (!anchorEl) return;
|
|
373
|
+
const rect = anchorEl.getBoundingClientRect();
|
|
374
|
+
const viewportWidth = typeof window === "undefined" ? rect.width : window.innerWidth;
|
|
375
|
+
const horizontalPadding = 8;
|
|
376
|
+
const maxWidth = Math.max(160, viewportWidth - horizontalPadding * 2);
|
|
377
|
+
const nextWidth = Math.min(Math.max(220, rect.width), maxWidth);
|
|
378
|
+
const maxLeft = viewportWidth - nextWidth - horizontalPadding;
|
|
379
|
+
popupTop = rect.bottom + 4;
|
|
380
|
+
popupWidth = nextWidth;
|
|
381
|
+
popupLeft = Math.min(Math.max(rect.left, horizontalPadding), Math.max(horizontalPadding, maxLeft));
|
|
382
|
+
}
|
|
383
|
+
function markDropdownPointerInteraction() {
|
|
384
|
+
pointerInteractingWithDropdown = true;
|
|
385
|
+
setTimeout(() => {
|
|
386
|
+
pointerInteractingWithDropdown = false;
|
|
387
|
+
}, 0);
|
|
388
|
+
}
|
|
389
|
+
function onBackdropPointerDown(e) {
|
|
390
|
+
// Consume the pointer sequence so it cannot activate elements behind the backdrop.
|
|
391
|
+
e.preventDefault();
|
|
392
|
+
e.stopPropagation();
|
|
393
|
+
store.setOpened(false);
|
|
394
|
+
}
|
|
395
|
+
function onOptionPointerDown(e, index) {
|
|
396
|
+
// Commit selection before blur/focusout closes the popover on some browsers.
|
|
397
|
+
e.preventDefault();
|
|
398
|
+
e.stopPropagation();
|
|
399
|
+
onOptionSubmit(index);
|
|
400
|
+
}
|
|
401
|
+
function syncInsideDialogFlag() {
|
|
402
|
+
insideDialog = !!anchorEl?.closest("dialog, [role=\"dialog\"]");
|
|
403
|
+
}
|
|
404
|
+
// Public API via bind:this
|
|
405
|
+
export function clear() {
|
|
406
|
+
onClear();
|
|
407
|
+
}
|
|
408
|
+
export function close() {
|
|
409
|
+
store.setOpened(false);
|
|
410
|
+
activeOptionIndex = null;
|
|
411
|
+
}
|
|
412
|
+
export function focus() {
|
|
413
|
+
suppressOpenOnFocus = false;
|
|
414
|
+
targetRef?.focus();
|
|
415
|
+
}
|
|
416
|
+
export function getValue() {
|
|
417
|
+
return value;
|
|
418
|
+
}
|
|
419
|
+
export function open() {
|
|
420
|
+
if (disabled) return;
|
|
421
|
+
store.setOpened(true);
|
|
422
|
+
activeOptionIndex = null;
|
|
423
|
+
}
|
|
424
|
+
export function refetch() {
|
|
425
|
+
return store.refetch();
|
|
426
|
+
}
|
|
427
|
+
export function setValue(val) {
|
|
428
|
+
value = val;
|
|
429
|
+
onChange?.(val);
|
|
430
|
+
}
|
|
431
|
+
$effect(() => {
|
|
432
|
+
if (!$store.opened || effectiveDisablePortal || disabled) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
updatePopoverPosition();
|
|
436
|
+
if (typeof window === "undefined") {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const onWindowChange = () => {
|
|
440
|
+
updatePopoverPosition();
|
|
441
|
+
};
|
|
442
|
+
window.addEventListener("resize", onWindowChange);
|
|
443
|
+
window.addEventListener("scroll", onWindowChange, true);
|
|
444
|
+
return () => {
|
|
445
|
+
window.removeEventListener("resize", onWindowChange);
|
|
446
|
+
window.removeEventListener("scroll", onWindowChange, true);
|
|
447
|
+
};
|
|
448
|
+
});
|
|
449
|
+
$effect(() => {
|
|
450
|
+
if (!$store.opened || disabled) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
const overlay = registerOverlay({
|
|
454
|
+
kind: "popover",
|
|
455
|
+
mount: effectiveDisablePortal ? "inline" : "portal"
|
|
456
|
+
});
|
|
457
|
+
backdropZ = overlay.layer.backdrop;
|
|
458
|
+
dropdownZ = overlay.layer.content;
|
|
459
|
+
return () => {
|
|
460
|
+
overlay.unregister();
|
|
461
|
+
backdropZ = 1090;
|
|
462
|
+
dropdownZ = 1100;
|
|
463
|
+
};
|
|
464
|
+
});
|
|
465
|
+
$effect(() => {
|
|
466
|
+
void anchorEl;
|
|
467
|
+
void storeOpened;
|
|
468
|
+
syncInsideDialogFlag();
|
|
469
|
+
});
|
|
470
|
+
$effect(() => {
|
|
471
|
+
if (!$store.opened || !effectiveDisablePortal || disabled || typeof window === "undefined") {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const onDocumentPointerDown = (event) => {
|
|
475
|
+
const target = event.target;
|
|
476
|
+
if (!target) return;
|
|
477
|
+
const insideAnchor = !!anchorEl?.contains(target);
|
|
478
|
+
const insideDropdown = !!dropdownEl?.contains(target);
|
|
479
|
+
if (!insideAnchor && !insideDropdown) {
|
|
480
|
+
store.setOpened(false);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
window.addEventListener("pointerdown", onDocumentPointerDown, true);
|
|
484
|
+
return () => window.removeEventListener("pointerdown", onDocumentPointerDown, true);
|
|
485
|
+
});
|
|
603
486
|
</script>
|
|
604
487
|
|
|
605
488
|
<div
|
|
@@ -631,6 +514,7 @@
|
|
|
631
514
|
{inputId}
|
|
632
515
|
{label}
|
|
633
516
|
{leftSection}
|
|
517
|
+
{name}
|
|
634
518
|
{placeholder}
|
|
635
519
|
isFetching={$store.isFetching}
|
|
636
520
|
search={$store.input}
|
|
@@ -657,6 +541,7 @@
|
|
|
657
541
|
<div
|
|
658
542
|
class="fixed inset-0"
|
|
659
543
|
data-testid="boxer-backdrop"
|
|
544
|
+
role="presentation"
|
|
660
545
|
onpointerdown={onBackdropPointerDown}
|
|
661
546
|
style:z-index={backdropZ}
|
|
662
547
|
></div>
|
|
@@ -670,6 +555,7 @@
|
|
|
670
555
|
data-testid="boxer-dropdown"
|
|
671
556
|
id={listboxId}
|
|
672
557
|
role="listbox"
|
|
558
|
+
tabindex="-1"
|
|
673
559
|
aria-label={label ?? "Options"}
|
|
674
560
|
onpointerdown={markDropdownPointerInteraction}
|
|
675
561
|
style:z-index={dropdownZ}
|