svelte-select-5 6.1.9 → 6.2.1
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/Select.svelte +71 -49
- package/no-styles/Select.svelte +71 -49
- package/package.json +1 -1
package/Select.svelte
CHANGED
|
@@ -151,6 +151,20 @@
|
|
|
151
151
|
requiredSlot: requiredSlotSnippet = undefined,
|
|
152
152
|
} = $props();
|
|
153
153
|
|
|
154
|
+
// Prop validation (runs once on init)
|
|
155
|
+
if (typeof itemId !== 'string') {
|
|
156
|
+
console.warn('[svelte-select-5] itemId must be a string, using "value"');
|
|
157
|
+
itemId = 'value';
|
|
158
|
+
}
|
|
159
|
+
if (typeof label !== 'string') {
|
|
160
|
+
console.warn('[svelte-select-5] label must be a string, using "label"');
|
|
161
|
+
label = 'label';
|
|
162
|
+
}
|
|
163
|
+
if (loadOptions !== undefined && typeof loadOptions !== 'function') {
|
|
164
|
+
console.warn('[svelte-select-5] loadOptions must be a function');
|
|
165
|
+
loadOptions = undefined;
|
|
166
|
+
}
|
|
167
|
+
|
|
154
168
|
// Internal state
|
|
155
169
|
let timeout;
|
|
156
170
|
let activeValue = $state(undefined);
|
|
@@ -162,6 +176,8 @@
|
|
|
162
176
|
let prefloat = $state(true);
|
|
163
177
|
let _inputAttributes = $state({});
|
|
164
178
|
let prevJustValue = $state(undefined);
|
|
179
|
+
let pendingJustValue = $state(undefined);
|
|
180
|
+
let loadRequestVersion = 0;
|
|
165
181
|
let isScrollingTimer;
|
|
166
182
|
|
|
167
183
|
// Floating UI config - using closure for listOffset to capture current value
|
|
@@ -319,7 +335,9 @@
|
|
|
319
335
|
|
|
320
336
|
if (loadOptions) {
|
|
321
337
|
debounce(async function () {
|
|
338
|
+
const currentVersion = ++loadRequestVersion;
|
|
322
339
|
loading = true;
|
|
340
|
+
|
|
323
341
|
let res = await getItems({
|
|
324
342
|
dispatch: (event, data) => {
|
|
325
343
|
if (event === 'error') onerror?.(data);
|
|
@@ -330,6 +348,11 @@
|
|
|
330
348
|
filterText,
|
|
331
349
|
});
|
|
332
350
|
|
|
351
|
+
// Ignore stale responses from earlier requests
|
|
352
|
+
if (currentVersion !== loadRequestVersion) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
333
356
|
if (res) {
|
|
334
357
|
loading = res.loading;
|
|
335
358
|
listOpen = listOpen ? res.listOpen : filterText.length > 0 ? true : false;
|
|
@@ -351,8 +374,12 @@
|
|
|
351
374
|
}
|
|
352
375
|
|
|
353
376
|
function computeJustValue() {
|
|
354
|
-
if (
|
|
355
|
-
|
|
377
|
+
if (!value) return multiple ? null : undefined;
|
|
378
|
+
if (multiple) {
|
|
379
|
+
return value.map((item) => item?.[itemId]).filter(id => id !== undefined);
|
|
380
|
+
}
|
|
381
|
+
const id = value[itemId];
|
|
382
|
+
return id !== undefined ? id : undefined;
|
|
356
383
|
}
|
|
357
384
|
|
|
358
385
|
function checkValueForDuplicates() {
|
|
@@ -736,24 +763,21 @@
|
|
|
736
763
|
if (inputAttributes || !searchable) assignInputAttributes();
|
|
737
764
|
});
|
|
738
765
|
|
|
766
|
+
// Consolidated: Multiple-mode effects
|
|
739
767
|
$effect(() => {
|
|
740
|
-
if (multiple)
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
$effect(() => {
|
|
748
|
-
if (multiple && value && value.length > 1) checkValueForDuplicates();
|
|
749
|
-
});
|
|
750
|
-
|
|
751
|
-
$effect(() => {
|
|
752
|
-
if (value) dispatchSelectedItem();
|
|
768
|
+
if (multiple) {
|
|
769
|
+
setupMulti();
|
|
770
|
+
if (value && value.length > 1) checkValueForDuplicates();
|
|
771
|
+
} else if (prev_multiple) {
|
|
772
|
+
setupSingle();
|
|
773
|
+
}
|
|
753
774
|
});
|
|
754
775
|
|
|
776
|
+
// Consolidated: Value change effects
|
|
755
777
|
$effect(() => {
|
|
756
|
-
if (
|
|
778
|
+
if (value) {
|
|
779
|
+
dispatchSelectedItem();
|
|
780
|
+
} else if (prev_value) {
|
|
757
781
|
oninput?.(value);
|
|
758
782
|
}
|
|
759
783
|
});
|
|
@@ -770,10 +794,6 @@
|
|
|
770
794
|
if (!multiple && listOpen && value && filteredItems) setValueIndexAsHoverIndex();
|
|
771
795
|
});
|
|
772
796
|
|
|
773
|
-
$effect(() => {
|
|
774
|
-
dispatchHover(hoverItemIndex);
|
|
775
|
-
});
|
|
776
|
-
|
|
777
797
|
$effect(() => {
|
|
778
798
|
updateValueDisplay(items);
|
|
779
799
|
});
|
|
@@ -782,6 +802,15 @@
|
|
|
782
802
|
justValue = computeJustValue();
|
|
783
803
|
});
|
|
784
804
|
|
|
805
|
+
// Helper function to resolve justValue to value
|
|
806
|
+
function resolveJustValue(jv) {
|
|
807
|
+
if (multiple) {
|
|
808
|
+
value = jv ? items.filter(item => jv.includes(item[itemId])) : null;
|
|
809
|
+
} else {
|
|
810
|
+
value = jv != null ? items.find(item => item[itemId] === jv) ?? null : null;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
785
814
|
// Handle external changes to justValue (allows setting value via justValue)
|
|
786
815
|
// Also handles case where justValue is set before items are loaded
|
|
787
816
|
$effect(() => {
|
|
@@ -789,21 +818,23 @@
|
|
|
789
818
|
const isExternalChange = justValue !== prevJustValue &&
|
|
790
819
|
JSON.stringify(justValue) !== JSON.stringify(computed);
|
|
791
820
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
if (needsValueUpdate && items) {
|
|
797
|
-
if (multiple) {
|
|
798
|
-
value = justValue
|
|
799
|
-
? items.filter(item => justValue.includes(item[itemId]))
|
|
800
|
-
: null;
|
|
821
|
+
if (isExternalChange) {
|
|
822
|
+
if (!items) {
|
|
823
|
+
// Items not loaded yet - save for later
|
|
824
|
+
pendingJustValue = justValue;
|
|
801
825
|
} else {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
826
|
+
// Items available - resolve immediately
|
|
827
|
+
resolveJustValue(justValue);
|
|
828
|
+
pendingJustValue = undefined;
|
|
805
829
|
}
|
|
806
830
|
}
|
|
831
|
+
|
|
832
|
+
// When items load and we have a pending justValue, resolve it
|
|
833
|
+
if (items && pendingJustValue !== undefined && !value) {
|
|
834
|
+
resolveJustValue(pendingJustValue);
|
|
835
|
+
pendingJustValue = undefined;
|
|
836
|
+
}
|
|
837
|
+
|
|
807
838
|
prevJustValue = justValue;
|
|
808
839
|
});
|
|
809
840
|
|
|
@@ -814,10 +845,6 @@
|
|
|
814
845
|
readonlyId = computeJustValue();
|
|
815
846
|
});
|
|
816
847
|
|
|
817
|
-
$effect(() => {
|
|
818
|
-
if (!multiple && prev_value && !value) oninput?.(value);
|
|
819
|
-
});
|
|
820
|
-
|
|
821
848
|
$effect(() => {
|
|
822
849
|
if (listOpen && filteredItems && !multiple && !value) checkHoverSelectable();
|
|
823
850
|
});
|
|
@@ -830,24 +857,19 @@
|
|
|
830
857
|
if (container && floatingConfig) floatingUpdate(Object.assign(_floatingConfig, floatingConfig));
|
|
831
858
|
});
|
|
832
859
|
|
|
860
|
+
// Consolidated: List open effects
|
|
833
861
|
$effect(() => {
|
|
834
862
|
listMounted(list, listOpen);
|
|
863
|
+
if (listOpen) {
|
|
864
|
+
if (container && list) setListWidth();
|
|
865
|
+
if (input && !focused) handleFocus();
|
|
866
|
+
}
|
|
835
867
|
});
|
|
836
868
|
|
|
869
|
+
// Consolidated: hoverItemIndex effects
|
|
837
870
|
$effect(() => {
|
|
838
|
-
if (
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
$effect(() => {
|
|
842
|
-
if (listOpen && multiple) hoverItemIndex = 0;
|
|
843
|
-
});
|
|
844
|
-
|
|
845
|
-
$effect(() => {
|
|
846
|
-
if (input && listOpen && !focused) handleFocus();
|
|
847
|
-
});
|
|
848
|
-
|
|
849
|
-
$effect(() => {
|
|
850
|
-
if (filterText) hoverItemIndex = 0;
|
|
871
|
+
if (filterText || (listOpen && multiple)) hoverItemIndex = 0;
|
|
872
|
+
dispatchHover(hoverItemIndex);
|
|
851
873
|
});
|
|
852
874
|
|
|
853
875
|
// Lifecycle
|
package/no-styles/Select.svelte
CHANGED
|
@@ -151,6 +151,20 @@
|
|
|
151
151
|
requiredSlot: requiredSlotSnippet = undefined,
|
|
152
152
|
} = $props();
|
|
153
153
|
|
|
154
|
+
// Prop validation (runs once on init)
|
|
155
|
+
if (typeof itemId !== 'string') {
|
|
156
|
+
console.warn('[svelte-select-5] itemId must be a string, using "value"');
|
|
157
|
+
itemId = 'value';
|
|
158
|
+
}
|
|
159
|
+
if (typeof label !== 'string') {
|
|
160
|
+
console.warn('[svelte-select-5] label must be a string, using "label"');
|
|
161
|
+
label = 'label';
|
|
162
|
+
}
|
|
163
|
+
if (loadOptions !== undefined && typeof loadOptions !== 'function') {
|
|
164
|
+
console.warn('[svelte-select-5] loadOptions must be a function');
|
|
165
|
+
loadOptions = undefined;
|
|
166
|
+
}
|
|
167
|
+
|
|
154
168
|
// Internal state
|
|
155
169
|
let timeout;
|
|
156
170
|
let activeValue = $state(undefined);
|
|
@@ -162,6 +176,8 @@
|
|
|
162
176
|
let prefloat = $state(true);
|
|
163
177
|
let _inputAttributes = $state({});
|
|
164
178
|
let prevJustValue = $state(undefined);
|
|
179
|
+
let pendingJustValue = $state(undefined);
|
|
180
|
+
let loadRequestVersion = 0;
|
|
165
181
|
let isScrollingTimer;
|
|
166
182
|
|
|
167
183
|
// Floating UI config - using closure for listOffset to capture current value
|
|
@@ -319,7 +335,9 @@
|
|
|
319
335
|
|
|
320
336
|
if (loadOptions) {
|
|
321
337
|
debounce(async function () {
|
|
338
|
+
const currentVersion = ++loadRequestVersion;
|
|
322
339
|
loading = true;
|
|
340
|
+
|
|
323
341
|
let res = await getItems({
|
|
324
342
|
dispatch: (event, data) => {
|
|
325
343
|
if (event === 'error') onerror?.(data);
|
|
@@ -330,6 +348,11 @@
|
|
|
330
348
|
filterText,
|
|
331
349
|
});
|
|
332
350
|
|
|
351
|
+
// Ignore stale responses from earlier requests
|
|
352
|
+
if (currentVersion !== loadRequestVersion) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
333
356
|
if (res) {
|
|
334
357
|
loading = res.loading;
|
|
335
358
|
listOpen = listOpen ? res.listOpen : filterText.length > 0 ? true : false;
|
|
@@ -351,8 +374,12 @@
|
|
|
351
374
|
}
|
|
352
375
|
|
|
353
376
|
function computeJustValue() {
|
|
354
|
-
if (
|
|
355
|
-
|
|
377
|
+
if (!value) return multiple ? null : undefined;
|
|
378
|
+
if (multiple) {
|
|
379
|
+
return value.map((item) => item?.[itemId]).filter(id => id !== undefined);
|
|
380
|
+
}
|
|
381
|
+
const id = value[itemId];
|
|
382
|
+
return id !== undefined ? id : undefined;
|
|
356
383
|
}
|
|
357
384
|
|
|
358
385
|
function checkValueForDuplicates() {
|
|
@@ -736,24 +763,21 @@
|
|
|
736
763
|
if (inputAttributes || !searchable) assignInputAttributes();
|
|
737
764
|
});
|
|
738
765
|
|
|
766
|
+
// Consolidated: Multiple-mode effects
|
|
739
767
|
$effect(() => {
|
|
740
|
-
if (multiple)
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
$effect(() => {
|
|
748
|
-
if (multiple && value && value.length > 1) checkValueForDuplicates();
|
|
749
|
-
});
|
|
750
|
-
|
|
751
|
-
$effect(() => {
|
|
752
|
-
if (value) dispatchSelectedItem();
|
|
768
|
+
if (multiple) {
|
|
769
|
+
setupMulti();
|
|
770
|
+
if (value && value.length > 1) checkValueForDuplicates();
|
|
771
|
+
} else if (prev_multiple) {
|
|
772
|
+
setupSingle();
|
|
773
|
+
}
|
|
753
774
|
});
|
|
754
775
|
|
|
776
|
+
// Consolidated: Value change effects
|
|
755
777
|
$effect(() => {
|
|
756
|
-
if (
|
|
778
|
+
if (value) {
|
|
779
|
+
dispatchSelectedItem();
|
|
780
|
+
} else if (prev_value) {
|
|
757
781
|
oninput?.(value);
|
|
758
782
|
}
|
|
759
783
|
});
|
|
@@ -770,10 +794,6 @@
|
|
|
770
794
|
if (!multiple && listOpen && value && filteredItems) setValueIndexAsHoverIndex();
|
|
771
795
|
});
|
|
772
796
|
|
|
773
|
-
$effect(() => {
|
|
774
|
-
dispatchHover(hoverItemIndex);
|
|
775
|
-
});
|
|
776
|
-
|
|
777
797
|
$effect(() => {
|
|
778
798
|
updateValueDisplay(items);
|
|
779
799
|
});
|
|
@@ -782,6 +802,15 @@
|
|
|
782
802
|
justValue = computeJustValue();
|
|
783
803
|
});
|
|
784
804
|
|
|
805
|
+
// Helper function to resolve justValue to value
|
|
806
|
+
function resolveJustValue(jv) {
|
|
807
|
+
if (multiple) {
|
|
808
|
+
value = jv ? items.filter(item => jv.includes(item[itemId])) : null;
|
|
809
|
+
} else {
|
|
810
|
+
value = jv != null ? items.find(item => item[itemId] === jv) ?? null : null;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
785
814
|
// Handle external changes to justValue (allows setting value via justValue)
|
|
786
815
|
// Also handles case where justValue is set before items are loaded
|
|
787
816
|
$effect(() => {
|
|
@@ -789,21 +818,23 @@
|
|
|
789
818
|
const isExternalChange = justValue !== prevJustValue &&
|
|
790
819
|
JSON.stringify(justValue) !== JSON.stringify(computed);
|
|
791
820
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
if (needsValueUpdate && items) {
|
|
797
|
-
if (multiple) {
|
|
798
|
-
value = justValue
|
|
799
|
-
? items.filter(item => justValue.includes(item[itemId]))
|
|
800
|
-
: null;
|
|
821
|
+
if (isExternalChange) {
|
|
822
|
+
if (!items) {
|
|
823
|
+
// Items not loaded yet - save for later
|
|
824
|
+
pendingJustValue = justValue;
|
|
801
825
|
} else {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
826
|
+
// Items available - resolve immediately
|
|
827
|
+
resolveJustValue(justValue);
|
|
828
|
+
pendingJustValue = undefined;
|
|
805
829
|
}
|
|
806
830
|
}
|
|
831
|
+
|
|
832
|
+
// When items load and we have a pending justValue, resolve it
|
|
833
|
+
if (items && pendingJustValue !== undefined && !value) {
|
|
834
|
+
resolveJustValue(pendingJustValue);
|
|
835
|
+
pendingJustValue = undefined;
|
|
836
|
+
}
|
|
837
|
+
|
|
807
838
|
prevJustValue = justValue;
|
|
808
839
|
});
|
|
809
840
|
|
|
@@ -814,10 +845,6 @@
|
|
|
814
845
|
readonlyId = computeJustValue();
|
|
815
846
|
});
|
|
816
847
|
|
|
817
|
-
$effect(() => {
|
|
818
|
-
if (!multiple && prev_value && !value) oninput?.(value);
|
|
819
|
-
});
|
|
820
|
-
|
|
821
848
|
$effect(() => {
|
|
822
849
|
if (listOpen && filteredItems && !multiple && !value) checkHoverSelectable();
|
|
823
850
|
});
|
|
@@ -830,24 +857,19 @@
|
|
|
830
857
|
if (container && floatingConfig) floatingUpdate(Object.assign(_floatingConfig, floatingConfig));
|
|
831
858
|
});
|
|
832
859
|
|
|
860
|
+
// Consolidated: List open effects
|
|
833
861
|
$effect(() => {
|
|
834
862
|
listMounted(list, listOpen);
|
|
863
|
+
if (listOpen) {
|
|
864
|
+
if (container && list) setListWidth();
|
|
865
|
+
if (input && !focused) handleFocus();
|
|
866
|
+
}
|
|
835
867
|
});
|
|
836
868
|
|
|
869
|
+
// Consolidated: hoverItemIndex effects
|
|
837
870
|
$effect(() => {
|
|
838
|
-
if (
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
$effect(() => {
|
|
842
|
-
if (listOpen && multiple) hoverItemIndex = 0;
|
|
843
|
-
});
|
|
844
|
-
|
|
845
|
-
$effect(() => {
|
|
846
|
-
if (input && listOpen && !focused) handleFocus();
|
|
847
|
-
});
|
|
848
|
-
|
|
849
|
-
$effect(() => {
|
|
850
|
-
if (filterText) hoverItemIndex = 0;
|
|
871
|
+
if (filterText || (listOpen && multiple)) hoverItemIndex = 0;
|
|
872
|
+
dispatchHover(hoverItemIndex);
|
|
851
873
|
});
|
|
852
874
|
|
|
853
875
|
// Lifecycle
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-select-5",
|
|
3
|
-
"version": "6.1
|
|
3
|
+
"version": "6.2.1",
|
|
4
4
|
"description": "A <Select> component for Svelte 5 apps (fork of svelte-select)",
|
|
5
5
|
"repository": "https://github.com/Dbone29/svelte-select-5.git",
|
|
6
6
|
"author": "Robert Balfré <rob.balfre@gmail.com> (https://github.com/rob-balfre)",
|