@ibobbyts/svelte-ui-utils 0.2.1 → 0.2.3
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 +50 -17
- package/dist/{modal → dialog}/ConfirmDialog.svelte +25 -8
- package/dist/{modal → dialog}/ConfirmDialog.svelte.d.ts +11 -2
- package/dist/dialog/ConfirmDialog.svelte.d.ts.map +1 -0
- package/dist/dialog/CsvUploadDialog.svelte +207 -0
- package/dist/dialog/CsvUploadDialog.svelte.d.ts +59 -0
- package/dist/dialog/CsvUploadDialog.svelte.d.ts.map +1 -0
- package/dist/{modal/Modal.svelte → dialog/Dialog.svelte} +37 -15
- package/dist/{modal/Modal.svelte.d.ts → dialog/Dialog.svelte.d.ts} +14 -6
- package/dist/dialog/Dialog.svelte.d.ts.map +1 -0
- package/dist/dialog/ImagePreviewDialog.svelte +75 -0
- package/dist/dialog/ImagePreviewDialog.svelte.d.ts +38 -0
- package/dist/dialog/ImagePreviewDialog.svelte.d.ts.map +1 -0
- package/dist/dialog/InputDialog.svelte +131 -0
- package/dist/dialog/InputDialog.svelte.d.ts +45 -0
- package/dist/dialog/InputDialog.svelte.d.ts.map +1 -0
- package/dist/dialog/PasswordCopyDialog.svelte +95 -0
- package/dist/dialog/PasswordCopyDialog.svelte.d.ts +40 -0
- package/dist/dialog/PasswordCopyDialog.svelte.d.ts.map +1 -0
- package/dist/dialog/index.d.ts +8 -0
- package/dist/dialog/index.d.ts.map +1 -0
- package/dist/dialog/index.js +6 -0
- package/dist/dialog/types.d.ts +4 -0
- package/dist/dialog/types.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/modal/index.d.ts +2 -3
- package/dist/modal/index.d.ts.map +1 -1
- package/dist/modal/index.js +2 -2
- package/dist/style.css +213 -33
- package/package.json +7 -2
- package/dist/modal/ConfirmDialog.svelte.d.ts.map +0 -1
- package/dist/modal/Modal.svelte.d.ts.map +0 -1
- package/dist/modal/types.d.ts +0 -3
- package/dist/modal/types.d.ts.map +0 -1
- /package/dist/{modal → dialog}/types.js +0 -0
package/README.md
CHANGED
|
@@ -10,19 +10,19 @@ Install from the public npm registry. No GitHub Packages token is required.
|
|
|
10
10
|
With Bun:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
bun add @ibobbyts/svelte-ui-utils@0.2.
|
|
13
|
+
bun add @ibobbyts/svelte-ui-utils@0.2.3
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
Canonical Bun pull address:
|
|
17
17
|
|
|
18
18
|
```text
|
|
19
|
-
@ibobbyts/svelte-ui-utils@0.2.
|
|
19
|
+
@ibobbyts/svelte-ui-utils@0.2.3
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
With npm:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
npm install @ibobbyts/svelte-ui-utils@0.2.
|
|
25
|
+
npm install @ibobbyts/svelte-ui-utils@0.2.3
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
The repository does not track `dist/`; releases and local integration builds run
|
|
@@ -41,7 +41,7 @@ import '@ibobbyts/svelte-ui-utils/style.css';
|
|
|
41
41
|
import { ToastManager, toast } from '@ibobbyts/svelte-ui-utils/toast';
|
|
42
42
|
import { Dropdown } from '@ibobbyts/svelte-ui-utils/dropdown';
|
|
43
43
|
import { DropdownSearch, DropdownSearchMultiSelect } from '@ibobbyts/svelte-ui-utils/dropdown-search';
|
|
44
|
-
import {
|
|
44
|
+
import { Dialog, ConfirmDialog, InputDialog, CsvUploadDialog, ImagePreviewDialog, PasswordCopyDialog } from '@ibobbyts/svelte-ui-utils/dialog';
|
|
45
45
|
import { DataTable, DateRangeFilter, FilterTable, NumberRangeFilter } from '@ibobbyts/svelte-ui-utils/table';
|
|
46
46
|
</script>
|
|
47
47
|
```
|
|
@@ -49,7 +49,7 @@ import '@ibobbyts/svelte-ui-utils/style.css';
|
|
|
49
49
|
The package root also re-exports the public modules:
|
|
50
50
|
|
|
51
51
|
```ts
|
|
52
|
-
import { ToastManager, Dropdown, DropdownSearch,
|
|
52
|
+
import { ToastManager, Dropdown, DropdownSearch, Dialog, DataTable } from '@ibobbyts/svelte-ui-utils';
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
## Toast
|
|
@@ -153,31 +153,37 @@ In multiselect mode, the text input remains a search query. Selecting an item
|
|
|
153
153
|
adds or removes it from `selectedItems`, clears the query, and emits both
|
|
154
154
|
`onChange` and `onSelectedItemsChange`.
|
|
155
155
|
|
|
156
|
-
##
|
|
156
|
+
## Dialogs
|
|
157
157
|
|
|
158
158
|
```svelte
|
|
159
159
|
<script lang="ts">
|
|
160
|
-
import { ConfirmDialog,
|
|
160
|
+
import { ConfirmDialog, Dialog, InputDialog } from '@ibobbyts/svelte-ui-utils/dialog';
|
|
161
161
|
|
|
162
|
-
let
|
|
162
|
+
let dialogOpen = false;
|
|
163
163
|
let confirmOpen = false;
|
|
164
|
+
let inputOpen = false;
|
|
165
|
+
let passwordOpen = false;
|
|
166
|
+
let name = '';
|
|
164
167
|
</script>
|
|
165
168
|
|
|
166
|
-
<button type="button" on:click={() => (
|
|
169
|
+
<button type="button" on:click={() => (dialogOpen = true)}>Open dialog</button>
|
|
167
170
|
|
|
168
|
-
<
|
|
169
|
-
open={
|
|
171
|
+
<Dialog
|
|
172
|
+
open={dialogOpen}
|
|
170
173
|
title="Edit record"
|
|
171
174
|
description="Update the shared fields."
|
|
172
175
|
closeLabel="Close dialog"
|
|
173
|
-
|
|
176
|
+
blurBackdrop={true}
|
|
177
|
+
showCountdown={true}
|
|
178
|
+
countdownDurationMs={30000}
|
|
179
|
+
onClose={() => (dialogOpen = false)}
|
|
174
180
|
>
|
|
175
181
|
<p>Dialog body content goes here.</p>
|
|
176
182
|
<svelte:fragment slot="footer">
|
|
177
|
-
<button type="button" class="suu-
|
|
178
|
-
<button type="button" class="suu-
|
|
183
|
+
<button type="button" class="suu-dialog__button" on:click={() => (dialogOpen = false)}>Cancel</button>
|
|
184
|
+
<button type="button" class="suu-dialog__button suu-dialog__button--primary">Save</button>
|
|
179
185
|
</svelte:fragment>
|
|
180
|
-
</
|
|
186
|
+
</Dialog>
|
|
181
187
|
|
|
182
188
|
<ConfirmDialog
|
|
183
189
|
open={confirmOpen}
|
|
@@ -191,11 +197,38 @@ adds or removes it from `selectedItems`, clears the query, and emits both
|
|
|
191
197
|
confirmOpen = false;
|
|
192
198
|
}}
|
|
193
199
|
/>
|
|
200
|
+
|
|
201
|
+
<InputDialog
|
|
202
|
+
open={inputOpen}
|
|
203
|
+
title="Rename"
|
|
204
|
+
inputLabel="Name"
|
|
205
|
+
bind:inputValue={name}
|
|
206
|
+
onClose={() => (inputOpen = false)}
|
|
207
|
+
onConfirm={(value) => {
|
|
208
|
+
name = value;
|
|
209
|
+
inputOpen = false;
|
|
210
|
+
}}
|
|
211
|
+
/>
|
|
212
|
+
|
|
213
|
+
<PasswordCopyDialog
|
|
214
|
+
open={passwordOpen}
|
|
215
|
+
title="Temporary password"
|
|
216
|
+
message="This value is shown only once."
|
|
217
|
+
value="Abc123xy"
|
|
218
|
+
valueLabel="Password"
|
|
219
|
+
copyLabel="Copy password"
|
|
220
|
+
copiedLabel="Copied"
|
|
221
|
+
doneLabel="Done"
|
|
222
|
+
onClose={() => (passwordOpen = false)}
|
|
223
|
+
/>
|
|
194
224
|
```
|
|
195
225
|
|
|
196
|
-
|
|
226
|
+
Dialog components are controlled by the consuming app. `Dialog` calls `onClose`
|
|
197
227
|
from the close button, backdrop, or Escape key when dismissible; it does not
|
|
198
|
-
mutate `open` internally.
|
|
228
|
+
mutate `open` internally. Set `dimBackdrop={false}` to disable background
|
|
229
|
+
darkening, `blurBackdrop={true}` to blur content behind the dialog, and
|
|
230
|
+
`showCountdown={true}` with `countdownDurationMs` to show a toast-style top
|
|
231
|
+
countdown bar.
|
|
199
232
|
|
|
200
233
|
## Dropdown
|
|
201
234
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<svelte:options runes={false} />
|
|
2
2
|
|
|
3
3
|
<script lang="ts">
|
|
4
|
-
import
|
|
5
|
-
import type { ConfirmDialogIntent,
|
|
4
|
+
import Dialog from './Dialog.svelte';
|
|
5
|
+
import type { ConfirmDialogIntent, DialogSize } from './types.js';
|
|
6
6
|
|
|
7
7
|
export let open = false;
|
|
8
8
|
export let title = 'Confirm';
|
|
@@ -11,10 +11,19 @@
|
|
|
11
11
|
export let cancelLabel = 'Cancel';
|
|
12
12
|
export let closeLabel = 'Close dialog';
|
|
13
13
|
export let intent: ConfirmDialogIntent = 'default';
|
|
14
|
-
export let size:
|
|
14
|
+
export let size: DialogSize = 'sm';
|
|
15
15
|
export let confirmDisabled = false;
|
|
16
16
|
export let cancelDisabled = false;
|
|
17
17
|
export let dismissible = true;
|
|
18
|
+
export let closeOnBackdrop = true;
|
|
19
|
+
export let closeOnEscape = true;
|
|
20
|
+
export let dimBackdrop = true;
|
|
21
|
+
export let blurBackdrop = false;
|
|
22
|
+
export let backdropOpacity: number | string = 0.46;
|
|
23
|
+
export let backdropBlur = '6px';
|
|
24
|
+
export let showCountdown = false;
|
|
25
|
+
export let countdownDurationMs = 0;
|
|
26
|
+
export let countdownLabel = 'Dialog countdown';
|
|
18
27
|
export let onConfirm: (() => void | Promise<void>) | undefined = undefined;
|
|
19
28
|
export let onCancel: (() => void) | undefined = undefined;
|
|
20
29
|
export let onClose: (() => void) | undefined = undefined;
|
|
@@ -33,13 +42,21 @@
|
|
|
33
42
|
}
|
|
34
43
|
</script>
|
|
35
44
|
|
|
36
|
-
<
|
|
45
|
+
<Dialog
|
|
37
46
|
{open}
|
|
38
47
|
{title}
|
|
39
48
|
{closeLabel}
|
|
40
49
|
{size}
|
|
41
50
|
{dismissible}
|
|
42
|
-
|
|
51
|
+
{closeOnBackdrop}
|
|
52
|
+
{closeOnEscape}
|
|
53
|
+
{dimBackdrop}
|
|
54
|
+
{blurBackdrop}
|
|
55
|
+
{backdropOpacity}
|
|
56
|
+
{backdropBlur}
|
|
57
|
+
{showCountdown}
|
|
58
|
+
{countdownDurationMs}
|
|
59
|
+
{countdownLabel}
|
|
43
60
|
onClose={handleClose}
|
|
44
61
|
>
|
|
45
62
|
<slot>
|
|
@@ -51,7 +68,7 @@
|
|
|
51
68
|
<svelte:fragment slot="footer">
|
|
52
69
|
<button
|
|
53
70
|
type="button"
|
|
54
|
-
class="suu-
|
|
71
|
+
class="suu-dialog__button"
|
|
55
72
|
disabled={cancelDisabled}
|
|
56
73
|
on:click={handleCancel}
|
|
57
74
|
>
|
|
@@ -59,11 +76,11 @@
|
|
|
59
76
|
</button>
|
|
60
77
|
<button
|
|
61
78
|
type="button"
|
|
62
|
-
class={`suu-
|
|
79
|
+
class={`suu-dialog__button suu-dialog__button--primary suu-dialog__button--${intent}`}
|
|
63
80
|
disabled={confirmDisabled}
|
|
64
81
|
on:click={handleConfirm}
|
|
65
82
|
>
|
|
66
83
|
{confirmLabel}
|
|
67
84
|
</button>
|
|
68
85
|
</svelte:fragment>
|
|
69
|
-
</
|
|
86
|
+
</Dialog>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ConfirmDialogIntent,
|
|
1
|
+
import type { ConfirmDialogIntent, DialogSize } from './types.js';
|
|
2
2
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
3
|
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
4
|
$$bindings?: Bindings;
|
|
@@ -25,10 +25,19 @@ declare const ConfirmDialog: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_P
|
|
|
25
25
|
cancelLabel?: string;
|
|
26
26
|
closeLabel?: string;
|
|
27
27
|
intent?: ConfirmDialogIntent;
|
|
28
|
-
size?:
|
|
28
|
+
size?: DialogSize;
|
|
29
29
|
confirmDisabled?: boolean;
|
|
30
30
|
cancelDisabled?: boolean;
|
|
31
31
|
dismissible?: boolean;
|
|
32
|
+
closeOnBackdrop?: boolean;
|
|
33
|
+
closeOnEscape?: boolean;
|
|
34
|
+
dimBackdrop?: boolean;
|
|
35
|
+
blurBackdrop?: boolean;
|
|
36
|
+
backdropOpacity?: number | string;
|
|
37
|
+
backdropBlur?: string;
|
|
38
|
+
showCountdown?: boolean;
|
|
39
|
+
countdownDurationMs?: number;
|
|
40
|
+
countdownLabel?: string;
|
|
32
41
|
onConfirm?: (() => void | Promise<void>) | undefined;
|
|
33
42
|
onCancel?: (() => void) | undefined;
|
|
34
43
|
onClose?: (() => void) | undefined;
|
|
@@ -0,0 +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;AAiElE,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;;;;;;;aAfqxB,mBAAmB;WAAS,UAAU;;;;;;;;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;;;;;;;cAetzC,CAAC;AACvF,KAAK,aAAa,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1D,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
<svelte:options runes={false} />
|
|
2
|
+
|
|
3
|
+
<script lang="ts">
|
|
4
|
+
import Dialog from './Dialog.svelte';
|
|
5
|
+
import type { DialogSize } from './types.js';
|
|
6
|
+
|
|
7
|
+
export let open = false;
|
|
8
|
+
export let title = 'Upload CSV';
|
|
9
|
+
export let description = '';
|
|
10
|
+
export let closeLabel = 'Close dialog';
|
|
11
|
+
export let size: DialogSize = 'lg';
|
|
12
|
+
export let dismissible = true;
|
|
13
|
+
export let closeOnBackdrop = true;
|
|
14
|
+
export let closeOnEscape = true;
|
|
15
|
+
export let dimBackdrop = true;
|
|
16
|
+
export let blurBackdrop = false;
|
|
17
|
+
export let backdropOpacity: number | string = 0.46;
|
|
18
|
+
export let backdropBlur = '6px';
|
|
19
|
+
export let templateUrl: string | undefined = undefined;
|
|
20
|
+
export let templateDownloadName: string | undefined = undefined;
|
|
21
|
+
export let downloadTemplateLabel = 'Download template';
|
|
22
|
+
export let fileLabel = 'Select CSV file';
|
|
23
|
+
export let uploadLabel = 'Upload';
|
|
24
|
+
export let cancelLabel = 'Cancel';
|
|
25
|
+
export let doneLabel = 'Done';
|
|
26
|
+
export let uploadAnotherLabel = 'Upload another';
|
|
27
|
+
export let instructionsTitle = 'Instructions';
|
|
28
|
+
export let instructions: string[] = [];
|
|
29
|
+
export let accept = '.csv,text/csv';
|
|
30
|
+
export let missingFileMessage = 'Please select a CSV file.';
|
|
31
|
+
export let uploadFailedMessage = 'Upload failed. Please try again.';
|
|
32
|
+
export let successMessage = 'Upload completed.';
|
|
33
|
+
export let externalError = '';
|
|
34
|
+
export let disabled = false;
|
|
35
|
+
export let onUpload: ((file: File) => void | Promise<void>) | undefined = undefined;
|
|
36
|
+
export let onCancel: (() => void) | undefined = undefined;
|
|
37
|
+
export let onClose: (() => void) | undefined = undefined;
|
|
38
|
+
export let onFileChange: ((file: File | null) => void) | undefined = undefined;
|
|
39
|
+
|
|
40
|
+
let selectedFile: File | null = null;
|
|
41
|
+
let fileInput: HTMLInputElement | undefined;
|
|
42
|
+
let localError = '';
|
|
43
|
+
let localUploading = false;
|
|
44
|
+
let uploadComplete = false;
|
|
45
|
+
|
|
46
|
+
$: isBusy = disabled || localUploading;
|
|
47
|
+
$: effectiveError = externalError || localError;
|
|
48
|
+
|
|
49
|
+
function resetFileState() {
|
|
50
|
+
selectedFile = null;
|
|
51
|
+
localError = '';
|
|
52
|
+
uploadComplete = false;
|
|
53
|
+
if (fileInput) {
|
|
54
|
+
fileInput.value = '';
|
|
55
|
+
}
|
|
56
|
+
onFileChange?.(null);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function handleClose() {
|
|
60
|
+
resetFileState();
|
|
61
|
+
onClose?.();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function handleCancel() {
|
|
65
|
+
resetFileState();
|
|
66
|
+
onCancel?.();
|
|
67
|
+
onClose?.();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function handleFileChange(event: Event) {
|
|
71
|
+
const target = event.currentTarget;
|
|
72
|
+
selectedFile = target instanceof HTMLInputElement
|
|
73
|
+
? target.files?.[0] ?? null
|
|
74
|
+
: null;
|
|
75
|
+
localError = '';
|
|
76
|
+
uploadComplete = false;
|
|
77
|
+
onFileChange?.(selectedFile);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function handleUpload() {
|
|
81
|
+
if (!selectedFile) {
|
|
82
|
+
localError = missingFileMessage;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
localError = '';
|
|
87
|
+
localUploading = true;
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
await onUpload?.(selectedFile);
|
|
91
|
+
uploadComplete = true;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
localError = error instanceof Error ? error.message : uploadFailedMessage;
|
|
94
|
+
} finally {
|
|
95
|
+
localUploading = false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
</script>
|
|
99
|
+
|
|
100
|
+
<Dialog
|
|
101
|
+
{open}
|
|
102
|
+
{title}
|
|
103
|
+
{description}
|
|
104
|
+
{closeLabel}
|
|
105
|
+
{size}
|
|
106
|
+
{dismissible}
|
|
107
|
+
{closeOnBackdrop}
|
|
108
|
+
{closeOnEscape}
|
|
109
|
+
{dimBackdrop}
|
|
110
|
+
{blurBackdrop}
|
|
111
|
+
{backdropOpacity}
|
|
112
|
+
{backdropBlur}
|
|
113
|
+
onClose={handleClose}
|
|
114
|
+
>
|
|
115
|
+
<div class="suu-csv-upload-dialog">
|
|
116
|
+
{#if templateUrl}
|
|
117
|
+
<div class="suu-csv-upload-dialog__center">
|
|
118
|
+
<a
|
|
119
|
+
class="suu-dialog__button"
|
|
120
|
+
href={templateUrl}
|
|
121
|
+
download={templateDownloadName}
|
|
122
|
+
>
|
|
123
|
+
{downloadTemplateLabel}
|
|
124
|
+
</a>
|
|
125
|
+
</div>
|
|
126
|
+
{/if}
|
|
127
|
+
|
|
128
|
+
<label class="suu-csv-upload-dialog__field">
|
|
129
|
+
<span>{fileLabel}</span>
|
|
130
|
+
<input
|
|
131
|
+
bind:this={fileInput}
|
|
132
|
+
type="file"
|
|
133
|
+
{accept}
|
|
134
|
+
disabled={isBusy}
|
|
135
|
+
on:change={handleFileChange}
|
|
136
|
+
/>
|
|
137
|
+
</label>
|
|
138
|
+
|
|
139
|
+
{#if selectedFile}
|
|
140
|
+
<p class="suu-csv-upload-dialog__selected">{selectedFile.name}</p>
|
|
141
|
+
{/if}
|
|
142
|
+
|
|
143
|
+
{#if $$slots.preview}
|
|
144
|
+
<slot name="preview" file={selectedFile} uploading={localUploading} complete={uploadComplete} />
|
|
145
|
+
{/if}
|
|
146
|
+
|
|
147
|
+
{#if effectiveError}
|
|
148
|
+
<div class="suu-dialog__alert suu-dialog__alert--error" role="alert">
|
|
149
|
+
{effectiveError}
|
|
150
|
+
</div>
|
|
151
|
+
{/if}
|
|
152
|
+
|
|
153
|
+
{#if localUploading}
|
|
154
|
+
<div class="suu-dialog__status" role="status">
|
|
155
|
+
<span class="suu-dialog__spinner" aria-hidden="true"></span>
|
|
156
|
+
<span>{uploadLabel}...</span>
|
|
157
|
+
</div>
|
|
158
|
+
{/if}
|
|
159
|
+
|
|
160
|
+
{#if uploadComplete}
|
|
161
|
+
<div class="suu-dialog__alert suu-dialog__alert--success" role="status">
|
|
162
|
+
{successMessage}
|
|
163
|
+
</div>
|
|
164
|
+
{/if}
|
|
165
|
+
|
|
166
|
+
{#if instructions.length > 0}
|
|
167
|
+
<section class="suu-csv-upload-dialog__instructions" aria-label={instructionsTitle}>
|
|
168
|
+
<h3>{instructionsTitle}</h3>
|
|
169
|
+
<ul>
|
|
170
|
+
{#each instructions as instruction}
|
|
171
|
+
<li>{instruction}</li>
|
|
172
|
+
{/each}
|
|
173
|
+
</ul>
|
|
174
|
+
</section>
|
|
175
|
+
{/if}
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<svelte:fragment slot="footer">
|
|
179
|
+
<button
|
|
180
|
+
type="button"
|
|
181
|
+
class="suu-dialog__button"
|
|
182
|
+
disabled={isBusy}
|
|
183
|
+
on:click={handleCancel}
|
|
184
|
+
>
|
|
185
|
+
{uploadComplete ? doneLabel : cancelLabel}
|
|
186
|
+
</button>
|
|
187
|
+
{#if uploadComplete}
|
|
188
|
+
<button
|
|
189
|
+
type="button"
|
|
190
|
+
class="suu-dialog__button suu-dialog__button--primary"
|
|
191
|
+
disabled={isBusy}
|
|
192
|
+
on:click={resetFileState}
|
|
193
|
+
>
|
|
194
|
+
{uploadAnotherLabel}
|
|
195
|
+
</button>
|
|
196
|
+
{:else}
|
|
197
|
+
<button
|
|
198
|
+
type="button"
|
|
199
|
+
class="suu-dialog__button suu-dialog__button--primary"
|
|
200
|
+
disabled={isBusy || !selectedFile}
|
|
201
|
+
on:click={handleUpload}
|
|
202
|
+
>
|
|
203
|
+
{uploadLabel}
|
|
204
|
+
</button>
|
|
205
|
+
{/if}
|
|
206
|
+
</svelte:fragment>
|
|
207
|
+
</Dialog>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { DialogSize } from './types.js';
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: Props & {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const CsvUploadDialog: $$__sveltets_2_IsomorphicComponent<{
|
|
16
|
+
open?: boolean;
|
|
17
|
+
title?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
closeLabel?: string;
|
|
20
|
+
size?: DialogSize;
|
|
21
|
+
dismissible?: boolean;
|
|
22
|
+
closeOnBackdrop?: boolean;
|
|
23
|
+
closeOnEscape?: boolean;
|
|
24
|
+
dimBackdrop?: boolean;
|
|
25
|
+
blurBackdrop?: boolean;
|
|
26
|
+
backdropOpacity?: number | string;
|
|
27
|
+
backdropBlur?: string;
|
|
28
|
+
templateUrl?: string | undefined;
|
|
29
|
+
templateDownloadName?: string | undefined;
|
|
30
|
+
downloadTemplateLabel?: string;
|
|
31
|
+
fileLabel?: string;
|
|
32
|
+
uploadLabel?: string;
|
|
33
|
+
cancelLabel?: string;
|
|
34
|
+
doneLabel?: string;
|
|
35
|
+
uploadAnotherLabel?: string;
|
|
36
|
+
instructionsTitle?: string;
|
|
37
|
+
instructions?: string[];
|
|
38
|
+
accept?: string;
|
|
39
|
+
missingFileMessage?: string;
|
|
40
|
+
uploadFailedMessage?: string;
|
|
41
|
+
successMessage?: string;
|
|
42
|
+
externalError?: string;
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
onUpload?: ((file: File) => void | Promise<void>) | undefined;
|
|
45
|
+
onCancel?: (() => void) | undefined;
|
|
46
|
+
onClose?: (() => void) | undefined;
|
|
47
|
+
onFileChange?: ((file: File | null) => void) | undefined;
|
|
48
|
+
}, {
|
|
49
|
+
[evt: string]: CustomEvent<any>;
|
|
50
|
+
}, {
|
|
51
|
+
preview: {
|
|
52
|
+
file: null;
|
|
53
|
+
uploading: boolean;
|
|
54
|
+
complete: boolean;
|
|
55
|
+
};
|
|
56
|
+
}, {}, string>;
|
|
57
|
+
type CsvUploadDialog = InstanceType<typeof CsvUploadDialog>;
|
|
58
|
+
export default CsvUploadDialog;
|
|
59
|
+
//# sourceMappingURL=CsvUploadDialog.svelte.d.ts.map
|
|
@@ -0,0 +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;AA6K7C,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;;;;;WAfggC,UAAU;;;;;;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;;;;;;;;;cAep9D,CAAC;AACzF,KAAK,eAAe,GAAG,YAAY,CAAC,OAAO,eAAe,CAAC,CAAC;AAC9D,eAAe,eAAe,CAAC"}
|
|
@@ -2,29 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
<script lang="ts">
|
|
4
4
|
import { tick } from 'svelte';
|
|
5
|
-
import type {
|
|
5
|
+
import type { DialogSize } from './types.js';
|
|
6
6
|
|
|
7
7
|
export let open = false;
|
|
8
8
|
export let title = '';
|
|
9
9
|
export let description = '';
|
|
10
10
|
export let closeLabel = 'Close dialog';
|
|
11
|
-
export let size:
|
|
11
|
+
export let size: DialogSize = 'md';
|
|
12
12
|
export let dismissible = true;
|
|
13
|
+
export let showCloseButton = true;
|
|
13
14
|
export let closeOnBackdrop = true;
|
|
14
15
|
export let closeOnEscape = true;
|
|
16
|
+
export let dimBackdrop = true;
|
|
17
|
+
export let blurBackdrop = false;
|
|
18
|
+
export let backdropOpacity: number | string = 0.46;
|
|
19
|
+
export let backdropBlur = '6px';
|
|
20
|
+
export let showCountdown = false;
|
|
21
|
+
export let countdownDurationMs = 0;
|
|
22
|
+
export let countdownLabel = 'Dialog countdown';
|
|
15
23
|
export let labelledBy: string | undefined = undefined;
|
|
16
24
|
export let describedBy: string | undefined = undefined;
|
|
17
25
|
export let onClose: (() => void) | undefined = undefined;
|
|
18
26
|
|
|
19
27
|
let dialogElement: HTMLElement | undefined;
|
|
20
|
-
let titleId = `suu-
|
|
21
|
-
let descriptionId = `suu-
|
|
28
|
+
let titleId = `suu-dialog-title-${Math.random().toString(36).slice(2)}`;
|
|
29
|
+
let descriptionId = `suu-dialog-description-${Math.random().toString(36).slice(2)}`;
|
|
22
30
|
let wasOpen = false;
|
|
23
31
|
let previouslyFocusedElement: HTMLElement | null = null;
|
|
24
32
|
|
|
25
33
|
$: resolvedLabelledBy = labelledBy ?? (title ? titleId : undefined);
|
|
26
34
|
$: resolvedDescribedBy =
|
|
27
35
|
describedBy ?? (description ? descriptionId : undefined);
|
|
36
|
+
$: backdropStyle =
|
|
37
|
+
`--suu-dialog-backdrop-opacity: ${backdropOpacity}; --suu-dialog-backdrop-blur: ${backdropBlur};`;
|
|
38
|
+
$: countdownStyle = `--suu-dialog-countdown-duration: ${Math.max(0, countdownDurationMs)}ms;`;
|
|
28
39
|
$: if (open && !wasOpen) {
|
|
29
40
|
wasOpen = true;
|
|
30
41
|
void focusDialog();
|
|
@@ -67,7 +78,7 @@
|
|
|
67
78
|
}
|
|
68
79
|
|
|
69
80
|
function handleKeydown(event: KeyboardEvent) {
|
|
70
|
-
if (event.key === 'Escape' && closeOnEscape) {
|
|
81
|
+
if (open && event.key === 'Escape' && closeOnEscape) {
|
|
71
82
|
event.preventDefault();
|
|
72
83
|
requestClose();
|
|
73
84
|
}
|
|
@@ -78,34 +89,45 @@
|
|
|
78
89
|
|
|
79
90
|
{#if open}
|
|
80
91
|
<div
|
|
81
|
-
class="suu-
|
|
92
|
+
class="suu-dialog-backdrop"
|
|
93
|
+
data-dimmed={dimBackdrop ? 'true' : 'false'}
|
|
94
|
+
data-blurred={blurBackdrop ? 'true' : 'false'}
|
|
95
|
+
style={backdropStyle}
|
|
82
96
|
role="presentation"
|
|
83
97
|
on:mousedown={handleBackdropMouseDown}
|
|
84
98
|
>
|
|
85
99
|
<div
|
|
86
100
|
bind:this={dialogElement}
|
|
87
|
-
class={`suu-
|
|
101
|
+
class={`suu-dialog suu-dialog--${size}`}
|
|
88
102
|
role="dialog"
|
|
89
103
|
aria-modal="true"
|
|
90
104
|
aria-labelledby={resolvedLabelledBy}
|
|
91
105
|
aria-describedby={resolvedDescribedBy}
|
|
92
106
|
tabindex="-1"
|
|
93
107
|
>
|
|
94
|
-
|
|
95
|
-
<div
|
|
108
|
+
{#if showCountdown && countdownDurationMs > 0}
|
|
109
|
+
<div
|
|
110
|
+
class="suu-dialog__countdown"
|
|
111
|
+
style={countdownStyle}
|
|
112
|
+
role="timer"
|
|
113
|
+
aria-label={countdownLabel}
|
|
114
|
+
></div>
|
|
115
|
+
{/if}
|
|
116
|
+
<header class="suu-dialog__header">
|
|
117
|
+
<div class="suu-dialog__heading">
|
|
96
118
|
{#if title}
|
|
97
|
-
<h2 class="suu-
|
|
119
|
+
<h2 class="suu-dialog__title" id={titleId}>{title}</h2>
|
|
98
120
|
{/if}
|
|
99
121
|
{#if description}
|
|
100
|
-
<p class="suu-
|
|
122
|
+
<p class="suu-dialog__description" id={descriptionId}>
|
|
101
123
|
{description}
|
|
102
124
|
</p>
|
|
103
125
|
{/if}
|
|
104
126
|
</div>
|
|
105
|
-
{#if dismissible}
|
|
127
|
+
{#if showCloseButton && dismissible}
|
|
106
128
|
<button
|
|
107
129
|
type="button"
|
|
108
|
-
class="suu-
|
|
130
|
+
class="suu-dialog__close"
|
|
109
131
|
aria-label={closeLabel}
|
|
110
132
|
title={closeLabel}
|
|
111
133
|
on:click={requestClose}
|
|
@@ -117,12 +139,12 @@
|
|
|
117
139
|
{/if}
|
|
118
140
|
</header>
|
|
119
141
|
|
|
120
|
-
<div class="suu-
|
|
142
|
+
<div class="suu-dialog__body">
|
|
121
143
|
<slot />
|
|
122
144
|
</div>
|
|
123
145
|
|
|
124
146
|
{#if $$slots.footer}
|
|
125
|
-
<footer class="suu-
|
|
147
|
+
<footer class="suu-dialog__footer">
|
|
126
148
|
<slot name="footer" />
|
|
127
149
|
</footer>
|
|
128
150
|
{/if}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DialogSize } from './types.js';
|
|
2
2
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
3
|
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
4
|
$$bindings?: Bindings;
|
|
@@ -17,15 +17,23 @@ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
|
17
17
|
} ? Props extends Record<string, never> ? any : {
|
|
18
18
|
children?: any;
|
|
19
19
|
} : {});
|
|
20
|
-
declare const
|
|
20
|
+
declare const Dialog: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
|
|
21
21
|
open?: boolean;
|
|
22
22
|
title?: string;
|
|
23
23
|
description?: string;
|
|
24
24
|
closeLabel?: string;
|
|
25
|
-
size?:
|
|
25
|
+
size?: DialogSize;
|
|
26
26
|
dismissible?: boolean;
|
|
27
|
+
showCloseButton?: boolean;
|
|
27
28
|
closeOnBackdrop?: boolean;
|
|
28
29
|
closeOnEscape?: boolean;
|
|
30
|
+
dimBackdrop?: boolean;
|
|
31
|
+
blurBackdrop?: boolean;
|
|
32
|
+
backdropOpacity?: number | string;
|
|
33
|
+
backdropBlur?: string;
|
|
34
|
+
showCountdown?: boolean;
|
|
35
|
+
countdownDurationMs?: number;
|
|
36
|
+
countdownLabel?: string;
|
|
29
37
|
labelledBy?: string | undefined;
|
|
30
38
|
describedBy?: string | undefined;
|
|
31
39
|
onClose?: (() => void) | undefined;
|
|
@@ -38,6 +46,6 @@ declare const Modal: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWith
|
|
|
38
46
|
default: {};
|
|
39
47
|
footer: {};
|
|
40
48
|
}, {}, string>;
|
|
41
|
-
type
|
|
42
|
-
export default
|
|
43
|
-
//# sourceMappingURL=
|
|
49
|
+
type Dialog = InstanceType<typeof Dialog>;
|
|
50
|
+
export default Dialog;
|
|
51
|
+
//# sourceMappingURL=Dialog.svelte.d.ts.map
|
|
@@ -0,0 +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;AAoI7C,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;;;;;WAfkoB,UAAU;;;;;;;sBAAsP,MAAM,GAAG,MAAM;;;;;iBAAmL,MAAM,GAAG,SAAS;kBAAgB,MAAM,GAAG,SAAS;cAAY,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS;;;;;;;;;cAevkC,CAAC;AAChF,KAAK,MAAM,GAAG,YAAY,CAAC,OAAO,MAAM,CAAC,CAAC;AAC5C,eAAe,MAAM,CAAC"}
|