@sveltia/ui 0.7.5 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package/components/alert/alert.svelte +4 -4
- package/package/components/alert/alert.svelte.d.ts +2 -2
- package/package/components/button/button.svelte +5 -3
- package/package/components/button/button.svelte.d.ts +6 -4
- package/package/components/button/select-button-group.svelte +9 -5
- package/package/components/button/select-button.svelte +5 -4
- package/package/components/button/select-button.svelte.d.ts +2 -0
- package/package/components/calendar/calendar.svelte +20 -14
- package/package/components/checkbox/checkbox-group.svelte +6 -5
- package/package/components/checkbox/checkbox.svelte +6 -4
- package/package/components/checkbox/checkbox.svelte.d.ts +2 -2
- package/package/components/dialog/alert-dialog.svelte +50 -0
- package/package/components/dialog/alert-dialog.svelte.d.ts +55 -0
- package/package/components/dialog/confirmation-dialog.svelte +55 -0
- package/package/components/dialog/confirmation-dialog.svelte.d.ts +57 -0
- package/package/components/dialog/dialog.svelte +165 -221
- package/package/components/dialog/dialog.svelte.d.ts +20 -12
- package/package/components/dialog/prompt-dialog.svelte +78 -0
- package/package/components/dialog/prompt-dialog.svelte.d.ts +72 -0
- package/package/components/disclosure/disclosure.svelte +3 -2
- package/package/components/divider/divider.svelte +1 -1
- package/package/components/divider/spacer.svelte +1 -12
- package/package/components/divider/spacer.svelte.d.ts +0 -2
- package/package/components/drawer/drawer.svelte +119 -209
- package/package/components/drawer/drawer.svelte.d.ts +13 -9
- package/package/components/grid/grid-body.svelte +51 -0
- package/package/components/grid/grid-body.svelte.d.ts +36 -0
- package/package/components/grid/grid-cell.svelte +22 -0
- package/package/components/grid/grid-cell.svelte.d.ts +34 -0
- package/package/components/grid/grid-col-header.svelte +22 -0
- package/package/components/grid/grid-col-header.svelte.d.ts +34 -0
- package/package/components/grid/grid-foot.svelte +27 -0
- package/package/components/grid/grid-foot.svelte.d.ts +34 -0
- package/package/components/grid/grid-head.svelte +27 -0
- package/package/components/grid/grid-head.svelte.d.ts +34 -0
- package/package/components/grid/grid-row-header.svelte +23 -0
- package/package/components/grid/grid-row-header.svelte.d.ts +34 -0
- package/package/components/grid/grid-row.svelte +37 -0
- package/package/components/grid/grid-row.svelte.d.ts +44 -0
- package/package/components/grid/grid.svelte +52 -0
- package/package/components/grid/grid.svelte.d.ts +42 -0
- package/package/components/icon/icon.svelte +6 -7
- package/package/components/icon/icon.svelte.d.ts +0 -2
- package/package/components/listbox/listbox.svelte +3 -3
- package/package/components/listbox/option-group.svelte +6 -5
- package/package/components/listbox/option.svelte +7 -28
- package/package/components/listbox/option.svelte.d.ts +2 -0
- package/package/components/menu/menu-button.svelte +26 -16
- package/package/components/menu/menu-button.svelte.d.ts +2 -2
- package/package/components/menu/menu-item-checkbox.svelte +5 -4
- package/package/components/menu/menu-item-checkbox.svelte.d.ts +2 -0
- package/package/components/menu/menu-item-group.svelte +4 -3
- package/package/components/menu/menu-item-radio.svelte +5 -4
- package/package/components/menu/menu-item-radio.svelte.d.ts +2 -0
- package/package/components/menu/menu-item.svelte +7 -5
- package/package/components/menu/menu-item.svelte.d.ts +4 -2
- package/package/components/menu/menu.svelte +1 -1
- package/package/components/radio/radio-group.svelte +5 -5
- package/package/components/radio/radio.svelte +5 -2
- package/package/components/radio/radio.svelte.d.ts +2 -0
- package/package/components/select/combobox.svelte +11 -9
- package/package/components/slider/slider.svelte +12 -5
- package/package/components/switch/switch.svelte +3 -2
- package/package/components/switch/switch.svelte.d.ts +2 -2
- package/package/components/table/table-body.svelte +31 -3
- package/package/components/table/table-body.svelte.d.ts +2 -0
- package/package/components/table/table-cell.svelte +3 -4
- package/package/components/table/table-cell.svelte.d.ts +1 -1
- package/package/components/table/table-col-header.svelte +1 -2
- package/package/components/table/table-foot.svelte +7 -3
- package/package/components/table/table-head.svelte +7 -3
- package/package/components/table/table-row-header.svelte +1 -2
- package/package/components/table/table-row.svelte +1 -14
- package/package/components/table/table-row.svelte.d.ts +0 -8
- package/package/components/table/table.svelte +5 -17
- package/package/components/table/table.svelte.d.ts +1 -7
- package/package/components/tabs/tab-list.svelte +7 -5
- package/package/components/tabs/tab-panel.svelte +1 -1
- package/package/components/tabs/tab.svelte +2 -1
- package/package/components/tabs/tab.svelte.d.ts +2 -0
- package/package/components/text-field/markdown-editor.svelte +30 -6
- package/package/components/text-field/markdown-editor.svelte.d.ts +2 -0
- package/package/components/text-field/number-input.svelte +36 -6
- package/package/components/text-field/number-input.svelte.d.ts +2 -0
- package/package/components/text-field/password-input.svelte +34 -8
- package/package/components/text-field/password-input.svelte.d.ts +2 -0
- package/package/components/text-field/search-bar.svelte +39 -11
- package/package/components/text-field/search-bar.svelte.d.ts +5 -0
- package/package/components/text-field/text-area.svelte +21 -2
- package/package/components/text-field/text-area.svelte.d.ts +2 -0
- package/package/components/text-field/text-input.svelte +22 -4
- package/package/components/text-field/text-input.svelte.d.ts +7 -2
- package/package/components/toast/toast.svelte +6 -16
- package/package/components/toast/toast.svelte.d.ts +2 -2
- package/package/components/toolbar/toolbar.svelte +3 -4
- package/package/components/util/app-shell.svelte +26 -27
- package/package/components/util/group.svelte +2 -2
- package/package/components/util/modal.svelte +220 -0
- package/package/components/util/modal.svelte.d.ts +83 -0
- package/package/components/util/popup.svelte +81 -127
- package/package/components/util/popup.svelte.d.ts +22 -18
- package/package/components/util/portal.svelte +1 -1
- package/package/index.d.ts +12 -0
- package/package/index.js +12 -0
- package/package/locales/en.d.ts +1 -0
- package/package/locales/en.js +1 -0
- package/package/locales/ja.d.ts +1 -0
- package/package/locales/ja.js +1 -0
- package/package/services/group.js +51 -13
- package/package/styles/core.scss +9 -26
- package/package/styles/variables.scss +12 -0
- package/package.json +97 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
A generic modal top-layer helper based on the HTML `<dialog>` element.
|
|
4
|
+
-->
|
|
5
|
+
<svelte:options accessors={true} />
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
import { createEventDispatcher, onMount } from 'svelte';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The `class` attribute on the `<dialog>` element.
|
|
12
|
+
* @type {string}
|
|
13
|
+
*/
|
|
14
|
+
let className = '';
|
|
15
|
+
export { className as class };
|
|
16
|
+
/**
|
|
17
|
+
* The `role` attribute on the `<dialog>` element.
|
|
18
|
+
* @type {'dialog' | 'alertdialog' | 'none'}
|
|
19
|
+
*/
|
|
20
|
+
export let role = 'dialog';
|
|
21
|
+
/**
|
|
22
|
+
* Whether to show the modal.
|
|
23
|
+
* @type {boolean}
|
|
24
|
+
*/
|
|
25
|
+
export let open = false;
|
|
26
|
+
/**
|
|
27
|
+
* Whether to show the backdrop.
|
|
28
|
+
* @type {boolean}
|
|
29
|
+
*/
|
|
30
|
+
export let showBackdrop = false;
|
|
31
|
+
/**
|
|
32
|
+
* Whether to close the modal when the backdrop (outside of the modal) is clicked.
|
|
33
|
+
* @type {boolean}
|
|
34
|
+
*/
|
|
35
|
+
export let lightDismiss = false;
|
|
36
|
+
/**
|
|
37
|
+
* Whether to close the modal when the Escape key is pressed.
|
|
38
|
+
* @type {boolean}
|
|
39
|
+
*/
|
|
40
|
+
export let escapeDismiss = true;
|
|
41
|
+
/**
|
|
42
|
+
* Whether to keep the content in the DOM tree when the modal is not displayed.
|
|
43
|
+
* @type {boolean}
|
|
44
|
+
*/
|
|
45
|
+
export let keepContent = false;
|
|
46
|
+
/**
|
|
47
|
+
* A reference to the `<dialog>` element.
|
|
48
|
+
* @type {HTMLDialogElement}
|
|
49
|
+
*/
|
|
50
|
+
export let dialog = undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Close the modal.
|
|
53
|
+
* @param {string} returnValue Return value to be used for `<dialog>`.
|
|
54
|
+
*/
|
|
55
|
+
export const close = (returnValue) => {
|
|
56
|
+
dialog.returnValue = returnValue;
|
|
57
|
+
open = false;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const dispatch = createEventDispatcher();
|
|
61
|
+
let setOpenClass = false;
|
|
62
|
+
let setActiveClass = false;
|
|
63
|
+
let showContent = false;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Resolve once the transition is complete.
|
|
67
|
+
* @returns {Promise<void>} Nothing.
|
|
68
|
+
*/
|
|
69
|
+
const waitForTransition = async () =>
|
|
70
|
+
new Promise((resolve) => {
|
|
71
|
+
/**
|
|
72
|
+
* @param {TransitionEvent} event `transition` event.
|
|
73
|
+
*/
|
|
74
|
+
const listener = (event) => {
|
|
75
|
+
if (event.target === dialog) {
|
|
76
|
+
dialog.removeEventListener('transitionend', listener);
|
|
77
|
+
resolve();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
dialog.addEventListener('transitionend', listener);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Show the modal.
|
|
86
|
+
*/
|
|
87
|
+
const openDialog = async () => {
|
|
88
|
+
dispatch('opening');
|
|
89
|
+
(document.querySelector('.sui.app-shell') ?? document.body).appendChild(dialog);
|
|
90
|
+
showContent = true;
|
|
91
|
+
dialog.showModal();
|
|
92
|
+
|
|
93
|
+
window.requestAnimationFrame(async () => {
|
|
94
|
+
dispatch('open');
|
|
95
|
+
setOpenClass = true;
|
|
96
|
+
await waitForTransition();
|
|
97
|
+
setActiveClass = true;
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Hide the modal.
|
|
103
|
+
*/
|
|
104
|
+
const closeDialog = async () => {
|
|
105
|
+
dispatch('closing');
|
|
106
|
+
setActiveClass = false;
|
|
107
|
+
setOpenClass = false;
|
|
108
|
+
await waitForTransition();
|
|
109
|
+
showContent = false;
|
|
110
|
+
dialog.close();
|
|
111
|
+
dialog.remove();
|
|
112
|
+
|
|
113
|
+
if (['ok', 'cancel'].includes(dialog?.returnValue)) {
|
|
114
|
+
dispatch(dialog?.returnValue);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
dispatch('close', dialog?.returnValue);
|
|
118
|
+
dialog.returnValue = undefined;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Toggle the modal.
|
|
123
|
+
*/
|
|
124
|
+
const toggleDialog = () => {
|
|
125
|
+
if (dialog) {
|
|
126
|
+
if (open) {
|
|
127
|
+
openDialog();
|
|
128
|
+
} else {
|
|
129
|
+
closeDialog();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
$: {
|
|
135
|
+
void open;
|
|
136
|
+
void dialog;
|
|
137
|
+
toggleDialog();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
onMount(() => {
|
|
141
|
+
dialog.remove();
|
|
142
|
+
|
|
143
|
+
// onUnmount
|
|
144
|
+
return () => {
|
|
145
|
+
dialog?.close();
|
|
146
|
+
dialog?.remove();
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
</script>
|
|
150
|
+
|
|
151
|
+
<dialog
|
|
152
|
+
{role}
|
|
153
|
+
class="sui modal {className}"
|
|
154
|
+
class:backdrop={showBackdrop}
|
|
155
|
+
class:open={setOpenClass}
|
|
156
|
+
class:active={setActiveClass}
|
|
157
|
+
{...$$restProps}
|
|
158
|
+
bind:this={dialog}
|
|
159
|
+
on:click={({ target }) => {
|
|
160
|
+
if (lightDismiss && /** @type {HTMLElement?} */ (target)?.matches('dialog')) {
|
|
161
|
+
dialog.returnValue = 'cancel';
|
|
162
|
+
open = false;
|
|
163
|
+
}
|
|
164
|
+
}}
|
|
165
|
+
on:cancel|preventDefault={() => {
|
|
166
|
+
// Escape key is pressed
|
|
167
|
+
if (escapeDismiss) {
|
|
168
|
+
open = false;
|
|
169
|
+
}
|
|
170
|
+
}}
|
|
171
|
+
>
|
|
172
|
+
<slot name="always-show" />
|
|
173
|
+
{#if showContent || keepContent}
|
|
174
|
+
<slot />
|
|
175
|
+
{/if}
|
|
176
|
+
</dialog>
|
|
177
|
+
|
|
178
|
+
<style>dialog {
|
|
179
|
+
position: fixed;
|
|
180
|
+
inset: 0;
|
|
181
|
+
display: flex;
|
|
182
|
+
justify-content: center;
|
|
183
|
+
align-items: center;
|
|
184
|
+
overflow: hidden;
|
|
185
|
+
outline: 0;
|
|
186
|
+
margin: 0;
|
|
187
|
+
border: 0;
|
|
188
|
+
padding: 0;
|
|
189
|
+
width: 100dvw;
|
|
190
|
+
max-width: 100dvw;
|
|
191
|
+
height: 100dvh;
|
|
192
|
+
max-height: 100dvh;
|
|
193
|
+
color: var(--sui-primary-foreground-color);
|
|
194
|
+
background: transparent;
|
|
195
|
+
-webkit-user-select: none;
|
|
196
|
+
user-select: none;
|
|
197
|
+
touch-action: none;
|
|
198
|
+
pointer-events: all;
|
|
199
|
+
cursor: default;
|
|
200
|
+
}
|
|
201
|
+
dialog::backdrop {
|
|
202
|
+
background: transparent;
|
|
203
|
+
}
|
|
204
|
+
dialog.backdrop {
|
|
205
|
+
background-color: var(--sui-popup-backdrop-color);
|
|
206
|
+
}
|
|
207
|
+
dialog.open {
|
|
208
|
+
transition-duration: 200ms;
|
|
209
|
+
opacity: 1;
|
|
210
|
+
}
|
|
211
|
+
dialog:not(.open) {
|
|
212
|
+
transition-duration: 400ms;
|
|
213
|
+
opacity: 0;
|
|
214
|
+
}
|
|
215
|
+
dialog:not(.active) {
|
|
216
|
+
pointer-events: none !important;
|
|
217
|
+
}
|
|
218
|
+
dialog:not(.active) :global(*) {
|
|
219
|
+
pointer-events: none !important;
|
|
220
|
+
}</style>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} ModalProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} ModalEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} ModalSlots */
|
|
4
|
+
/** A generic modal top-layer helper based on the HTML `<dialog>` element. */
|
|
5
|
+
export default class Modal extends SvelteComponent<{
|
|
6
|
+
[x: string]: any;
|
|
7
|
+
class?: string;
|
|
8
|
+
close?: (returnValue: string) => void;
|
|
9
|
+
dialog?: HTMLDialogElement;
|
|
10
|
+
role?: "dialog" | "none" | "alertdialog";
|
|
11
|
+
open?: boolean;
|
|
12
|
+
showBackdrop?: boolean;
|
|
13
|
+
lightDismiss?: boolean;
|
|
14
|
+
escapeDismiss?: boolean;
|
|
15
|
+
keepContent?: boolean;
|
|
16
|
+
}, {
|
|
17
|
+
opening: CustomEvent<any>;
|
|
18
|
+
open: CustomEvent<any>;
|
|
19
|
+
closing: CustomEvent<any>;
|
|
20
|
+
close: CustomEvent<any>;
|
|
21
|
+
} & {
|
|
22
|
+
[evt: string]: CustomEvent<any>;
|
|
23
|
+
}, {
|
|
24
|
+
'always-show': {};
|
|
25
|
+
default: {};
|
|
26
|
+
}> {
|
|
27
|
+
get close(): (returnValue: string) => void;
|
|
28
|
+
/**accessor*/
|
|
29
|
+
set class(arg: string);
|
|
30
|
+
get class(): string;
|
|
31
|
+
/**accessor*/
|
|
32
|
+
set role(arg: "dialog" | "none" | "alertdialog");
|
|
33
|
+
get role(): "dialog" | "none" | "alertdialog";
|
|
34
|
+
/**accessor*/
|
|
35
|
+
set open(arg: boolean);
|
|
36
|
+
get open(): boolean;
|
|
37
|
+
/**accessor*/
|
|
38
|
+
set showBackdrop(arg: boolean);
|
|
39
|
+
get showBackdrop(): boolean;
|
|
40
|
+
/**accessor*/
|
|
41
|
+
set lightDismiss(arg: boolean);
|
|
42
|
+
get lightDismiss(): boolean;
|
|
43
|
+
/**accessor*/
|
|
44
|
+
set escapeDismiss(arg: boolean);
|
|
45
|
+
get escapeDismiss(): boolean;
|
|
46
|
+
/**accessor*/
|
|
47
|
+
set keepContent(arg: boolean);
|
|
48
|
+
get keepContent(): boolean;
|
|
49
|
+
/**accessor*/
|
|
50
|
+
set dialog(arg: HTMLDialogElement);
|
|
51
|
+
get dialog(): HTMLDialogElement;
|
|
52
|
+
}
|
|
53
|
+
export type ModalProps = typeof __propDef.props;
|
|
54
|
+
export type ModalEvents = typeof __propDef.events;
|
|
55
|
+
export type ModalSlots = typeof __propDef.slots;
|
|
56
|
+
import { SvelteComponent } from "svelte";
|
|
57
|
+
declare const __propDef: {
|
|
58
|
+
props: {
|
|
59
|
+
[x: string]: any;
|
|
60
|
+
class?: string;
|
|
61
|
+
close?: (returnValue: string) => void;
|
|
62
|
+
dialog?: HTMLDialogElement;
|
|
63
|
+
role?: 'dialog' | 'alertdialog' | 'none';
|
|
64
|
+
open?: boolean;
|
|
65
|
+
showBackdrop?: boolean;
|
|
66
|
+
lightDismiss?: boolean;
|
|
67
|
+
escapeDismiss?: boolean;
|
|
68
|
+
keepContent?: boolean;
|
|
69
|
+
};
|
|
70
|
+
events: {
|
|
71
|
+
opening: CustomEvent<any>;
|
|
72
|
+
open: CustomEvent<any>;
|
|
73
|
+
closing: CustomEvent<any>;
|
|
74
|
+
close: CustomEvent<any>;
|
|
75
|
+
} & {
|
|
76
|
+
[evt: string]: CustomEvent<any>;
|
|
77
|
+
};
|
|
78
|
+
slots: {
|
|
79
|
+
'always-show': {};
|
|
80
|
+
default: {};
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
export {};
|
|
@@ -9,40 +9,34 @@
|
|
|
9
9
|
import { writable } from 'svelte/store';
|
|
10
10
|
import { activatePopup } from '../../services/popup';
|
|
11
11
|
import { sleep } from '../../services/util';
|
|
12
|
+
import Modal from './modal.svelte';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
* The `class` attribute on the
|
|
15
|
+
* The `class` attribute on the content element.
|
|
15
16
|
* @type {string}
|
|
16
17
|
*/
|
|
17
18
|
let className = '';
|
|
18
19
|
export { className as class };
|
|
19
|
-
|
|
20
|
-
/** @type {HTMLElement | undefined} */
|
|
21
|
-
export let anchor = undefined;
|
|
22
|
-
|
|
23
20
|
/**
|
|
24
|
-
*
|
|
25
|
-
* @type {
|
|
21
|
+
* Whether to open the popup.
|
|
22
|
+
* @type {import('svelte/store').Writable<boolean>}
|
|
26
23
|
*/
|
|
27
|
-
export let
|
|
28
|
-
|
|
24
|
+
export let open = writable(false);
|
|
25
|
+
/**
|
|
26
|
+
* A reference to the anchor element that opens the popup. Typically a `<button>`.
|
|
27
|
+
* @type {HTMLElement}
|
|
28
|
+
*/
|
|
29
|
+
export let anchor;
|
|
29
30
|
/**
|
|
30
|
-
*
|
|
31
|
-
* @type {HTMLElement
|
|
31
|
+
* A reference to the content element.
|
|
32
|
+
* @type {HTMLElement}
|
|
32
33
|
*/
|
|
33
34
|
export let content = undefined;
|
|
34
|
-
|
|
35
35
|
/**
|
|
36
|
-
* Where to show the
|
|
36
|
+
* Where to show the popup.
|
|
37
37
|
* @type {PopupPosition}
|
|
38
38
|
*/
|
|
39
39
|
export let position = 'bottom-left';
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Whether to keep the content when the dialog is not displayed.
|
|
43
|
-
*/
|
|
44
|
-
export let keepContent = false;
|
|
45
|
-
|
|
46
40
|
/**
|
|
47
41
|
* Whether to show the popup at the center of the screen on mobile/tablet and ignore the defined
|
|
48
42
|
* dropdown `position`.
|
|
@@ -50,14 +44,27 @@
|
|
|
50
44
|
*/
|
|
51
45
|
export let touchOptimized = false;
|
|
52
46
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
/**
|
|
48
|
+
* A reference to the modal component.
|
|
49
|
+
* @type {Modal}
|
|
50
|
+
*/
|
|
51
|
+
let modal;
|
|
52
|
+
/**
|
|
53
|
+
* Whether the touch is enabled on the user device.
|
|
54
|
+
* @type {boolean}
|
|
55
|
+
*/
|
|
57
56
|
let touchEnabled = false;
|
|
58
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* The type of the content displayed in the popup, defined with the `aria-haspopup` attribute on
|
|
59
|
+
* the anchor element.
|
|
60
|
+
* @type {string}
|
|
61
|
+
* @see https://w3c.github.io/aria/#aria-haspopup
|
|
62
|
+
*/
|
|
59
63
|
let contentType;
|
|
60
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Style to be applied to the content.
|
|
66
|
+
* @type {import('svelte/store').Writable<any>}
|
|
67
|
+
*/
|
|
61
68
|
let style = writable({
|
|
62
69
|
inset: undefined,
|
|
63
70
|
zIndex: undefined,
|
|
@@ -66,156 +73,103 @@
|
|
|
66
73
|
});
|
|
67
74
|
|
|
68
75
|
$: {
|
|
69
|
-
if (anchor && dialog) {
|
|
70
|
-
({ open, style } = activatePopup(anchor, dialog, position));
|
|
76
|
+
if (anchor && modal?.dialog) {
|
|
77
|
+
({ open, style } = activatePopup(anchor, modal.dialog, position));
|
|
71
78
|
contentType = anchor.getAttribute('aria-haspopup');
|
|
72
79
|
}
|
|
73
80
|
}
|
|
74
81
|
|
|
75
|
-
|
|
76
|
-
*
|
|
77
|
-
*/
|
|
78
|
-
const openDialog = () => {
|
|
79
|
-
(document.querySelector('.sui.app-shell') ?? document.body).appendChild(dialog);
|
|
80
|
-
showContent = true;
|
|
81
|
-
dialog.showModal();
|
|
82
|
-
|
|
83
|
-
window.requestAnimationFrame(async () => {
|
|
84
|
-
showDialog = true;
|
|
85
|
-
await sleep(100);
|
|
86
|
-
|
|
87
|
-
const target = /** @type {HTMLElement} */ (
|
|
88
|
-
content.querySelector('[tabindex]:not([aria-disabled="true"])')
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
if (target) {
|
|
92
|
-
target.focus();
|
|
93
|
-
} else {
|
|
94
|
-
content.tabIndex = -1;
|
|
95
|
-
content.focus();
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
*
|
|
102
|
-
*/
|
|
103
|
-
const closeDialog = async () => {
|
|
104
|
-
showDialog = false;
|
|
105
|
-
|
|
106
|
-
await new Promise((resolve) => {
|
|
107
|
-
content.addEventListener('transitionend', () => resolve(), { once: true });
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
showContent = false;
|
|
111
|
-
dialog?.close();
|
|
112
|
-
dialog?.remove();
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
*
|
|
117
|
-
*/
|
|
118
|
-
const toggleDialog = () => {
|
|
119
|
-
if (dialog) {
|
|
120
|
-
if ($open) {
|
|
121
|
-
openDialog();
|
|
122
|
-
} else {
|
|
123
|
-
closeDialog();
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
$: {
|
|
129
|
-
void $open;
|
|
130
|
-
toggleDialog();
|
|
131
|
-
}
|
|
82
|
+
$: touch = touchOptimized && touchEnabled;
|
|
132
83
|
|
|
133
84
|
onMount(() => {
|
|
134
|
-
dialog.remove();
|
|
135
|
-
|
|
136
85
|
touchEnabled = window.matchMedia('(pointer: coarse)').matches;
|
|
137
|
-
|
|
138
|
-
// onUnmount
|
|
139
|
-
return () => {
|
|
140
|
-
dialog?.close();
|
|
141
|
-
dialog?.remove();
|
|
142
|
-
};
|
|
143
86
|
});
|
|
144
87
|
</script>
|
|
145
88
|
|
|
146
|
-
<
|
|
147
|
-
class="sui popup {className}"
|
|
89
|
+
<Modal
|
|
148
90
|
role="none"
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
91
|
+
class="popup"
|
|
92
|
+
bind:open={$open}
|
|
93
|
+
showBackdrop={touch}
|
|
94
|
+
lightDismiss={true}
|
|
95
|
+
keepContent={true}
|
|
96
|
+
bind:this={modal}
|
|
152
97
|
{...$$restProps}
|
|
98
|
+
on:opening
|
|
99
|
+
on:open
|
|
100
|
+
on:ok
|
|
101
|
+
on:cancel
|
|
102
|
+
on:closing
|
|
103
|
+
on:close
|
|
104
|
+
on:open={async () => {
|
|
105
|
+
await sleep(100);
|
|
106
|
+
|
|
107
|
+
const target = /** @type {HTMLElement} */ (
|
|
108
|
+
content.querySelector('[tabindex]:not([aria-disabled="true"])')
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (target) {
|
|
112
|
+
target.focus();
|
|
113
|
+
} else {
|
|
114
|
+
content.tabIndex = -1;
|
|
115
|
+
content.focus();
|
|
116
|
+
}
|
|
117
|
+
}}
|
|
153
118
|
>
|
|
154
119
|
<div
|
|
155
|
-
|
|
156
|
-
class="content {contentType}"
|
|
120
|
+
role="none"
|
|
121
|
+
class="content {className} {contentType}"
|
|
122
|
+
class:touch
|
|
157
123
|
style:inset={$style.inset}
|
|
158
124
|
style:z-index={$style.zIndex}
|
|
159
125
|
style:min-width={$style.width}
|
|
160
126
|
style:max-height={$style.height}
|
|
161
127
|
style:visibility={$style.inset ? undefined : 'hidden'}
|
|
128
|
+
bind:this={content}
|
|
162
129
|
>
|
|
163
|
-
|
|
164
|
-
<slot />
|
|
165
|
-
{/if}
|
|
130
|
+
<slot />
|
|
166
131
|
</div>
|
|
167
|
-
</
|
|
132
|
+
</Modal>
|
|
168
133
|
|
|
169
|
-
<style>.
|
|
170
|
-
display: flex;
|
|
171
|
-
align-items: center;
|
|
172
|
-
justify-content: center;
|
|
173
|
-
background-color: var(--sui-popup-backdrop-color);
|
|
174
|
-
}
|
|
175
|
-
.popup.touch .content {
|
|
134
|
+
<style>.content.touch {
|
|
176
135
|
position: static;
|
|
177
136
|
border-width: 0 !important;
|
|
178
137
|
border-radius: 4px !important;
|
|
179
138
|
padding: 8px;
|
|
180
139
|
min-width: 320px !important;
|
|
181
|
-
max-width: calc(
|
|
182
|
-
max-height: calc(
|
|
140
|
+
max-width: calc(100dvw - 32px) !important;
|
|
141
|
+
max-height: calc(100dvh - 32px) !important;
|
|
183
142
|
}
|
|
184
|
-
.
|
|
143
|
+
:global(dialog.open) .content.touch {
|
|
185
144
|
transform: scale(100%) !important;
|
|
186
145
|
}
|
|
187
|
-
|
|
146
|
+
:global(dialog:not(.open)) .content.touch {
|
|
188
147
|
transform: scale(90%);
|
|
189
148
|
}
|
|
190
|
-
.
|
|
149
|
+
.content.touch.combobox :global(.sui.listbox) {
|
|
191
150
|
gap: 4px;
|
|
192
151
|
padding: 8px 4px !important;
|
|
193
152
|
}
|
|
194
|
-
.
|
|
153
|
+
:global(dialog.open) .content {
|
|
154
|
+
transition-duration: 150ms;
|
|
195
155
|
opacity: 1;
|
|
196
156
|
transform: translateY(2px);
|
|
197
|
-
transition-duration: 100ms;
|
|
198
|
-
}
|
|
199
|
-
.popup:not(.open) {
|
|
200
|
-
pointer-events: none;
|
|
201
157
|
}
|
|
202
|
-
|
|
158
|
+
:global(dialog:not(.open)) .content {
|
|
159
|
+
transition-duration: 300ms;
|
|
203
160
|
opacity: 0;
|
|
204
161
|
transform: translateY(-8px);
|
|
205
|
-
pointer-events: none;
|
|
206
|
-
transition-duration: 200ms;
|
|
207
162
|
}
|
|
208
163
|
|
|
209
164
|
.content {
|
|
210
|
-
position:
|
|
165
|
+
position: absolute;
|
|
211
166
|
overflow-y: auto;
|
|
212
167
|
outline-width: 0 !important;
|
|
213
168
|
color: var(--sui-primary-foreground-color);
|
|
214
169
|
background-color: var(--sui-secondary-background-color-translucent);
|
|
215
|
-
-webkit-backdrop-filter: blur(32px);
|
|
216
|
-
backdrop-filter: blur(32px);
|
|
217
170
|
box-shadow: 0 8px 16px var(--sui-popup-shadow-color);
|
|
218
|
-
|
|
171
|
+
-webkit-backdrop-filter: blur(16px);
|
|
172
|
+
backdrop-filter: blur(16px);
|
|
219
173
|
transition-property: opacity, transform;
|
|
220
174
|
}
|
|
221
175
|
.content.listbox, .content.menu {
|
|
@@ -4,15 +4,20 @@
|
|
|
4
4
|
/** Generic popup helper. */
|
|
5
5
|
export default class Popup extends SvelteComponent<{
|
|
6
6
|
[x: string]: any;
|
|
7
|
+
anchor: HTMLElement;
|
|
7
8
|
class?: string;
|
|
8
|
-
dialog?: HTMLDialogElement;
|
|
9
9
|
position?: PopupPosition;
|
|
10
|
-
|
|
10
|
+
open?: import("svelte/store").Writable<boolean>;
|
|
11
11
|
content?: HTMLElement;
|
|
12
|
-
keepContent?: boolean;
|
|
13
12
|
touchOptimized?: boolean;
|
|
14
|
-
open?: import("svelte/store").Writable<boolean>;
|
|
15
13
|
}, {
|
|
14
|
+
opening: CustomEvent<any>;
|
|
15
|
+
open: CustomEvent<any>;
|
|
16
|
+
ok: CustomEvent<any>;
|
|
17
|
+
cancel: CustomEvent<any>;
|
|
18
|
+
closing: CustomEvent<any>;
|
|
19
|
+
close: CustomEvent<any>;
|
|
20
|
+
} & {
|
|
16
21
|
[evt: string]: CustomEvent<any>;
|
|
17
22
|
}, {
|
|
18
23
|
default: {};
|
|
@@ -21,26 +26,20 @@ export default class Popup extends SvelteComponent<{
|
|
|
21
26
|
set class(arg: string);
|
|
22
27
|
get class(): string;
|
|
23
28
|
/**accessor*/
|
|
29
|
+
set open(arg: import("svelte/store").Writable<boolean>);
|
|
30
|
+
get open(): import("svelte/store").Writable<boolean>;
|
|
31
|
+
/**accessor*/
|
|
24
32
|
set anchor(arg: HTMLElement);
|
|
25
33
|
get anchor(): HTMLElement;
|
|
26
34
|
/**accessor*/
|
|
27
|
-
set dialog(arg: HTMLDialogElement);
|
|
28
|
-
get dialog(): HTMLDialogElement;
|
|
29
|
-
/**accessor*/
|
|
30
35
|
set content(arg: HTMLElement);
|
|
31
36
|
get content(): HTMLElement;
|
|
32
37
|
/**accessor*/
|
|
33
38
|
set position(arg: PopupPosition);
|
|
34
39
|
get position(): PopupPosition;
|
|
35
40
|
/**accessor*/
|
|
36
|
-
set keepContent(arg: boolean);
|
|
37
|
-
get keepContent(): boolean;
|
|
38
|
-
/**accessor*/
|
|
39
41
|
set touchOptimized(arg: boolean);
|
|
40
42
|
get touchOptimized(): boolean;
|
|
41
|
-
/**accessor*/
|
|
42
|
-
set open(arg: import("svelte/store").Writable<boolean>);
|
|
43
|
-
get open(): import("svelte/store").Writable<boolean>;
|
|
44
43
|
}
|
|
45
44
|
export type PopupProps = typeof __propDef.props;
|
|
46
45
|
export type PopupEvents = typeof __propDef.events;
|
|
@@ -49,16 +48,21 @@ import { SvelteComponent } from "svelte";
|
|
|
49
48
|
declare const __propDef: {
|
|
50
49
|
props: {
|
|
51
50
|
[x: string]: any;
|
|
51
|
+
anchor: HTMLElement;
|
|
52
52
|
class?: string;
|
|
53
|
-
dialog?: HTMLDialogElement | undefined;
|
|
54
53
|
position?: PopupPosition;
|
|
55
|
-
|
|
56
|
-
content?: HTMLElement
|
|
57
|
-
keepContent?: boolean;
|
|
54
|
+
open?: import('svelte/store').Writable<boolean>;
|
|
55
|
+
content?: HTMLElement;
|
|
58
56
|
touchOptimized?: boolean;
|
|
59
|
-
open?: import("svelte/store").Writable<boolean>;
|
|
60
57
|
};
|
|
61
58
|
events: {
|
|
59
|
+
opening: CustomEvent<any>;
|
|
60
|
+
open: CustomEvent<any>;
|
|
61
|
+
ok: CustomEvent<any>;
|
|
62
|
+
cancel: CustomEvent<any>;
|
|
63
|
+
closing: CustomEvent<any>;
|
|
64
|
+
close: CustomEvent<any>;
|
|
65
|
+
} & {
|
|
62
66
|
[evt: string]: CustomEvent<any>;
|
|
63
67
|
};
|
|
64
68
|
slots: {
|