@ibobbyts/svelte-ui-utils 0.2.11 → 0.2.13
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 +112 -1
- package/dist/dialog/ConfirmDialog.svelte +2 -0
- package/dist/dialog/ConfirmDialog.svelte.d.ts +1 -0
- package/dist/dialog/ConfirmDialog.svelte.d.ts.map +1 -1
- package/dist/dialog/CsvUploadDialog.svelte +2 -0
- package/dist/dialog/CsvUploadDialog.svelte.d.ts +1 -0
- package/dist/dialog/CsvUploadDialog.svelte.d.ts.map +1 -1
- package/dist/dialog/Dialog.svelte +3 -0
- package/dist/dialog/Dialog.svelte.d.ts +1 -0
- package/dist/dialog/Dialog.svelte.d.ts.map +1 -1
- package/dist/dialog/ImagePreviewDialog.svelte +2 -0
- package/dist/dialog/ImagePreviewDialog.svelte.d.ts +1 -0
- package/dist/dialog/ImagePreviewDialog.svelte.d.ts.map +1 -1
- package/dist/dialog/InputDialog.svelte +2 -0
- package/dist/dialog/InputDialog.svelte.d.ts +1 -0
- package/dist/dialog/InputDialog.svelte.d.ts.map +1 -1
- package/dist/dialog/PasswordCopyDialog.svelte +2 -0
- package/dist/dialog/PasswordCopyDialog.svelte.d.ts +1 -0
- package/dist/dialog/PasswordCopyDialog.svelte.d.ts.map +1 -1
- package/dist/dropdown/Dropdown.svelte +122 -39
- package/dist/dropdown/Dropdown.svelte.d.ts +7 -1
- package/dist/dropdown/Dropdown.svelte.d.ts.map +1 -1
- package/dist/dropdown/index.d.ts +1 -1
- package/dist/dropdown/index.d.ts.map +1 -1
- package/dist/dropdown/types.d.ts +6 -1
- package/dist/dropdown/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/ordered-list/OrderedListEditor.svelte +60 -0
- package/dist/ordered-list/OrderedListEditor.svelte.d.ts +23 -0
- package/dist/ordered-list/OrderedListEditor.svelte.d.ts.map +1 -0
- package/dist/ordered-list/index.d.ts +3 -0
- package/dist/ordered-list/index.d.ts.map +1 -0
- package/dist/ordered-list/index.js +1 -0
- package/dist/sortable-list/SortableList.svelte +167 -0
- package/dist/sortable-list/SortableList.svelte.d.ts +38 -0
- package/dist/sortable-list/SortableList.svelte.d.ts.map +1 -0
- package/dist/sortable-list/index.d.ts +3 -0
- package/dist/sortable-list/index.d.ts.map +1 -0
- package/dist/sortable-list/index.js +1 -0
- package/dist/sortable-list/types.d.ts +23 -0
- package/dist/sortable-list/types.d.ts.map +1 -0
- package/dist/sortable-list/types.js +1 -0
- package/dist/sortable-table/SortableTable.svelte +118 -0
- package/dist/sortable-table/SortableTable.svelte.d.ts +41 -0
- package/dist/sortable-table/SortableTable.svelte.d.ts.map +1 -0
- package/dist/sortable-table/SortableTableEnhanced.svelte +128 -0
- package/dist/sortable-table/SortableTableEnhanced.svelte.d.ts +44 -0
- package/dist/sortable-table/SortableTableEnhanced.svelte.d.ts.map +1 -0
- package/dist/sortable-table/index.d.ts +4 -0
- package/dist/sortable-table/index.d.ts.map +1 -0
- package/dist/sortable-table/index.js +2 -0
- package/dist/sortable-table/types.d.ts +16 -0
- package/dist/sortable-table/types.d.ts.map +1 -0
- package/dist/sortable-table/types.js +1 -0
- package/dist/style.css +19 -2
- package/package.json +16 -1
package/README.md
CHANGED
|
@@ -76,6 +76,14 @@ import { ToastManager, Dropdown, DropdownSearch, Dialog, DataTable } from '@ibob
|
|
|
76
76
|
Supported positions are `top-left`, `top-center`, `top-right`, `right-center`,
|
|
77
77
|
`bottom-right`, `bottom-center`, `bottom-left`, and `left-center`.
|
|
78
78
|
|
|
79
|
+
## Dropdown
|
|
80
|
+
|
|
81
|
+
Dropdown menus default to `placement="auto"` and open toward whichever side of
|
|
82
|
+
the trigger has more available viewport space. The direction is recalculated
|
|
83
|
+
while the menu is open when the viewport is resized or a scroll container
|
|
84
|
+
moves. Set `placement="up"` or `placement="down"` to force a direction. Use
|
|
85
|
+
`fitViewport={true}` as well to constrain the panel height to the chosen side.
|
|
86
|
+
|
|
79
87
|
## DropdownSearch
|
|
80
88
|
|
|
81
89
|
```svelte
|
|
@@ -162,6 +170,98 @@ In multiselect mode, the text input remains a search query. Selecting an item
|
|
|
162
170
|
adds or removes it from `selectedItems`, clears the query, and emits both
|
|
163
171
|
`onChange` and `onSelectedItemsChange`.
|
|
164
172
|
|
|
173
|
+
## SortableList
|
|
174
|
+
|
|
175
|
+
`SortableList` provides controlled vertical HTML5 drag-and-drop ordering. Each
|
|
176
|
+
item has a string `id` (and may contain any additional fields); `getId` can
|
|
177
|
+
project a different string key while retaining that typed item contract. The
|
|
178
|
+
caller owns the item array and receives the reordered array through
|
|
179
|
+
`onReorder`. Use the third snippet argument to attach drag bindings to a
|
|
180
|
+
dedicated handle. `listTag` and `itemTag` can be changed when the list must
|
|
181
|
+
render valid table markup such as direct `<tr>` children under `<tbody>`.
|
|
182
|
+
|
|
183
|
+
```svelte
|
|
184
|
+
<script lang="ts">
|
|
185
|
+
import { SortableList } from '@ibobbyts/svelte-ui-utils/sortable-list';
|
|
186
|
+
|
|
187
|
+
let items = [{ id: 'a', label: 'First' }, { id: 'b', label: 'Second' }];
|
|
188
|
+
</script>
|
|
189
|
+
|
|
190
|
+
<SortableList {items} onReorder={(next) => (items = next)}>
|
|
191
|
+
{#snippet children(item, _index, handle)}
|
|
192
|
+
<div {...handle} aria-label={`Drag ${item.label}`}>⠿</div>
|
|
193
|
+
<span>{item.label}</span>
|
|
194
|
+
{/snippet}
|
|
195
|
+
</SortableList>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Dragging over the target item's upper or lower half displays a before/after
|
|
199
|
+
insertion indicator. Dropping on the same item or while `disabled={true}` is a
|
|
200
|
+
no-op. The component does not persist order or perform rollback; those remain
|
|
201
|
+
the responsibility of the controlled parent.
|
|
202
|
+
|
|
203
|
+
## OrderedListEditor
|
|
204
|
+
|
|
205
|
+
`OrderedListEditor` is the shared editor for ordered fields. It renders the
|
|
206
|
+
provided content first, an optional current/select action next, and a trash-icon
|
|
207
|
+
remove action at the far right. Reorder arrows are intentionally not rendered;
|
|
208
|
+
use `SortableList` when drag-and-drop ordering is needed. Set
|
|
209
|
+
`allowRemoveLast={true}` when an empty list is valid.
|
|
210
|
+
|
|
211
|
+
```svelte
|
|
212
|
+
<script lang="ts">
|
|
213
|
+
import { OrderedListEditor } from '@ibobbyts/svelte-ui-utils/ordered-list';
|
|
214
|
+
</script>
|
|
215
|
+
|
|
216
|
+
<OrderedListEditor items={rows} onremove={(id) => remove(id)}>
|
|
217
|
+
{#snippet children(item)}
|
|
218
|
+
<input value={item.value ?? ''} />
|
|
219
|
+
{/snippet}
|
|
220
|
+
</OrderedListEditor>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## SortableTable
|
|
224
|
+
|
|
225
|
+
`SortableTable` is the table-level ordering primitive. It owns the table rows,
|
|
226
|
+
the left drag-handle column, and the right trash-icon delete column. Callers
|
|
227
|
+
provide only the header cells and the middle row cells through snippets.
|
|
228
|
+
Use `getDragLabel(item, index)` and `getRemoveLabel(item, index)` when the
|
|
229
|
+
controls need caller-owned accessible labels. Each label is applied to both
|
|
230
|
+
`aria-label` and `title`; defaults remain `Drag ${getId(item)}` and
|
|
231
|
+
`Remove ${getId(item)}`.
|
|
232
|
+
|
|
233
|
+
```svelte
|
|
234
|
+
<SortableTable items={rows} onReorder={reorder} onRemove={remove}>
|
|
235
|
+
{#snippet header()}<th>Name</th><th>Protocol</th>{/snippet}
|
|
236
|
+
{#snippet children(row)}<td>{row.name}</td><td>{row.protocol}</td>{/snippet}
|
|
237
|
+
</SortableTable>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
`SortableTableEnhanced` composes the same table and adds a controlled current
|
|
241
|
+
radio immediately after each drag handle. `currentId` is read-only input;
|
|
242
|
+
`onCurrentChange` asks the caller to persist a new current item. Use
|
|
243
|
+
`getCurrentDisabled` for per-row eligibility and `getRowColorPreset` to select
|
|
244
|
+
the package-owned `red`, `yellow`, or `green` background. The presets include
|
|
245
|
+
light and dark defaults and expose `--suu-sortable-table-row-*-light` and
|
|
246
|
+
`--suu-sortable-table-row-*-dark` override variables.
|
|
247
|
+
|
|
248
|
+
```svelte
|
|
249
|
+
<SortableTableEnhanced
|
|
250
|
+
items={rows}
|
|
251
|
+
currentId={currentRowId}
|
|
252
|
+
getDragLabel={(row) => `Reorder ${row.name}`}
|
|
253
|
+
getRemoveLabel={(row) => `Remove ${row.name}`}
|
|
254
|
+
onCurrentChange={(row) => selectCurrent(row.id)}
|
|
255
|
+
getCurrentDisabled={(row) => row.exhausted}
|
|
256
|
+
getRowColorPreset={(row) => row.exhausted ? 'red' : row.cooling ? 'yellow' : 'green'}
|
|
257
|
+
onReorder={reorder}
|
|
258
|
+
onRemove={remove}
|
|
259
|
+
>
|
|
260
|
+
{#snippet header()}<th>Name</th><th>Protocol</th>{/snippet}
|
|
261
|
+
{#snippet children(row)}<td>{row.name}</td><td>{row.protocol}</td>{/snippet}
|
|
262
|
+
</SortableTableEnhanced>
|
|
263
|
+
```
|
|
264
|
+
|
|
165
265
|
## Dialogs
|
|
166
266
|
|
|
167
267
|
```svelte
|
|
@@ -181,6 +281,7 @@ adds or removes it from `selectedItems`, clears the query, and emits both
|
|
|
181
281
|
open={dialogOpen}
|
|
182
282
|
title="Edit record"
|
|
183
283
|
description="Update the shared fields."
|
|
284
|
+
padding="12px 16px"
|
|
184
285
|
closeLabel="Close dialog"
|
|
185
286
|
blurBackdrop={true}
|
|
186
287
|
showCountdown={true}
|
|
@@ -237,7 +338,10 @@ from the close button, backdrop, or Escape key when dismissible; it does not
|
|
|
237
338
|
mutate `open` internally. Set `dimBackdrop={false}` to disable background
|
|
238
339
|
darkening, `blurBackdrop={true}` to blur content behind the dialog, and
|
|
239
340
|
`showCountdown={true}` with `countdownDurationMs` to show a toast-style top
|
|
240
|
-
countdown bar.
|
|
341
|
+
countdown bar. The optional `padding` prop accepts a CSS padding shorthand and
|
|
342
|
+
applies it consistently to the dialog header, body, and footer. The default
|
|
343
|
+
section-specific spacing is preserved when `padding` is omitted, and the same
|
|
344
|
+
prop is available on all dialog wrapper components.
|
|
241
345
|
|
|
242
346
|
## Dropdown
|
|
243
347
|
|
|
@@ -279,6 +383,13 @@ scrollable when its contents exceed that height. When `fitViewport` is enabled,
|
|
|
279
383
|
the component replaces that default with the space available above or below the
|
|
280
384
|
trigger.
|
|
281
385
|
|
|
386
|
+
The original flat `options` API and all default behavior remain unchanged. New
|
|
387
|
+
callers may opt into grouped options with `optionGroups`; each group can have an
|
|
388
|
+
optional accessible label and its options keep the same keyboard and disabled
|
|
389
|
+
semantics. `width`, `minWidth`, `maxWidth`, and `className` are optional styling
|
|
390
|
+
hooks. `onTriggerClick` runs before the dropdown toggles, so a nested control
|
|
391
|
+
can stop event propagation without preventing the dropdown from opening.
|
|
392
|
+
|
|
282
393
|
## DataTable
|
|
283
394
|
|
|
284
395
|
```svelte
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
export let closeLabel = 'Close dialog';
|
|
13
13
|
export let intent: ConfirmDialogIntent = 'default';
|
|
14
14
|
export let size: DialogSize = 'sm';
|
|
15
|
+
export let padding: string | undefined = undefined;
|
|
15
16
|
export let confirmDisabled = false;
|
|
16
17
|
export let cancelDisabled = false;
|
|
17
18
|
export let dismissible = true;
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
{title}
|
|
48
49
|
{closeLabel}
|
|
49
50
|
{size}
|
|
51
|
+
{padding}
|
|
50
52
|
{dismissible}
|
|
51
53
|
{closeOnBackdrop}
|
|
52
54
|
{closeOnEscape}
|
|
@@ -26,6 +26,7 @@ declare const ConfirmDialog: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_P
|
|
|
26
26
|
closeLabel?: string;
|
|
27
27
|
intent?: ConfirmDialogIntent;
|
|
28
28
|
size?: DialogSize;
|
|
29
|
+
padding?: string | undefined;
|
|
29
30
|
confirmDisabled?: boolean;
|
|
30
31
|
cancelDisabled?: boolean;
|
|
31
32
|
dismissible?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfirmDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/ConfirmDialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/ConfirmDialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAkElE,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AACD,KAAK,gCAAgC,CAAC,KAAK,EAAE,KAAK,IAAI,KAAK,GACvD,CAAC,KAAK,SAAS;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,GACzB,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACnC,GAAG,GACH;IAAE,QAAQ,CAAC,EAAE,GAAG,CAAA;CAAE,GAClB,EAAE,CAAC,CAAC;AAId,QAAA,MAAM,aAAa;;;;;;;aAfwyB,mBAAmB;WAAS,UAAU;cAAY,MAAM,GAAG,SAAS;;;;;;;;sBAA8R,MAAM,GAAG,MAAM;;;;;gBAAkL,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS;eAAa,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;cAAY,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;;;;;;;cAev2C,CAAC;AACvF,KAAK,aAAa,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1D,eAAe,aAAa,CAAC"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
export let description = '';
|
|
10
10
|
export let closeLabel = 'Close dialog';
|
|
11
11
|
export let size: DialogSize = 'lg';
|
|
12
|
+
export let padding: string | undefined = undefined;
|
|
12
13
|
export let dismissible = true;
|
|
13
14
|
export let closeOnBackdrop = true;
|
|
14
15
|
export let closeOnEscape = true;
|
|
@@ -103,6 +104,7 @@
|
|
|
103
104
|
{description}
|
|
104
105
|
{closeLabel}
|
|
105
106
|
{size}
|
|
107
|
+
{padding}
|
|
106
108
|
{dismissible}
|
|
107
109
|
{closeOnBackdrop}
|
|
108
110
|
{closeOnEscape}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CsvUploadDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/CsvUploadDialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"CsvUploadDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/CsvUploadDialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA8K7C,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAUD,QAAA,MAAM,eAAe;;;;;WAfmhC,UAAU;cAAY,MAAM,GAAG,SAAS;;;;;;sBAA4M,MAAM,GAAG,MAAM;;kBAAoD,MAAM,GAAG,SAAS;2BAAyB,MAAM,GAAG,SAAS;;;;;;;;mBAAqS,MAAM,EAAE;;;;;;;eAAiP,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS;eAAa,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;cAAY,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;mBAAiB,CAAC,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS;;;;;;;;;cAergE,CAAC;AACzF,KAAK,eAAe,GAAG,YAAY,CAAC,OAAO,eAAe,CAAC,CAAC;AAC9D,eAAe,eAAe,CAAC"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
export let description = '';
|
|
10
10
|
export let closeLabel = 'Close dialog';
|
|
11
11
|
export let size: DialogSize = 'md';
|
|
12
|
+
export let padding: string | undefined = undefined;
|
|
12
13
|
export let dismissible = true;
|
|
13
14
|
export let showCloseButton = true;
|
|
14
15
|
export let closeOnBackdrop = true;
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
describedBy ?? (description ? descriptionId : undefined);
|
|
36
37
|
$: backdropStyle =
|
|
37
38
|
`--suu-dialog-backdrop-opacity: ${backdropOpacity}; --suu-dialog-backdrop-blur: ${backdropBlur};`;
|
|
39
|
+
$: dialogStyle = padding ? `--suu-dialog-padding: ${padding};` : '';
|
|
38
40
|
$: countdownStyle = `--suu-dialog-countdown-duration: ${Math.max(0, countdownDurationMs)}ms;`;
|
|
39
41
|
$: if (open && !wasOpen) {
|
|
40
42
|
wasOpen = true;
|
|
@@ -99,6 +101,7 @@
|
|
|
99
101
|
<div
|
|
100
102
|
bind:this={dialogElement}
|
|
101
103
|
class={`suu-dialog suu-dialog--${size}`}
|
|
104
|
+
style={dialogStyle}
|
|
102
105
|
role="dialog"
|
|
103
106
|
aria-modal="true"
|
|
104
107
|
aria-labelledby={resolvedLabelledBy}
|
|
@@ -23,6 +23,7 @@ declare const Dialog: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWit
|
|
|
23
23
|
description?: string;
|
|
24
24
|
closeLabel?: string;
|
|
25
25
|
size?: DialogSize;
|
|
26
|
+
padding?: string | undefined;
|
|
26
27
|
dismissible?: boolean;
|
|
27
28
|
showCloseButton?: boolean;
|
|
28
29
|
closeOnBackdrop?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/Dialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"Dialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/Dialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAsI7C,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AACD,KAAK,gCAAgC,CAAC,KAAK,EAAE,KAAK,IAAI,KAAK,GACvD,CAAC,KAAK,SAAS;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,GACzB,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACnC,GAAG,GACH;IAAE,QAAQ,CAAC,EAAE,GAAG,CAAA;CAAE,GAClB,EAAE,CAAC,CAAC;AAId,QAAA,MAAM,MAAM;;;;;WAfqpB,UAAU;cAAY,MAAM,GAAG,SAAS;;;;;;;sBAAsP,MAAM,GAAG,MAAM;;;;;iBAAmL,MAAM,GAAG,SAAS;kBAAgB,MAAM,GAAG,SAAS;cAAY,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;;;;;;;;;cAexnC,CAAC;AAChF,KAAK,MAAM,GAAG,YAAY,CAAC,OAAO,MAAM,CAAC,CAAC;AAC5C,eAAe,MAAM,CAAC"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
export let closeLabel = 'Close dialog';
|
|
13
13
|
export let downloadLabel = 'Download';
|
|
14
14
|
export let size: DialogSize = 'lg';
|
|
15
|
+
export let padding: string | undefined = undefined;
|
|
15
16
|
export let dismissible = true;
|
|
16
17
|
export let closeOnBackdrop = true;
|
|
17
18
|
export let closeOnEscape = true;
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
title={resolvedTitle}
|
|
46
47
|
{closeLabel}
|
|
47
48
|
{size}
|
|
49
|
+
{padding}
|
|
48
50
|
{dismissible}
|
|
49
51
|
{closeOnBackdrop}
|
|
50
52
|
{closeOnEscape}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImagePreviewDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/ImagePreviewDialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"ImagePreviewDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/ImagePreviewDialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA+D7C,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,kBAAkB;;;;;;;;WAV2mB,UAAU;cAAY,MAAM,GAAG,SAAS;;;;;;sBAA4M,MAAM,GAAG,MAAM;;;cAAoF,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;;;kBAU34B,CAAC;AACtF,KAAK,kBAAkB,GAAG,YAAY,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACpE,eAAe,kBAAkB,CAAC"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
export let cancelLabel = 'Cancel';
|
|
17
17
|
export let closeLabel = 'Close dialog';
|
|
18
18
|
export let size: DialogSize = 'sm';
|
|
19
|
+
export let padding: string | undefined = undefined;
|
|
19
20
|
export let confirmDisabled = false;
|
|
20
21
|
export let cancelDisabled = false;
|
|
21
22
|
export let dismissible = true;
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
{title}
|
|
82
83
|
{closeLabel}
|
|
83
84
|
{size}
|
|
85
|
+
{padding}
|
|
84
86
|
{dismissible}
|
|
85
87
|
{closeOnBackdrop}
|
|
86
88
|
{closeOnEscape}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/InputDialog.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"InputDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/InputDialog.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA0G9D,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,WAAW;;;;;gBAVsuB,eAAe;;;;;;WAAiL,UAAU;cAAY,MAAM,GAAG,SAAS;;;;;;;;sBAA8R,MAAM,GAAG,MAAM;;;gBAAgF,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS;eAAa,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;cAAY,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;;;kBAU13C,CAAC;AAC/E,KAAK,WAAW,GAAG,YAAY,CAAC,OAAO,WAAW,CAAC,CAAC;AACtD,eAAe,WAAW,CAAC"}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
export let doneLabel = 'Done';
|
|
15
15
|
export let closeLabel = 'Close dialog';
|
|
16
16
|
export let size: DialogSize = 'sm';
|
|
17
|
+
export let padding: string | undefined = undefined;
|
|
17
18
|
export let dismissible = true;
|
|
18
19
|
export let closeOnBackdrop = true;
|
|
19
20
|
export let closeOnEscape = true;
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
{title}
|
|
54
55
|
{closeLabel}
|
|
55
56
|
{size}
|
|
57
|
+
{padding}
|
|
56
58
|
{dismissible}
|
|
57
59
|
{closeOnBackdrop}
|
|
58
60
|
{closeOnEscape}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PasswordCopyDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/PasswordCopyDialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"PasswordCopyDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dialog/PasswordCopyDialog.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA+E7C,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,kBAAkB;;;;;;;;;;WAV6sB,UAAU;cAAY,MAAM,GAAG,SAAS;;;;;;sBAA4M,MAAM,GAAG,MAAM;;cAAgD,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;aAAW,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS;;;kBAU5/B,CAAC;AACtF,KAAK,kBAAkB,GAAG,YAAY,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACpE,eAAe,kBAAkB,CAAC"}
|
|
@@ -2,18 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
<script lang="ts">
|
|
4
4
|
import { onDestroy, tick } from 'svelte';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
DropdownChangeHandler,
|
|
7
|
+
DropdownMenuAlign,
|
|
8
|
+
DropdownOption,
|
|
9
|
+
DropdownOptionGroup,
|
|
10
|
+
DropdownPlacement,
|
|
11
|
+
DropdownTriggerClickHandler,
|
|
12
|
+
DropdownValue
|
|
13
|
+
} from './types.js';
|
|
6
14
|
|
|
7
15
|
export let id: string | undefined = undefined;
|
|
8
16
|
export let value: DropdownValue = '';
|
|
9
17
|
export let options: DropdownOption[] = [];
|
|
18
|
+
export let optionGroups: DropdownOptionGroup[] | undefined = undefined;
|
|
10
19
|
export let ariaLabel: string | undefined = undefined;
|
|
11
|
-
export let placement: DropdownPlacement = '
|
|
20
|
+
export let placement: DropdownPlacement = 'auto';
|
|
12
21
|
export let menuAlign: DropdownMenuAlign = 'right';
|
|
13
22
|
export let fitViewport = false;
|
|
14
23
|
export let fitContent = false;
|
|
15
24
|
export let disabled = false;
|
|
25
|
+
export let width: string | undefined = undefined;
|
|
26
|
+
export let minWidth: string | undefined = undefined;
|
|
27
|
+
export let maxWidth: string | undefined = undefined;
|
|
28
|
+
export let className: string | undefined = undefined;
|
|
16
29
|
export let onChange: DropdownChangeHandler | undefined = undefined;
|
|
30
|
+
export let onTriggerClick: DropdownTriggerClickHandler | undefined = undefined;
|
|
17
31
|
|
|
18
32
|
const viewportMargin = 20;
|
|
19
33
|
const menuGap = 6;
|
|
@@ -22,10 +36,12 @@
|
|
|
22
36
|
let activeValue: DropdownValue = value;
|
|
23
37
|
let dropdownElement: HTMLSpanElement | undefined;
|
|
24
38
|
let buttonElement: HTMLButtonElement | undefined;
|
|
39
|
+
let resolvedPlacement: Exclude<DropdownPlacement, 'auto'> = placement === 'up' ? 'up' : 'down';
|
|
25
40
|
let viewportPanelMaxHeight: string | undefined = undefined;
|
|
26
41
|
let removeOpenViewportListeners: (() => void) | undefined = undefined;
|
|
27
42
|
|
|
28
|
-
$:
|
|
43
|
+
$: resolvedOptions = optionGroups === undefined ? options : optionGroups.flatMap((group) => group.options);
|
|
44
|
+
$: selectedOption = resolvedOptions.find((option) => option.value === value);
|
|
29
45
|
$: selectedText = selectedOption?.label ?? String(value);
|
|
30
46
|
$: if (!open) {
|
|
31
47
|
activeValue = selectedOption?.value ?? firstEnabledOption()?.value ?? value;
|
|
@@ -37,28 +53,29 @@
|
|
|
37
53
|
void updateViewportPanelMaxHeight();
|
|
38
54
|
} else {
|
|
39
55
|
disableOpenViewportTracking();
|
|
56
|
+
resolvedPlacement = placement === 'up' ? 'up' : 'down';
|
|
40
57
|
viewportPanelMaxHeight = undefined;
|
|
41
58
|
}
|
|
42
59
|
}
|
|
43
60
|
|
|
44
61
|
function firstEnabledOption(): DropdownOption | undefined {
|
|
45
|
-
return
|
|
62
|
+
return resolvedOptions.find((option) => !option.disabled);
|
|
46
63
|
}
|
|
47
64
|
|
|
48
65
|
function activeOptionIndex(nextActiveValue: DropdownValue): number {
|
|
49
|
-
const index =
|
|
66
|
+
const index = resolvedOptions.findIndex((option) => option.value === nextActiveValue && !option.disabled);
|
|
50
67
|
if (index >= 0) {
|
|
51
68
|
return index;
|
|
52
69
|
}
|
|
53
|
-
const fallbackIndex =
|
|
70
|
+
const fallbackIndex = resolvedOptions.findIndex((option) => option.value === value && !option.disabled);
|
|
54
71
|
if (fallbackIndex >= 0) {
|
|
55
72
|
return fallbackIndex;
|
|
56
73
|
}
|
|
57
|
-
return
|
|
74
|
+
return resolvedOptions.findIndex((option) => !option.disabled);
|
|
58
75
|
}
|
|
59
76
|
|
|
60
77
|
function moveActiveOption(offset: number) {
|
|
61
|
-
const enabledOptions =
|
|
78
|
+
const enabledOptions = resolvedOptions.filter((option) => !option.disabled);
|
|
62
79
|
if (enabledOptions.length === 0) {
|
|
63
80
|
return;
|
|
64
81
|
}
|
|
@@ -82,10 +99,18 @@
|
|
|
82
99
|
if (disabled) {
|
|
83
100
|
return;
|
|
84
101
|
}
|
|
102
|
+
if (!open) {
|
|
103
|
+
updateResolvedPlacement();
|
|
104
|
+
}
|
|
85
105
|
open = !open;
|
|
86
106
|
activeValue = selectedOption?.value ?? firstEnabledOption()?.value ?? value;
|
|
87
107
|
}
|
|
88
108
|
|
|
109
|
+
function handleTriggerClick(event: MouseEvent) {
|
|
110
|
+
onTriggerClick?.(event);
|
|
111
|
+
toggleOpen();
|
|
112
|
+
}
|
|
113
|
+
|
|
89
114
|
function handleKeydown(event: KeyboardEvent) {
|
|
90
115
|
if (disabled) {
|
|
91
116
|
return;
|
|
@@ -102,6 +127,7 @@
|
|
|
102
127
|
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
103
128
|
event.preventDefault();
|
|
104
129
|
if (!open) {
|
|
130
|
+
updateResolvedPlacement();
|
|
105
131
|
open = true;
|
|
106
132
|
activeValue = selectedOption?.value ?? firstEnabledOption()?.value ?? value;
|
|
107
133
|
}
|
|
@@ -112,7 +138,7 @@
|
|
|
112
138
|
if ((event.key === 'Enter' || event.key === ' ') && open) {
|
|
113
139
|
event.preventDefault();
|
|
114
140
|
const index = activeOptionIndex(activeValue);
|
|
115
|
-
const option = index >= 0 ?
|
|
141
|
+
const option = index >= 0 ? resolvedOptions[index] : undefined;
|
|
116
142
|
if (option) {
|
|
117
143
|
selectOption(option);
|
|
118
144
|
}
|
|
@@ -144,6 +170,21 @@
|
|
|
144
170
|
return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
|
|
145
171
|
}
|
|
146
172
|
|
|
173
|
+
function updateResolvedPlacement(rect = dropdownElement?.getBoundingClientRect()) {
|
|
174
|
+
if (placement !== 'auto') {
|
|
175
|
+
resolvedPlacement = placement;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (!rect || typeof window === 'undefined') {
|
|
179
|
+
resolvedPlacement = 'down';
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const availableAbove = rect.top - viewportMargin - menuGap;
|
|
184
|
+
const availableBelow = window.innerHeight - rect.bottom - viewportMargin - menuGap;
|
|
185
|
+
resolvedPlacement = availableBelow >= availableAbove ? 'down' : 'up';
|
|
186
|
+
}
|
|
187
|
+
|
|
147
188
|
async function updateViewportPanelMaxHeight() {
|
|
148
189
|
await tick();
|
|
149
190
|
|
|
@@ -156,17 +197,18 @@
|
|
|
156
197
|
return;
|
|
157
198
|
}
|
|
158
199
|
|
|
159
|
-
|
|
200
|
+
const rect = dropdownElement?.getBoundingClientRect();
|
|
201
|
+
if (!rect) {
|
|
160
202
|
return;
|
|
161
203
|
}
|
|
162
204
|
|
|
163
|
-
|
|
164
|
-
if (!
|
|
205
|
+
updateResolvedPlacement(rect);
|
|
206
|
+
if (!fitViewport) {
|
|
165
207
|
return;
|
|
166
208
|
}
|
|
167
209
|
|
|
168
210
|
const available =
|
|
169
|
-
|
|
211
|
+
resolvedPlacement === 'up'
|
|
170
212
|
? rect.top - viewportMargin - menuGap
|
|
171
213
|
: window.innerHeight - rect.bottom - viewportMargin - menuGap;
|
|
172
214
|
viewportPanelMaxHeight = `${Math.max(0, Math.floor(available))}px`;
|
|
@@ -199,8 +241,17 @@
|
|
|
199
241
|
|
|
200
242
|
<span
|
|
201
243
|
bind:this={dropdownElement}
|
|
202
|
-
class=
|
|
244
|
+
class={[
|
|
245
|
+
'suu-dropdown',
|
|
246
|
+
width !== undefined || minWidth !== undefined || maxWidth !== undefined
|
|
247
|
+
? 'suu-dropdown--sized'
|
|
248
|
+
: '',
|
|
249
|
+
className ?? ''
|
|
250
|
+
].filter(Boolean).join(' ')}
|
|
203
251
|
style:--suu-dropdown-panel-max-height={viewportPanelMaxHeight}
|
|
252
|
+
style:width
|
|
253
|
+
style:min-width={minWidth}
|
|
254
|
+
style:max-width={maxWidth}
|
|
204
255
|
on:focusout={handleFocusout}
|
|
205
256
|
>
|
|
206
257
|
<button
|
|
@@ -213,7 +264,7 @@
|
|
|
213
264
|
aria-haspopup="listbox"
|
|
214
265
|
aria-expanded={open}
|
|
215
266
|
data-value={String(value)}
|
|
216
|
-
on:click={
|
|
267
|
+
on:click={handleTriggerClick}
|
|
217
268
|
on:keydown={handleKeydown}
|
|
218
269
|
>
|
|
219
270
|
<span>{selectedText}</span>
|
|
@@ -223,35 +274,67 @@
|
|
|
223
274
|
{#if open}
|
|
224
275
|
<div
|
|
225
276
|
class="suu-dropdown__menu"
|
|
226
|
-
class:suu-dropdown__menu--up={
|
|
227
|
-
class:suu-dropdown__menu--down={
|
|
277
|
+
class:suu-dropdown__menu--up={resolvedPlacement === 'up'}
|
|
278
|
+
class:suu-dropdown__menu--down={resolvedPlacement === 'down'}
|
|
228
279
|
class:suu-dropdown__menu--left={menuAlign === 'left'}
|
|
229
280
|
class:suu-dropdown__menu--right={menuAlign === 'right'}
|
|
230
281
|
class:suu-dropdown__menu--fit-content={fitContent}
|
|
231
282
|
>
|
|
232
283
|
<div class="suu-dropdown__panel" role="listbox" aria-label={ariaLabel}>
|
|
233
|
-
{#
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
284
|
+
{#if optionGroups === undefined}
|
|
285
|
+
{#each options as option}
|
|
286
|
+
<button
|
|
287
|
+
type="button"
|
|
288
|
+
class="suu-dropdown__option"
|
|
289
|
+
class:suu-dropdown__option--active={option.value === activeValue}
|
|
290
|
+
class:suu-dropdown__option--disabled={option.disabled}
|
|
291
|
+
role="option"
|
|
292
|
+
aria-selected={option.value === value}
|
|
293
|
+
aria-disabled={option.disabled}
|
|
294
|
+
disabled={option.disabled}
|
|
295
|
+
data-value={String(option.value)}
|
|
296
|
+
on:mousedown|preventDefault={() => undefined}
|
|
297
|
+
on:mouseenter={() => {
|
|
298
|
+
if (!option.disabled) {
|
|
299
|
+
activeValue = option.value;
|
|
300
|
+
}
|
|
301
|
+
}}
|
|
302
|
+
on:click={() => selectOption(option)}
|
|
303
|
+
>
|
|
304
|
+
{option.label}
|
|
305
|
+
</button>
|
|
306
|
+
{/each}
|
|
307
|
+
{:else}
|
|
308
|
+
{#each optionGroups as group}
|
|
309
|
+
<div class="suu-dropdown__group" role="group" aria-label={group.label}>
|
|
310
|
+
{#if group.label}
|
|
311
|
+
<div class="suu-dropdown__group-label">{group.label}</div>
|
|
312
|
+
{/if}
|
|
313
|
+
{#each group.options as option}
|
|
314
|
+
<button
|
|
315
|
+
type="button"
|
|
316
|
+
class="suu-dropdown__option"
|
|
317
|
+
class:suu-dropdown__option--active={option.value === activeValue}
|
|
318
|
+
class:suu-dropdown__option--disabled={option.disabled}
|
|
319
|
+
role="option"
|
|
320
|
+
aria-selected={option.value === value}
|
|
321
|
+
aria-disabled={option.disabled}
|
|
322
|
+
disabled={option.disabled}
|
|
323
|
+
data-value={String(option.value)}
|
|
324
|
+
on:mousedown|preventDefault={() => undefined}
|
|
325
|
+
on:mouseenter={() => {
|
|
326
|
+
if (!option.disabled) {
|
|
327
|
+
activeValue = option.value;
|
|
328
|
+
}
|
|
329
|
+
}}
|
|
330
|
+
on:click={() => selectOption(option)}
|
|
331
|
+
>
|
|
332
|
+
{option.label}
|
|
333
|
+
</button>
|
|
334
|
+
{/each}
|
|
335
|
+
</div>
|
|
336
|
+
{/each}
|
|
337
|
+
{/if}
|
|
255
338
|
</div>
|
|
256
339
|
</div>
|
|
257
340
|
{/if}
|