@14ch/svelte-ui 0.0.64 → 0.0.65
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/dist/components/ConfirmDialog.svelte +18 -1
- package/dist/components/ConfirmDialog.svelte.d.ts +5 -0
- package/dist/components/Dialog.svelte +13 -1
- package/dist/components/Dialog.svelte.d.ts +4 -0
- package/dist/components/Drawer.svelte +13 -1
- package/dist/components/Drawer.svelte.d.ts +4 -0
- package/dist/components/Modal.svelte +33 -7
- package/dist/components/Modal.svelte.d.ts +5 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import Button from './Button.svelte';
|
|
6
6
|
import { convertToHtml } from '../utils/formatText';
|
|
7
7
|
import type { SvelteComponent } from 'svelte';
|
|
8
|
+
import type { CloseReason } from '../types/propOptions';
|
|
8
9
|
|
|
9
10
|
// =========================================================================
|
|
10
11
|
// Props, States & Constants
|
|
@@ -35,7 +36,11 @@
|
|
|
35
36
|
|
|
36
37
|
// イベントハンドラー
|
|
37
38
|
onSubmit?: () => void;
|
|
39
|
+
/** Called on cancel, including dismissal via Escape or a backdrop click. */
|
|
38
40
|
onCancel?: () => void;
|
|
41
|
+
onOpen?: () => void;
|
|
42
|
+
/** Called after the close animation completes, with the reason it was closed. */
|
|
43
|
+
onClose?: (reason: CloseReason) => void;
|
|
39
44
|
};
|
|
40
45
|
|
|
41
46
|
let {
|
|
@@ -60,7 +65,9 @@
|
|
|
60
65
|
|
|
61
66
|
// イベントハンドラー
|
|
62
67
|
onSubmit = () => {}, // No params for type inference
|
|
63
|
-
onCancel = () => {} // No params for type inference
|
|
68
|
+
onCancel = () => {}, // No params for type inference
|
|
69
|
+
onOpen = () => {},
|
|
70
|
+
onClose = () => {}
|
|
64
71
|
}: ConfirmDialogProps = $props();
|
|
65
72
|
|
|
66
73
|
let dialogRef: SvelteComponent | undefined = $state();
|
|
@@ -78,6 +85,14 @@
|
|
|
78
85
|
close();
|
|
79
86
|
};
|
|
80
87
|
|
|
88
|
+
const handleClose = (reason: CloseReason): void => {
|
|
89
|
+
// Escape / 背景クリックでの離脱もキャンセルとして扱う
|
|
90
|
+
if (reason !== 'explicit') {
|
|
91
|
+
onCancel();
|
|
92
|
+
}
|
|
93
|
+
onClose(reason);
|
|
94
|
+
};
|
|
95
|
+
|
|
81
96
|
/** Opens the dialog. */
|
|
82
97
|
export const open = (): void => {
|
|
83
98
|
isOpen = true;
|
|
@@ -102,6 +117,8 @@
|
|
|
102
117
|
{scrollable}
|
|
103
118
|
{closeIfClickOutside}
|
|
104
119
|
{focusFirstOnOpen}
|
|
120
|
+
{onOpen}
|
|
121
|
+
onClose={handleClose}
|
|
105
122
|
id={id ? `${id}-dialog` : undefined}
|
|
106
123
|
>
|
|
107
124
|
<div class="confirm-dialog-message">
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CloseReason } from '../types/propOptions';
|
|
1
2
|
export type ConfirmDialogProps = {
|
|
2
3
|
title?: string;
|
|
3
4
|
description?: string;
|
|
@@ -15,7 +16,11 @@ export type ConfirmDialogProps = {
|
|
|
15
16
|
closeIfClickOutside?: boolean;
|
|
16
17
|
focusFirstOnOpen?: boolean;
|
|
17
18
|
onSubmit?: () => void;
|
|
19
|
+
/** Called on cancel, including dismissal via Escape or a backdrop click. */
|
|
18
20
|
onCancel?: () => void;
|
|
21
|
+
onOpen?: () => void;
|
|
22
|
+
/** Called after the close animation completes, with the reason it was closed. */
|
|
23
|
+
onClose?: (reason: CloseReason) => void;
|
|
19
24
|
};
|
|
20
25
|
declare const ConfirmDialog: import("svelte").Component<ConfirmDialogProps, {
|
|
21
26
|
/** Opens the dialog. */ open: () => void;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* This prevents state synchronization bugs and ensures consistent behavior.
|
|
15
15
|
*/
|
|
16
16
|
import type { Snippet } from 'svelte';
|
|
17
|
+
import type { CloseReason } from '../types/propOptions';
|
|
17
18
|
import Modal from './Modal.svelte';
|
|
18
19
|
import { getStyleFromNumber } from '../utils/style';
|
|
19
20
|
|
|
@@ -56,6 +57,11 @@
|
|
|
56
57
|
// ARIA/アクセシビリティ
|
|
57
58
|
ariaLabel?: string;
|
|
58
59
|
ariaDescribedby?: string;
|
|
60
|
+
|
|
61
|
+
// イベントハンドラー
|
|
62
|
+
onOpen?: () => void;
|
|
63
|
+
/** Called after the close animation completes, with the reason it was closed. */
|
|
64
|
+
onClose?: (reason: CloseReason) => void;
|
|
59
65
|
};
|
|
60
66
|
|
|
61
67
|
let {
|
|
@@ -85,7 +91,11 @@
|
|
|
85
91
|
|
|
86
92
|
// ARIA/アクセシビリティ
|
|
87
93
|
ariaLabel,
|
|
88
|
-
ariaDescribedby
|
|
94
|
+
ariaDescribedby,
|
|
95
|
+
|
|
96
|
+
// イベントハンドラー
|
|
97
|
+
onOpen = () => {}, // No params for type inference
|
|
98
|
+
onClose = () => {}
|
|
89
99
|
}: DialogProps = $props();
|
|
90
100
|
|
|
91
101
|
let modalRef: Modal;
|
|
@@ -145,6 +155,8 @@
|
|
|
145
155
|
{closeIfClickOutside}
|
|
146
156
|
{restoreFocus}
|
|
147
157
|
{focusFirstOnOpen}
|
|
158
|
+
{onOpen}
|
|
159
|
+
{onClose}
|
|
148
160
|
componentType="Dialog"
|
|
149
161
|
{ariaLabel}
|
|
150
162
|
{ariaLabelledby}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* This prevents state synchronization bugs and ensures consistent behavior.
|
|
12
12
|
*/
|
|
13
13
|
import type { Snippet } from 'svelte';
|
|
14
|
+
import type { CloseReason } from '../types/propOptions';
|
|
14
15
|
export type DialogProps = {
|
|
15
16
|
header?: Snippet;
|
|
16
17
|
children?: Snippet;
|
|
@@ -36,6 +37,9 @@ export type DialogProps = {
|
|
|
36
37
|
focusFirstOnOpen?: boolean;
|
|
37
38
|
ariaLabel?: string;
|
|
38
39
|
ariaDescribedby?: string;
|
|
40
|
+
onOpen?: () => void;
|
|
41
|
+
/** Called after the close animation completes, with the reason it was closed. */
|
|
42
|
+
onClose?: (reason: CloseReason) => void;
|
|
39
43
|
};
|
|
40
44
|
declare const Dialog: import("svelte").Component<DialogProps, {
|
|
41
45
|
/** Opens the dialog. */ open: () => void;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* This prevents state synchronization bugs and ensures consistent behavior.
|
|
15
15
|
*/
|
|
16
16
|
import type { Snippet } from 'svelte';
|
|
17
|
+
import type { CloseReason } from '../types/propOptions';
|
|
17
18
|
import Modal from './Modal.svelte';
|
|
18
19
|
import { getStyleFromNumber } from '../utils/style';
|
|
19
20
|
|
|
@@ -58,6 +59,11 @@
|
|
|
58
59
|
// ARIA/アクセシビリティ
|
|
59
60
|
ariaLabel?: string;
|
|
60
61
|
ariaDescribedby?: string;
|
|
62
|
+
|
|
63
|
+
// イベントハンドラー
|
|
64
|
+
onOpen?: () => void;
|
|
65
|
+
/** Called after the close animation completes, with the reason it was closed. */
|
|
66
|
+
onClose?: (reason: CloseReason) => void;
|
|
61
67
|
};
|
|
62
68
|
|
|
63
69
|
let {
|
|
@@ -88,7 +94,11 @@
|
|
|
88
94
|
|
|
89
95
|
// ARIA/アクセシビリティ
|
|
90
96
|
ariaLabel = 'Drawer',
|
|
91
|
-
ariaDescribedby
|
|
97
|
+
ariaDescribedby,
|
|
98
|
+
|
|
99
|
+
// イベントハンドラー
|
|
100
|
+
onOpen = () => {}, // No params for type inference
|
|
101
|
+
onClose = () => {}
|
|
92
102
|
}: DrawerProps = $props();
|
|
93
103
|
|
|
94
104
|
let modalRef: Modal;
|
|
@@ -159,6 +169,8 @@
|
|
|
159
169
|
{closeIfClickOutside}
|
|
160
170
|
{restoreFocus}
|
|
161
171
|
{focusFirstOnOpen}
|
|
172
|
+
{onOpen}
|
|
173
|
+
{onClose}
|
|
162
174
|
componentType="Drawer"
|
|
163
175
|
{ariaLabel}
|
|
164
176
|
{ariaLabelledby}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* This prevents state synchronization bugs and ensures consistent behavior.
|
|
12
12
|
*/
|
|
13
13
|
import type { Snippet } from 'svelte';
|
|
14
|
+
import type { CloseReason } from '../types/propOptions';
|
|
14
15
|
export type DrawerProps = {
|
|
15
16
|
header?: Snippet;
|
|
16
17
|
children?: Snippet;
|
|
@@ -38,6 +39,9 @@ export type DrawerProps = {
|
|
|
38
39
|
focusFirstOnOpen?: boolean;
|
|
39
40
|
ariaLabel?: string;
|
|
40
41
|
ariaDescribedby?: string;
|
|
42
|
+
onOpen?: () => void;
|
|
43
|
+
/** Called after the close animation completes, with the reason it was closed. */
|
|
44
|
+
onClose?: (reason: CloseReason) => void;
|
|
41
45
|
};
|
|
42
46
|
declare const Drawer: import("svelte").Component<DrawerProps, {
|
|
43
47
|
/** Opens the drawer. */ open: () => void;
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* This prevents state synchronization bugs and ensures consistent behavior.
|
|
14
14
|
*/
|
|
15
15
|
import type { Snippet } from 'svelte';
|
|
16
|
+
import type { CloseReason } from '../types/propOptions';
|
|
16
17
|
import { announceOpenClose } from '../utils/accessibility';
|
|
17
18
|
|
|
18
19
|
// =========================================================================
|
|
@@ -47,6 +48,11 @@
|
|
|
47
48
|
ariaLabel?: string;
|
|
48
49
|
ariaLabelledby?: string;
|
|
49
50
|
ariaDescribedby?: string;
|
|
51
|
+
|
|
52
|
+
// イベントハンドラー
|
|
53
|
+
onOpen?: () => void;
|
|
54
|
+
/** Called after the close animation completes, with the reason it was closed. */
|
|
55
|
+
onClose?: (reason: CloseReason) => void;
|
|
50
56
|
};
|
|
51
57
|
|
|
52
58
|
let {
|
|
@@ -72,12 +78,19 @@
|
|
|
72
78
|
// ARIA/アクセシビリティ
|
|
73
79
|
ariaLabel,
|
|
74
80
|
ariaLabelledby,
|
|
75
|
-
ariaDescribedby
|
|
81
|
+
ariaDescribedby,
|
|
82
|
+
|
|
83
|
+
// イベントハンドラー
|
|
84
|
+
onOpen = () => {}, // No params for type inference
|
|
85
|
+
onClose = () => {}
|
|
76
86
|
}: ModalProps = $props();
|
|
77
87
|
|
|
78
88
|
let dialogRef: HTMLDialogElement;
|
|
79
89
|
let containerRef: HTMLDivElement;
|
|
80
90
|
let previousActiveElement: HTMLElement | null = null;
|
|
91
|
+
// isOpen は bind でも変わるため、実際に開いているかは内部で持つ
|
|
92
|
+
let isVisible = false;
|
|
93
|
+
let pendingCloseReason: CloseReason | null = null;
|
|
81
94
|
|
|
82
95
|
// =========================================================================
|
|
83
96
|
// Effects
|
|
@@ -89,7 +102,7 @@
|
|
|
89
102
|
if (!closeIfClickOutside) return;
|
|
90
103
|
if (!containerRef || !event.target) return;
|
|
91
104
|
if (!containerRef.contains(event.target as Node)) {
|
|
92
|
-
close();
|
|
105
|
+
close(undefined, 'outside');
|
|
93
106
|
}
|
|
94
107
|
};
|
|
95
108
|
|
|
@@ -110,7 +123,7 @@
|
|
|
110
123
|
// クローズは抑止し、fade-out アニメーション付きの close() を使う。
|
|
111
124
|
const handleCancel = (event: Event) => {
|
|
112
125
|
event.preventDefault();
|
|
113
|
-
close();
|
|
126
|
+
close(undefined, 'escape');
|
|
114
127
|
};
|
|
115
128
|
|
|
116
129
|
dialogRef.addEventListener('cancel', handleCancel);
|
|
@@ -172,11 +185,14 @@
|
|
|
172
185
|
// =========================================================================
|
|
173
186
|
/** Opens the modal. */
|
|
174
187
|
export const open = (title?: string): void => {
|
|
175
|
-
if (!dialogRef) return;
|
|
188
|
+
if (!dialogRef || isVisible) return;
|
|
176
189
|
|
|
190
|
+
isVisible = true;
|
|
177
191
|
isOpen = true;
|
|
178
192
|
previousActiveElement = document.activeElement as HTMLElement;
|
|
179
193
|
|
|
194
|
+
// 閉じるアニメーションの途中で開き直した場合は close を取り消す
|
|
195
|
+
pendingCloseReason = null;
|
|
180
196
|
dialogRef.classList.add('fade-in');
|
|
181
197
|
dialogRef.removeEventListener('animationend', closeEnd);
|
|
182
198
|
dialogRef.showModal();
|
|
@@ -186,14 +202,17 @@
|
|
|
186
202
|
dialogRef?.focus();
|
|
187
203
|
}
|
|
188
204
|
announceOpenClose(componentType, true, title || ariaLabel || '');
|
|
205
|
+
onOpen?.();
|
|
189
206
|
}, 0);
|
|
190
207
|
};
|
|
191
208
|
|
|
192
209
|
/** Closes the modal. */
|
|
193
|
-
export const close = (title?: string): void => {
|
|
194
|
-
if (!dialogRef) return;
|
|
210
|
+
export const close = (title?: string, reason: CloseReason = 'explicit'): void => {
|
|
211
|
+
if (!dialogRef || !isVisible) return;
|
|
195
212
|
|
|
213
|
+
isVisible = false;
|
|
196
214
|
isOpen = false;
|
|
215
|
+
pendingCloseReason = reason;
|
|
197
216
|
dialogRef.classList.add('fade-out');
|
|
198
217
|
dialogRef.addEventListener('animationend', closeEnd, { once: true });
|
|
199
218
|
|
|
@@ -211,11 +230,18 @@
|
|
|
211
230
|
previousActiveElement.focus();
|
|
212
231
|
}
|
|
213
232
|
previousActiveElement = null;
|
|
233
|
+
|
|
234
|
+
// アニメーション完了後に onClose を呼ぶ
|
|
235
|
+
if (pendingCloseReason) {
|
|
236
|
+
const reason = pendingCloseReason;
|
|
237
|
+
pendingCloseReason = null;
|
|
238
|
+
onClose?.(reason);
|
|
239
|
+
}
|
|
214
240
|
};
|
|
215
241
|
|
|
216
242
|
/** Toggles between open and closed. */
|
|
217
243
|
export const toggle = (title?: string): void => {
|
|
218
|
-
if (
|
|
244
|
+
if (isVisible) {
|
|
219
245
|
close(title);
|
|
220
246
|
} else {
|
|
221
247
|
open(title);
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* This prevents state synchronization bugs and ensures consistent behavior.
|
|
12
12
|
*/
|
|
13
13
|
import type { Snippet } from 'svelte';
|
|
14
|
+
import type { CloseReason } from '../types/propOptions';
|
|
14
15
|
export type ModalProps = {
|
|
15
16
|
children?: Snippet;
|
|
16
17
|
/** Internal label used for accessibility announcements. @default 'Modal' */
|
|
@@ -29,10 +30,13 @@ export type ModalProps = {
|
|
|
29
30
|
ariaLabel?: string;
|
|
30
31
|
ariaLabelledby?: string;
|
|
31
32
|
ariaDescribedby?: string;
|
|
33
|
+
onOpen?: () => void;
|
|
34
|
+
/** Called after the close animation completes, with the reason it was closed. */
|
|
35
|
+
onClose?: (reason: CloseReason) => void;
|
|
32
36
|
};
|
|
33
37
|
declare const Modal: import("svelte").Component<ModalProps, {
|
|
34
38
|
/** Opens the modal. */ open: (title?: string) => void;
|
|
35
|
-
/** Closes the modal. */ close: (title?: string) => void;
|
|
39
|
+
/** Closes the modal. */ close: (title?: string, reason?: CloseReason) => void;
|
|
36
40
|
/** @internal Completes the close animation. Called automatically. */ closeEnd: () => void;
|
|
37
41
|
/** Toggles between open and closed. */ toggle: (title?: string) => void;
|
|
38
42
|
}, "isOpen">;
|
package/dist/index.d.ts
CHANGED
|
@@ -85,7 +85,7 @@ export type { NavProps } from './components/Nav.svelte';
|
|
|
85
85
|
export type { NavItemProps, NavItemSelectedVariant } from './components/NavItem.svelte';
|
|
86
86
|
export type { TabProps } from './components/Tab.svelte';
|
|
87
87
|
export type { TextareaProps } from './components/Textarea.svelte';
|
|
88
|
-
export type { PopupPosition, SnackbarPosition, FabPosition, ButtonVariant, ButtonSize, IconPosition, ComponentSize, SnackbarType, SnackbarVariant, BadgeVariant, DatepickerMode, FocusStyle, NavVariant, ChildrenVariant, StepNavOrientation } from './types/propOptions';
|
|
88
|
+
export type { PopupPosition, SnackbarPosition, FabPosition, ButtonVariant, ButtonSize, IconPosition, ComponentSize, SnackbarType, SnackbarVariant, BadgeVariant, DatepickerMode, FocusStyle, NavVariant, ChildrenVariant, StepNavOrientation, CloseReason } from './types/propOptions';
|
|
89
89
|
export type { MenuItem } from './types/menuItem';
|
|
90
90
|
export type { StepItem } from './types/stepItem';
|
|
91
91
|
export type { SegmentedControlItem } from './types/segmentedControlItem';
|