Skip to content

Commit 3fabb7b

Browse files
committed
Merge branch 'main' into next
2 parents 5053f64 + 1bba3f6 commit 3fabb7b

File tree

9 files changed

+309
-13
lines changed

9 files changed

+309
-13
lines changed

packages/svelte-ux/CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@
138138

139139
- fix(Progress): Fix `TypeError: Failed to set the 'value' property on 'HTMLProgressElement': The provided double value is non-finite.` ([`6c2efa2`](https://github.com/techniq/svelte-ux/commit/6c2efa2d6d5b1a7ccf2b99c1826bc1232c51d2cc))
140140

141+
## 1.0.8
142+
143+
### Patch Changes
144+
145+
- Fixed (Drawer/Dialog) open/close events firing on mount and unrelated updates. Now events are emitted only on actual state transitions by tracking the previous open value, preventing unintended closes and focus jumps. ([#632](https://github.com/techniq/svelte-ux/pull/632))
146+
Added (beforeOptions/afterOptions) slots to the (SelectField, MultiSelect, MultiSelectField, MultiSelectMenu) components.
147+
Updated docs examples (beforeOptions/afterOptions).
148+
149+
## 1.0.7
150+
151+
### Patch Changes
152+
153+
- feat(NumberStepper): Add slots to passthrough prefix and suffix to the NumberStepper component ([#629](https://github.com/techniq/svelte-ux/pull/629))
154+
141155
## 1.0.6
142156

143157
### Patch Changes

packages/svelte-ux/src/lib/components/Dialog.svelte

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,14 @@
7272
}
7373
}
7474
75-
$: if (open) {
76-
dispatch('open');
77-
} else {
78-
dispatch('close');
75+
let _wasOpen = open;
76+
$: if (open !== _wasOpen) {
77+
if (open) {
78+
dispatch('open');
79+
} else if (_wasOpen) {
80+
dispatch('close');
81+
}
82+
_wasOpen = open;
7983
}
8084
</script>
8185

packages/svelte-ux/src/lib/components/Drawer.svelte

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,14 @@
4848
}
4949
}
5050
51-
$: if (open) {
52-
dispatch('open');
53-
} else {
54-
dispatch('close');
51+
let _wasOpen = open;
52+
$: if (open !== _wasOpen) {
53+
if (open) {
54+
dispatch('open');
55+
} else if (_wasOpen) {
56+
dispatch('close');
57+
}
58+
_wasOpen = open;
5559
}
5660
</script>
5761

packages/svelte-ux/src/lib/components/NumberStepper.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
disabled={min != null && value <= min}
4545
/>
4646
</div>
47+
<div slot="prefix"><slot name="prefix" /></div>
48+
<div slot="suffix"><slot name="suffix" /></div>
4749
<div slot="append">
4850
<Button
4951
icon={icons.plus}

packages/svelte-ux/src/lib/components/SelectField.svelte

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@
242242
243243
function onChange(e: ComponentEvents<TextField>['change']) {
244244
logger.debug('onChange');
245-
246245
searchText = e.detail.inputValue as string;
247246
dispatch('inputChange', searchText);
248247
show();
@@ -262,7 +261,10 @@
262261
fe.relatedTarget instanceof HTMLElement &&
263262
!menuOptionsEl?.contains(fe.relatedTarget) && // TODO: Oddly Safari does not set `relatedTarget` to the clicked on menu option (like Chrome and Firefox) but instead appears to take `tabindex` into consideration. Currently resolves to `.options` after setting `tabindex="-1"
264263
fe.relatedTarget !== menuOptionsEl?.offsetParent && // click on scroll bar
265-
!fe.relatedTarget.closest('menu > [slot=actions]') && // click on action item
264+
// Allow focus to move into auxiliary slot areas (beforeOptions, afterOptions, actions)
265+
!fe.relatedTarget.closest(
266+
'menu > [slot=actions], menu > [slot=beforeOptions], menu > [slot=afterOptions]'
267+
) && // click on action / before / after item
266268
!selectFieldEl?.contains(fe.relatedTarget) && // click within <SelectField> (ex. toggleIcon)
267269
fe.relatedTarget !== selectFieldEl // click on SelectField itself
268270
) {
@@ -550,6 +552,7 @@
550552
on:close={() => hide('menu on:close')}
551553
{...menuProps}
552554
>
555+
<slot name="beforeOptions" {hide} />
553556
<!-- TODO: Rework into hierarchy of snippets in v2.0 -->
554557
<SelectListOptions
555558
bind:menuOptionsEl
@@ -605,6 +608,7 @@
605608
</svelte:fragment>
606609
</SelectListOptions>
607610

611+
<slot name="afterOptions" {hide} />
608612
<slot name="actions" {hide} />
609613
</Menu>
610614
{:else}

packages/svelte-ux/src/routes/docs/components/MultiSelect/+page.svelte

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
MultiSelect,
99
MultiSelectOption,
1010
ToggleButton,
11+
ToggleGroup,
12+
ToggleOption,
1113
} from 'svelte-ux';
1214
import Preview from '$lib/components/Preview.svelte';
1315
@@ -26,6 +28,15 @@
2628
}));
2729
2830
let value = [3];
31+
32+
// Filters (Any/Evens/Odds) for demos below
33+
let msSelectedStr: 'any' | 'even' | 'odds' = 'any';
34+
$: msOptionsFiltered =
35+
msSelectedStr === 'even'
36+
? options.filter((o) => typeof o.value === 'number' && o.value % 2 === 0)
37+
: msSelectedStr === 'odds'
38+
? options.filter((o) => typeof o.value === 'number' && o.value % 2 !== 0)
39+
: options;
2940
</script>
3041

3142
<h1>Examples</h1>
@@ -186,6 +197,64 @@
186197
</div>
187198
</Preview>
188199

200+
<h2>beforeOptions slot</h2>
201+
202+
<Preview>
203+
{value.length} selected
204+
<div class="flex flex-col max-h-[360px] overflow-auto">
205+
<MultiSelect
206+
options={msOptionsFiltered}
207+
{value}
208+
on:change={(e) => (value = e.detail.value)}
209+
search
210+
>
211+
<svelte:fragment slot="beforeOptions" let:selection>
212+
<div class="p-2 border-b">
213+
<ToggleGroup
214+
bind:value={msSelectedStr}
215+
classes={{ options: 'justify-start h-10' }}
216+
rounded="full"
217+
inset
218+
>
219+
<ToggleOption value="any">Any</ToggleOption>
220+
<ToggleOption value="even">Evens</ToggleOption>
221+
<ToggleOption value="odds">Odds</ToggleOption>
222+
</ToggleGroup>
223+
</div>
224+
</svelte:fragment>
225+
</MultiSelect>
226+
</div>
227+
</Preview>
228+
229+
<h2>afterOptions slot</h2>
230+
231+
<Preview>
232+
{value.length} selected
233+
<div class="flex flex-col max-h-[360px] overflow-auto">
234+
<MultiSelect
235+
options={msOptionsFiltered}
236+
{value}
237+
on:change={(e) => (value = e.detail.value)}
238+
search
239+
>
240+
<svelte:fragment slot="afterOptions" let:selection>
241+
<div class="p-2 border-t">
242+
<ToggleGroup
243+
bind:value={msSelectedStr}
244+
classes={{ options: 'justify-start h-10' }}
245+
rounded="full"
246+
inset
247+
>
248+
<ToggleOption value="any">Any</ToggleOption>
249+
<ToggleOption value="even">Evens</ToggleOption>
250+
<ToggleOption value="odds">Odds</ToggleOption>
251+
</ToggleGroup>
252+
</div>
253+
</svelte:fragment>
254+
</MultiSelect>
255+
</div>
256+
</Preview>
257+
189258
<h2>option slot with MultiSelectOption custom actions</h2>
190259

191260
<Preview>

packages/svelte-ux/src/routes/docs/components/MultiSelectField/+page.svelte

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
MultiSelectField,
99
MultiSelectOption,
1010
ToggleButton,
11+
ToggleGroup,
12+
ToggleOption,
1113
} from 'svelte-ux';
1214
import Preview from '$lib/components/Preview.svelte';
1315
@@ -26,6 +28,15 @@
2628
}));
2729
2830
let value: number[] | undefined = [3];
31+
32+
// Filters (Any/Evens/Odds) for demos below
33+
let msfSelectedStr: 'any' | 'even' | 'odds' = 'any';
34+
$: msfOptionsFiltered =
35+
msfSelectedStr === 'even'
36+
? options.filter((o) => typeof o.value === 'number' && o.value % 2 === 0)
37+
: msfSelectedStr === 'odds'
38+
? options.filter((o) => typeof o.value === 'number' && o.value % 2 !== 0)
39+
: options;
2940
</script>
3041

3142
<h1>Examples</h1>
@@ -182,6 +193,56 @@
182193
</MultiSelectField>
183194
</Preview>
184195

196+
<h2>beforeOptions slot</h2>
197+
198+
<Preview>
199+
<MultiSelectField
200+
options={msfOptionsFiltered}
201+
{value}
202+
on:change={(e) => (value = e.detail.value)}
203+
>
204+
<svelte:fragment slot="beforeOptions">
205+
<div class="p-2 border-b">
206+
<ToggleGroup
207+
bind:value={msfSelectedStr}
208+
classes={{ options: 'justify-start h-10' }}
209+
rounded="full"
210+
inset
211+
>
212+
<ToggleOption value="any">Any</ToggleOption>
213+
<ToggleOption value="even">Evens</ToggleOption>
214+
<ToggleOption value="odds">Odds</ToggleOption>
215+
</ToggleGroup>
216+
</div>
217+
</svelte:fragment>
218+
</MultiSelectField>
219+
</Preview>
220+
221+
<h2>afterOptions slot</h2>
222+
223+
<Preview>
224+
<MultiSelectField
225+
options={msfOptionsFiltered}
226+
{value}
227+
on:change={(e) => (value = e.detail.value)}
228+
>
229+
<svelte:fragment slot="afterOptions">
230+
<div class="p-2 border-t">
231+
<ToggleGroup
232+
bind:value={msfSelectedStr}
233+
classes={{ options: 'justify-start h-10' }}
234+
rounded="full"
235+
inset
236+
>
237+
<ToggleOption value="any">Any</ToggleOption>
238+
<ToggleOption value="even">Evens</ToggleOption>
239+
<ToggleOption value="odds">Odds</ToggleOption>
240+
</ToggleGroup>
241+
</div>
242+
</svelte:fragment>
243+
</MultiSelectField>
244+
</Preview>
245+
185246
<h2>within Drawer</h2>
186247

187248
<Preview>

packages/svelte-ux/src/routes/docs/components/MultiSelectMenu/+page.svelte

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
<script lang="ts">
2-
import { Button, getSettings, MultiSelectMenu, MultiSelectOption, ToggleButton } from 'svelte-ux';
2+
import {
3+
Button,
4+
MultiSelectMenu,
5+
MultiSelectOption,
6+
ToggleButton,
7+
ToggleGroup,
8+
ToggleOption,
9+
getSettings,
10+
} from 'svelte-ux';
311
import Preview from '$lib/components/Preview.svelte';
412
513
const { icons } = getSettings();
@@ -17,6 +25,15 @@
1725
}));
1826
1927
let value = [3];
28+
29+
// Filters (Any/Evens/Odds) for demos below
30+
let msmSelectedStr: 'any' | 'even' | 'odds' = 'any';
31+
$: msmOptionsFiltered =
32+
msmSelectedStr === 'even'
33+
? options.filter((o) => typeof o.value === 'number' && o.value % 2 === 0)
34+
: msmSelectedStr === 'odds'
35+
? options.filter((o) => typeof o.value === 'number' && o.value % 2 !== 0)
36+
: options;
2037
</script>
2138

2239
<h1>Examples</h1>
@@ -91,7 +108,6 @@
91108
</ToggleButton>
92109
</div>
93110
</Preview>
94-
95111
<h2>search</h2>
96112

97113
<Preview>
@@ -297,6 +313,80 @@
297313
</span>
298314
</Preview>
299315

316+
<h2>beforeOptions slot</h2>
317+
318+
<Preview>
319+
<span>
320+
<ToggleButton let:on={open} let:toggleOff transition={false}>
321+
{value.length} selected
322+
<MultiSelectMenu
323+
options={msmOptionsFiltered}
324+
{value}
325+
on:change={(e) => {
326+
// @ts-expect-error
327+
value = e.detail.value;
328+
}}
329+
{open}
330+
on:close={toggleOff}
331+
classes={{ menu: 'w-[360px]' }}
332+
search
333+
>
334+
<svelte:fragment slot="beforeOptions">
335+
<div class="p-2 border-b">
336+
<ToggleGroup
337+
bind:value={msmSelectedStr}
338+
classes={{ options: 'justify-start h-10' }}
339+
rounded="full"
340+
inset
341+
>
342+
<ToggleOption value="any">Any</ToggleOption>
343+
<ToggleOption value="even">Evens</ToggleOption>
344+
<ToggleOption value="odds">Odds</ToggleOption>
345+
</ToggleGroup>
346+
</div>
347+
</svelte:fragment>
348+
</MultiSelectMenu>
349+
</ToggleButton>
350+
</span>
351+
</Preview>
352+
353+
<h2>afterOptions slot</h2>
354+
355+
<Preview>
356+
<span>
357+
<ToggleButton let:on={open} let:toggleOff transition={false}>
358+
{value.length} selected
359+
<MultiSelectMenu
360+
options={msmOptionsFiltered}
361+
{value}
362+
on:change={(e) => {
363+
// @ts-expect-error
364+
value = e.detail.value;
365+
}}
366+
{open}
367+
on:close={toggleOff}
368+
classes={{ menu: 'w-[360px]' }}
369+
search
370+
>
371+
<svelte:fragment slot="afterOptions">
372+
<div class="p-2 border-t">
373+
<ToggleGroup
374+
bind:value={msmSelectedStr}
375+
classes={{ options: 'justify-start h-10' }}
376+
rounded="full"
377+
inset
378+
>
379+
<ToggleOption value="any">Any</ToggleOption>
380+
<ToggleOption value="even">Evens</ToggleOption>
381+
<ToggleOption value="odds">Odds</ToggleOption>
382+
</ToggleGroup>
383+
</div>
384+
</svelte:fragment>
385+
</MultiSelectMenu>
386+
</ToggleButton>
387+
</span>
388+
</Preview>
389+
300390
<h2>option slot</h2>
301391

302392
<Preview>

0 commit comments

Comments
 (0)