@placeholderco/placeholder-ui 2.1.1 → 2.2.0
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/dist/editors/CodeMirror.svelte +295 -297
- package/dist/editors/tiptap/LinkActionMenu.svelte +6 -1
- package/dist/editors/tiptap/extensions/Alert.js +17 -17
- package/dist/editors/tiptap/extensions/Div.js +19 -19
- package/dist/editors/tiptap/extensions/Span.js +14 -14
- package/dist/editors/tiptap/toolbar/AlertButton.svelte +254 -253
- package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/AlignRightButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/BoldButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/BulletListButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/CodeButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/ColorButton.svelte +265 -265
- package/dist/editors/tiptap/toolbar/DocumentButton.svelte +51 -51
- package/dist/editors/tiptap/toolbar/HeadingButton.svelte +21 -21
- package/dist/editors/tiptap/toolbar/HtmlButton.svelte +48 -52
- package/dist/editors/tiptap/toolbar/ImageButton.svelte +35 -39
- package/dist/editors/tiptap/toolbar/ItalicButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/LinkButton.svelte +249 -249
- package/dist/editors/tiptap/toolbar/OrderedListButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/RedoButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/SubscriptButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/TableButton.svelte +231 -224
- package/dist/editors/tiptap/toolbar/ToolbarButton.svelte +59 -65
- package/dist/editors/tiptap/toolbar/UnderlineButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/UndoButton.svelte +11 -11
- package/dist/form/Autocomplete.svelte +24 -22
- package/dist/form/AutocompleteMulti.svelte +24 -22
- package/dist/form/Checkbox.svelte +4 -4
- package/dist/form/Chips.svelte +15 -7
- package/dist/form/ColorPicker.svelte +5 -20
- package/dist/form/ComboBox.svelte +4 -4
- package/dist/form/ComboBoxItemBuilder.svelte +14 -32
- package/dist/form/ComboBoxMulti.svelte +7 -3
- package/dist/form/CronBuilder.svelte +32 -110
- package/dist/form/DatePicker.svelte +9 -28
- package/dist/form/DateRangePicker.svelte +46 -36
- package/dist/form/DateTimePicker.svelte +11 -30
- package/dist/form/Number.svelte +1 -3
- package/dist/form/RadioGroup.svelte +1 -3
- package/dist/form/Select.svelte +25 -28
- package/dist/form/SelectMulti.svelte +36 -38
- package/dist/form/StringArrayBuilder.svelte +1 -3
- package/dist/form/TextArea.svelte +5 -6
- package/dist/form/Textbox.svelte +10 -4
- package/dist/form/TimePicker.svelte +10 -4
- package/dist/icon/Icon.svelte +5 -1
- package/dist/index.d.ts +147 -146
- package/dist/index.js +78 -77
- package/dist/layout/CustomNavbar.svelte +1 -1
- package/dist/layout/NavbarItemDisplay.svelte +1 -1
- package/dist/layout/NavbarItemView.svelte +3 -1
- package/dist/layout/Sidenav.svelte +1 -1
- package/dist/models/ComboBoxItem.d.ts +4 -4
- package/dist/models/NotifyModel.js +0 -1
- package/dist/theme.svelte.d.ts +1 -1
- package/dist/theme.svelte.js +46 -22
- package/dist/ui/Accordion.svelte +1 -3
- package/dist/ui/Badge.svelte +4 -5
- package/dist/ui/Button.svelte +7 -1
- package/dist/ui/ContextMenu.svelte +5 -11
- package/dist/ui/Dialog.svelte +16 -3
- package/dist/ui/Dialog.svelte.d.ts +7 -1
- package/dist/ui/Dropdown.svelte +21 -10
- package/dist/ui/MultiSortable.svelte +1 -3
- package/dist/ui/Pagination.svelte +2 -2
- package/dist/ui/Popover.svelte +16 -37
- package/dist/ui/ProgressBar.svelte +1 -4
- package/dist/ui/ThemeSwitcher.svelte +2 -1
- package/dist/ui/Tooltip.svelte +1 -37
- package/dist/util/DateFunctions.js +1 -1
- package/dist/util/Floating.d.ts +70 -0
- package/dist/util/Floating.js +321 -0
- package/dist/util/NavigateTo.js +2 -2
- package/dist/util/Transitions.d.ts +1 -1
- package/dist/util/Transitions.js +1 -1
- package/package.json +1 -1
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import type { Editor } from '@tiptap/core';
|
|
3
|
+
import ToolbarButton from './ToolbarButton.svelte';
|
|
4
|
+
import { iconArrowBackUp } from '../../../icon/index.js';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
interface Props {
|
|
7
|
+
editor: Editor;
|
|
8
|
+
}
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
let { editor }: Props = $props();
|
|
11
11
|
</script>
|
|
12
12
|
|
|
13
13
|
<ToolbarButton
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
icon={iconArrowBackUp}
|
|
15
|
+
title="Undo"
|
|
16
|
+
disabled={!editor.can().undo()}
|
|
17
|
+
onclick={() => editor.chain().focus().undo().run()}
|
|
18
18
|
/>
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
<script lang="ts">
|
|
82
82
|
import ComboBoxMulti from './ComboBoxMulti.svelte';
|
|
83
83
|
import { clickOutside } from '../util/ClickOutside.js';
|
|
84
|
+
import { floating } from '../util/Floating.js';
|
|
84
85
|
import Textbox from './Textbox.svelte';
|
|
85
86
|
import { ComboBoxCore, findItemByValue } from './comboBoxCore.svelte.js';
|
|
86
87
|
import { tick } from 'svelte';
|
|
@@ -258,6 +259,7 @@
|
|
|
258
259
|
|
|
259
260
|
let textboxElement: HTMLElement | undefined = $state(undefined);
|
|
260
261
|
let comboBoxEl: ReturnType<typeof ComboBoxMulti> | undefined = $state(undefined);
|
|
262
|
+
let containerElement: HTMLElement | undefined = $state(undefined);
|
|
261
263
|
|
|
262
264
|
function onKeyDown(e: KeyboardEvent) {
|
|
263
265
|
if (!open) {
|
|
@@ -289,7 +291,7 @@
|
|
|
289
291
|
}
|
|
290
292
|
</script>
|
|
291
293
|
|
|
292
|
-
<div class="autocomplete-container">
|
|
294
|
+
<div class="autocomplete-container" bind:this={containerElement}>
|
|
293
295
|
<Textbox
|
|
294
296
|
{name}
|
|
295
297
|
type="search"
|
|
@@ -316,21 +318,27 @@
|
|
|
316
318
|
onfocus={onFocus}
|
|
317
319
|
onkeydown={onKeyDown}
|
|
318
320
|
/>
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
321
|
+
{#if open}
|
|
322
|
+
<!-- Rendered in the top layer so a scrolling Dialog body cannot clip it -->
|
|
323
|
+
<div
|
|
324
|
+
class="autocomplete-panel"
|
|
325
|
+
use:floating={{ anchor: () => containerElement, placement: 'bottom-start', matchWidth: true }}
|
|
326
|
+
>
|
|
327
|
+
<div class="autocomplete-panel-inner" use:clickOutside={closePopover}>
|
|
328
|
+
<ComboBoxMulti
|
|
329
|
+
bind:this={comboBoxEl}
|
|
330
|
+
filterString={value}
|
|
331
|
+
values={rawValue ? [rawValue] : []}
|
|
332
|
+
{onSelection}
|
|
333
|
+
groupedOptions={displayGroups}
|
|
334
|
+
{open}
|
|
335
|
+
loading={core.searching}
|
|
336
|
+
{hideNoResults}
|
|
337
|
+
{loadingText}
|
|
338
|
+
/>
|
|
339
|
+
</div>
|
|
332
340
|
</div>
|
|
333
|
-
|
|
341
|
+
{/if}
|
|
334
342
|
</div>
|
|
335
343
|
|
|
336
344
|
<style>
|
|
@@ -338,10 +346,8 @@
|
|
|
338
346
|
position: relative;
|
|
339
347
|
}
|
|
340
348
|
|
|
349
|
+
/* Position, width and top-layer promotion come from use:floating */
|
|
341
350
|
.autocomplete-panel {
|
|
342
|
-
position: absolute;
|
|
343
|
-
width: 100%;
|
|
344
|
-
left: 0;
|
|
345
351
|
z-index: 70;
|
|
346
352
|
}
|
|
347
353
|
|
|
@@ -349,8 +355,4 @@
|
|
|
349
355
|
position: relative;
|
|
350
356
|
width: 100%;
|
|
351
357
|
}
|
|
352
|
-
|
|
353
|
-
.hidden {
|
|
354
|
-
display: none;
|
|
355
|
-
}
|
|
356
358
|
</style>
|
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
import ComboBoxMulti from './ComboBoxMulti.svelte';
|
|
87
87
|
import FormGroup from './FormGroup.svelte';
|
|
88
88
|
import { clickOutside } from '../util/ClickOutside.js';
|
|
89
|
+
import { floating } from '../util/Floating.js';
|
|
89
90
|
import { ComboBoxMultiCore } from './comboBoxCore.svelte.js';
|
|
90
91
|
import Icon from '../icon/Icon.svelte';
|
|
91
92
|
import Loader from '../ui/Loader.svelte';
|
|
@@ -305,6 +306,7 @@
|
|
|
305
306
|
|
|
306
307
|
let textboxElement: HTMLInputElement | undefined = $state(undefined);
|
|
307
308
|
let comboBoxEl: ReturnType<typeof ComboBoxMulti> | undefined = $state(undefined);
|
|
309
|
+
let containerElement: HTMLElement | undefined = $state(undefined);
|
|
308
310
|
|
|
309
311
|
function onKeyDown(e: KeyboardEvent) {
|
|
310
312
|
if (e.key === 'Backspace' && filterValue.length === 0 && rawValues.length > 0) {
|
|
@@ -348,7 +350,7 @@
|
|
|
348
350
|
});
|
|
349
351
|
</script>
|
|
350
352
|
|
|
351
|
-
<div class="autocomplete-multi-container {containerClass}">
|
|
353
|
+
<div class="autocomplete-multi-container {containerClass}" bind:this={containerElement}>
|
|
352
354
|
<FormGroup
|
|
353
355
|
{label}
|
|
354
356
|
{required}
|
|
@@ -414,21 +416,27 @@
|
|
|
414
416
|
</div>
|
|
415
417
|
</FormGroup>
|
|
416
418
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
419
|
+
{#if open}
|
|
420
|
+
<!-- Rendered in the top layer so a scrolling Dialog body cannot clip it -->
|
|
421
|
+
<div
|
|
422
|
+
class="autocomplete-panel"
|
|
423
|
+
use:floating={{ anchor: () => containerElement, placement: 'bottom-start', matchWidth: true }}
|
|
424
|
+
>
|
|
425
|
+
<div class="autocomplete-panel-inner" use:clickOutside={closePopover}>
|
|
426
|
+
<ComboBoxMulti
|
|
427
|
+
bind:this={comboBoxEl}
|
|
428
|
+
filterString={filterValue}
|
|
429
|
+
values={rawValues}
|
|
430
|
+
{onSelection}
|
|
431
|
+
groupedOptions={displayGroups}
|
|
432
|
+
{open}
|
|
433
|
+
loading={core.searching}
|
|
434
|
+
{hideNoResults}
|
|
435
|
+
{loadingText}
|
|
436
|
+
/>
|
|
437
|
+
</div>
|
|
430
438
|
</div>
|
|
431
|
-
|
|
439
|
+
{/if}
|
|
432
440
|
</div>
|
|
433
441
|
|
|
434
442
|
<style>
|
|
@@ -496,10 +504,8 @@
|
|
|
496
504
|
line-height: 0;
|
|
497
505
|
}
|
|
498
506
|
|
|
507
|
+
/* Position, width and top-layer promotion come from use:floating */
|
|
499
508
|
.autocomplete-panel {
|
|
500
|
-
position: absolute;
|
|
501
|
-
width: 100%;
|
|
502
|
-
left: 0;
|
|
503
509
|
z-index: 70;
|
|
504
510
|
}
|
|
505
511
|
|
|
@@ -507,8 +513,4 @@
|
|
|
507
513
|
position: relative;
|
|
508
514
|
width: 100%;
|
|
509
515
|
}
|
|
510
|
-
|
|
511
|
-
.hidden {
|
|
512
|
-
display: none;
|
|
513
|
-
}
|
|
514
516
|
</style>
|
|
@@ -63,14 +63,14 @@
|
|
|
63
63
|
const autoName = `checkbox-${crypto.randomUUID()}`;
|
|
64
64
|
const nonce = Math.random().toString(36).substring(2, 15);
|
|
65
65
|
|
|
66
|
-
let resolvedName = $derived(
|
|
67
|
-
(name || label || autoName).replace(/[^a-zA-Z0-9_\-:.]/g, '_')
|
|
68
|
-
);
|
|
66
|
+
let resolvedName = $derived((name || label || autoName).replace(/[^a-zA-Z0-9_\-:.]/g, '_'));
|
|
69
67
|
|
|
70
68
|
const id = $derived(inputId ? inputId : label ? `input-${label}` : `input-${nonce}`);
|
|
71
69
|
|
|
72
70
|
let inputEl = $state<HTMLInputElement>();
|
|
73
|
-
$effect(() => {
|
|
71
|
+
$effect(() => {
|
|
72
|
+
if (inputEl) inputEl.indeterminate = indeterminate;
|
|
73
|
+
});
|
|
74
74
|
</script>
|
|
75
75
|
|
|
76
76
|
<div class="checkbox-container {disabled ? 'disabled' : ''}">
|
package/dist/form/Chips.svelte
CHANGED
|
@@ -84,8 +84,6 @@
|
|
|
84
84
|
onchange?.(values.length > 0 ? values : undefined);
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
87
|
</script>
|
|
90
88
|
|
|
91
89
|
<div class="radio-container {containerClass}">
|
|
@@ -102,15 +100,25 @@
|
|
|
102
100
|
{@const hasSelection = multiple ? values.length > 0 : value !== undefined}
|
|
103
101
|
{@const chipVariant = checked
|
|
104
102
|
? (selectedVariant ?? variant)
|
|
105
|
-
:
|
|
103
|
+
: deselectedVariant && (multiple || hasSelection)
|
|
104
|
+
? deselectedVariant
|
|
105
|
+
: variant}
|
|
106
106
|
<div class="flex">
|
|
107
107
|
{#if checked}
|
|
108
|
-
<Button
|
|
109
|
-
|
|
108
|
+
<Button
|
|
109
|
+
class="chip checked"
|
|
110
|
+
{disabled}
|
|
111
|
+
onclick={() => handleChange(option)}
|
|
112
|
+
svg={iconCheck}
|
|
113
|
+
iconSize={'16px'}
|
|
114
|
+
variant={chipVariant}>{option.label}</Button
|
|
110
115
|
>
|
|
111
116
|
{:else}
|
|
112
|
-
<Button
|
|
113
|
-
|
|
117
|
+
<Button
|
|
118
|
+
class="chip"
|
|
119
|
+
{disabled}
|
|
120
|
+
onclick={() => handleChange(option)}
|
|
121
|
+
variant={chipVariant}>{option.label}</Button
|
|
114
122
|
>
|
|
115
123
|
{/if}
|
|
116
124
|
</div>
|
|
@@ -205,6 +205,7 @@
|
|
|
205
205
|
import FormGroup from './FormGroup.svelte';
|
|
206
206
|
import ActionIcon from '../ui/ActionIcon.svelte';
|
|
207
207
|
import { clickOutside } from '../util/ClickOutside.js';
|
|
208
|
+
import { floating } from '../util/Floating.js';
|
|
208
209
|
import { iconX, iconPalette } from '../icon/index.js';
|
|
209
210
|
|
|
210
211
|
const autoName = `colorpicker-${crypto.randomUUID()}`;
|
|
@@ -306,19 +307,10 @@
|
|
|
306
307
|
|
|
307
308
|
// --- Popup -----------------------------------------------------------------
|
|
308
309
|
let open = $state(false);
|
|
309
|
-
let dropdownPosition: 'above' | 'below' = $state('below');
|
|
310
310
|
let triggerEl: HTMLElement | undefined = $state();
|
|
311
311
|
|
|
312
|
-
function checkDropdownPosition() {
|
|
313
|
-
if (!triggerEl) return;
|
|
314
|
-
const rect = triggerEl.getBoundingClientRect();
|
|
315
|
-
const spaceBelow = window.innerHeight - rect.bottom;
|
|
316
|
-
dropdownPosition = spaceBelow < 320 && rect.top > 320 ? 'above' : 'below';
|
|
317
|
-
}
|
|
318
|
-
|
|
319
312
|
function toggle() {
|
|
320
313
|
if (disabled) return;
|
|
321
|
-
if (!open) checkDropdownPosition();
|
|
322
314
|
open = !open;
|
|
323
315
|
}
|
|
324
316
|
|
|
@@ -511,11 +503,13 @@
|
|
|
511
503
|
</div>
|
|
512
504
|
|
|
513
505
|
{#if open}
|
|
506
|
+
<!-- Rendered in the top layer so a scrolling Dialog body cannot clip it -->
|
|
514
507
|
<div
|
|
515
|
-
class="panel
|
|
508
|
+
class="panel"
|
|
516
509
|
role="dialog"
|
|
517
510
|
aria-label="Colour picker"
|
|
518
511
|
transition:fade={{ duration: 150 }}
|
|
512
|
+
use:floating={{ anchor: () => triggerEl, placement: 'bottom-start', offset: 4 }}
|
|
519
513
|
use:clickOutside={onClickOutside}
|
|
520
514
|
>
|
|
521
515
|
<div
|
|
@@ -773,10 +767,9 @@
|
|
|
773
767
|
}
|
|
774
768
|
|
|
775
769
|
/* ---- Panel ----------------------------------------------------------- */
|
|
770
|
+
/* Position and top-layer promotion come from use:floating */
|
|
776
771
|
.panel {
|
|
777
|
-
position: absolute;
|
|
778
772
|
z-index: 10;
|
|
779
|
-
left: 0;
|
|
780
773
|
width: 16rem;
|
|
781
774
|
padding: 0.75rem;
|
|
782
775
|
display: flex;
|
|
@@ -789,14 +782,6 @@
|
|
|
789
782
|
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
|
790
783
|
}
|
|
791
784
|
|
|
792
|
-
.panel.below {
|
|
793
|
-
top: calc(100% + 0.25rem);
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
.panel.above {
|
|
797
|
-
bottom: calc(100% + 0.25rem);
|
|
798
|
-
}
|
|
799
|
-
|
|
800
785
|
.sv-area {
|
|
801
786
|
position: relative;
|
|
802
787
|
width: 100%;
|
|
@@ -78,9 +78,7 @@
|
|
|
78
78
|
{:else}
|
|
79
79
|
<div class="combobox-panel">
|
|
80
80
|
{#each options as option, index}
|
|
81
|
-
{@const localClasses = [
|
|
82
|
-
selectedIndex === index ? 'selected p-2' : 'p-2'
|
|
83
|
-
]}
|
|
81
|
+
{@const localClasses = [selectedIndex === index ? 'selected p-2' : 'p-2']}
|
|
84
82
|
<button
|
|
85
83
|
class="combobox-item {localClasses} {option.class}"
|
|
86
84
|
class:selected={selectedIndex === index}
|
|
@@ -150,7 +148,9 @@
|
|
|
150
148
|
padding: 0.5rem;
|
|
151
149
|
}
|
|
152
150
|
|
|
153
|
-
.error,
|
|
151
|
+
.error,
|
|
152
|
+
.loading,
|
|
153
|
+
.no-results {
|
|
154
154
|
padding: 0.5rem;
|
|
155
155
|
}
|
|
156
156
|
|
|
@@ -84,16 +84,12 @@
|
|
|
84
84
|
|
|
85
85
|
// Check if a value already exists (excluding a specific index for editing)
|
|
86
86
|
function valueExists(value: string, excludeIndex: number | undefined = undefined): boolean {
|
|
87
|
-
return items.some((item, i) =>
|
|
88
|
-
item.value === value && i !== excludeIndex
|
|
89
|
-
);
|
|
87
|
+
return items.some((item, i) => item.value === value && i !== excludeIndex);
|
|
90
88
|
}
|
|
91
89
|
|
|
92
90
|
// Check if a label already exists (excluding a specific index for editing)
|
|
93
91
|
function labelExists(label: string, excludeIndex: number | undefined = undefined): boolean {
|
|
94
|
-
return items.some((item, i) =>
|
|
95
|
-
item.label === label && i !== excludeIndex
|
|
96
|
-
);
|
|
92
|
+
return items.some((item, i) => item.label === label && i !== excludeIndex);
|
|
97
93
|
}
|
|
98
94
|
|
|
99
95
|
function removeItem(index: number) {
|
|
@@ -103,9 +99,9 @@
|
|
|
103
99
|
// Remove from defaults if it was selected and no remaining item shares the value
|
|
104
100
|
if (
|
|
105
101
|
defaultValues.includes(removedItem.value) &&
|
|
106
|
-
!items.some(item => item.value === removedItem.value)
|
|
102
|
+
!items.some((item) => item.value === removedItem.value)
|
|
107
103
|
) {
|
|
108
|
-
defaultValues = defaultValues.filter(v => v !== removedItem.value);
|
|
104
|
+
defaultValues = defaultValues.filter((v) => v !== removedItem.value);
|
|
109
105
|
}
|
|
110
106
|
|
|
111
107
|
notifyChange();
|
|
@@ -115,7 +111,7 @@
|
|
|
115
111
|
if (checked) {
|
|
116
112
|
defaultValues = [...defaultValues, value];
|
|
117
113
|
} else {
|
|
118
|
-
defaultValues = defaultValues.filter(v => v !== value);
|
|
114
|
+
defaultValues = defaultValues.filter((v) => v !== value);
|
|
119
115
|
}
|
|
120
116
|
notifyChange();
|
|
121
117
|
}
|
|
@@ -132,21 +128,14 @@
|
|
|
132
128
|
// If they were in sync, also update the value to maintain exact match (if it wouldn't create a duplicate)
|
|
133
129
|
if (wasInSync && (allowDuplicateValues || !valueExists(label, index))) {
|
|
134
130
|
const oldValue = currentItem.value;
|
|
135
|
-
items = items.map((item, i) =>
|
|
136
|
-
i === index ? { ...item, label, value: label } : item
|
|
137
|
-
);
|
|
131
|
+
items = items.map((item, i) => (i === index ? { ...item, label, value: label } : item));
|
|
138
132
|
|
|
139
133
|
// Update defaults if the value was changed and no remaining item shares the old value
|
|
140
|
-
if (
|
|
141
|
-
defaultValues.
|
|
142
|
-
!items.some(item => item.value === oldValue)
|
|
143
|
-
) {
|
|
144
|
-
defaultValues = defaultValues.map(v => v === oldValue ? label : v);
|
|
134
|
+
if (defaultValues.includes(oldValue) && !items.some((item) => item.value === oldValue)) {
|
|
135
|
+
defaultValues = defaultValues.map((v) => (v === oldValue ? label : v));
|
|
145
136
|
}
|
|
146
137
|
} else {
|
|
147
|
-
items = items.map((item, i) =>
|
|
148
|
-
i === index ? { ...item, label } : item
|
|
149
|
-
);
|
|
138
|
+
items = items.map((item, i) => (i === index ? { ...item, label } : item));
|
|
150
139
|
}
|
|
151
140
|
|
|
152
141
|
notifyChange();
|
|
@@ -157,16 +146,11 @@
|
|
|
157
146
|
if (!allowDuplicateValues && valueExists(newVal, index)) return;
|
|
158
147
|
|
|
159
148
|
const oldValue = items[index].value;
|
|
160
|
-
items = items.map((item, i) =>
|
|
161
|
-
i === index ? { ...item, value: newVal } : item
|
|
162
|
-
);
|
|
149
|
+
items = items.map((item, i) => (i === index ? { ...item, value: newVal } : item));
|
|
163
150
|
|
|
164
151
|
// Update defaults if the value was changed and no remaining item shares the old value
|
|
165
|
-
if (
|
|
166
|
-
defaultValues.
|
|
167
|
-
!items.some(item => item.value === oldValue)
|
|
168
|
-
) {
|
|
169
|
-
defaultValues = defaultValues.map(v => v === oldValue ? newVal : v);
|
|
152
|
+
if (defaultValues.includes(oldValue) && !items.some((item) => item.value === oldValue)) {
|
|
153
|
+
defaultValues = defaultValues.map((v) => (v === oldValue ? newVal : v));
|
|
170
154
|
}
|
|
171
155
|
|
|
172
156
|
notifyChange();
|
|
@@ -186,7 +170,7 @@
|
|
|
186
170
|
|
|
187
171
|
// Computed output for display/copying
|
|
188
172
|
let outputItems = $derived(
|
|
189
|
-
items.map(item => ({
|
|
173
|
+
items.map((item) => ({
|
|
190
174
|
...item,
|
|
191
175
|
selected: defaultValues.includes(item.value)
|
|
192
176
|
}))
|
|
@@ -194,9 +178,7 @@
|
|
|
194
178
|
|
|
195
179
|
// Get labels for selected defaults
|
|
196
180
|
let defaultLabels = $derived(
|
|
197
|
-
defaultValues
|
|
198
|
-
.map(v => items.find(i => i.value === v)?.label ?? v)
|
|
199
|
-
.join(', ')
|
|
181
|
+
defaultValues.map((v) => items.find((i) => i.value === v)?.label ?? v).join(', ')
|
|
200
182
|
);
|
|
201
183
|
</script>
|
|
202
184
|
|
|
@@ -103,7 +103,9 @@
|
|
|
103
103
|
<div class="group-label">{group.label}</div>
|
|
104
104
|
{/if}
|
|
105
105
|
{#each group.items as option, localIndex}
|
|
106
|
-
{@const globalIndex =
|
|
106
|
+
{@const globalIndex =
|
|
107
|
+
groupedOptions.slice(0, groupIndex).reduce((acc, g) => acc + g.items.length, 0) +
|
|
108
|
+
localIndex}
|
|
107
109
|
{@const localClasses = [selectedIndex === globalIndex ? 'selected p-2' : 'p-2']}
|
|
108
110
|
<button
|
|
109
111
|
class="combobox-item {localClasses.join(' ')} {option.class}"
|
|
@@ -141,7 +143,7 @@
|
|
|
141
143
|
} */
|
|
142
144
|
|
|
143
145
|
.combobox-multi {
|
|
144
|
-
position:
|
|
146
|
+
position: relative;
|
|
145
147
|
width: 100%;
|
|
146
148
|
z-index: 50;
|
|
147
149
|
border-radius: 0.25rem;
|
|
@@ -154,7 +156,9 @@
|
|
|
154
156
|
|
|
155
157
|
.combobox-multi-panel {
|
|
156
158
|
overflow: auto;
|
|
157
|
-
max-height
|
|
159
|
+
/* --ui-floating-max-height is set by the floating action to the room left
|
|
160
|
+
on the chosen side, so long lists shrink rather than run off-screen */
|
|
161
|
+
max-height: min(20rem, var(--ui-floating-max-height, 20rem));
|
|
158
162
|
border: 1px solid var(--border-color);
|
|
159
163
|
border-top: none;
|
|
160
164
|
/* max-h-80 overflow-auto */
|