|
1 |
| -<svelte:options runes={false} /> |
| 1 | +<svelte:options runes /> |
2 | 2 |
|
3 | 3 | <svelte:window
|
4 | 4 | onresize={() => open && instance && instance.layout()}
|
|
21 | 21 | })}
|
22 | 22 | role="alertdialog"
|
23 | 23 | aria-modal="true"
|
24 |
| - {...exclude($$restProps, ['container$', 'surface$'])} |
| 24 | + {...exclude(restProps, ['container$', 'surface$'])} |
25 | 25 | onSMUIDialogOpening={(e) => {
|
26 | 26 | handleDialogOpening();
|
27 |
| - $$restProps.onSMUIDialogOpening?.(e); |
| 27 | + restProps.onSMUIDialogOpening?.(e); |
28 | 28 | }}
|
29 | 29 | onSMUIDialogOpened={(e) => {
|
30 | 30 | handleDialogOpened();
|
31 |
| - $$restProps.onSMUIDialogOpened?.(e); |
| 31 | + restProps.onSMUIDialogOpened?.(e); |
32 | 32 | }}
|
33 | 33 | onSMUIDialogClosed={(e) => {
|
34 | 34 | handleDialogClosed();
|
35 |
| - $$restProps.onSMUIDialogClosed?.(e); |
| 35 | + restProps.onSMUIDialogClosed?.(e); |
36 | 36 | }}
|
37 | 37 | onclick={(e) => {
|
38 | 38 | if (instance) {
|
39 | 39 | instance.handleClick(e);
|
40 | 40 | }
|
41 |
| - $$restProps.onclick?.(e); |
| 41 | + restProps.onclick?.(e); |
42 | 42 | }}
|
43 | 43 | onkeydown={(e) => {
|
44 | 44 | if (instance) {
|
45 | 45 | instance.handleKeydown(e);
|
46 | 46 | }
|
47 |
| - $$restProps.onkeydown?.(e); |
| 47 | + restProps.onkeydown?.(e); |
48 | 48 | }}
|
49 | 49 | >
|
50 | 50 | <div
|
51 | 51 | class={classMap({
|
52 | 52 | [container$class]: true,
|
53 | 53 | 'mdc-dialog__container': true,
|
54 | 54 | })}
|
55 |
| - {...prefixFilter($$restProps, 'container$')} |
| 55 | + {...prefixFilter(restProps, 'container$')} |
56 | 56 | >
|
57 | 57 | <div
|
58 | 58 | class={classMap({
|
|
61 | 61 | })}
|
62 | 62 | role="alertdialog"
|
63 | 63 | aria-modal="true"
|
64 |
| - {...prefixFilter($$restProps, 'surface$')} |
| 64 | + {...prefixFilter(restProps, 'surface$')} |
65 | 65 | >
|
66 |
| - <slot /> |
| 66 | + {@render children?.()} |
67 | 67 | {#if fullscreen}
|
68 | 68 | <div
|
69 | 69 | class="mdc-dialog__surface-scrim"
|
|
76 | 76 | <div class="mdc-dialog__scrim"></div>
|
77 | 77 | </div>
|
78 | 78 |
|
79 |
| -<slot name="over" /> |
| 79 | +{@render over?.()} |
80 | 80 |
|
81 | 81 | <script lang="ts">
|
82 | 82 | import { MDCDialogFoundation, util } from '@material/dialog';
|
83 | 83 | import { focusTrap as domFocusTrap, ponyfill } from '@material/dom';
|
| 84 | + import type { Snippet } from 'svelte'; |
84 | 85 | import { onMount, onDestroy, getContext, setContext } from 'svelte';
|
85 | 86 | import type { Writable } from 'svelte/store';
|
86 | 87 | import { writable } from 'svelte/store';
|
|
103 | 104 | const { closest, matches } = ponyfill;
|
104 | 105 |
|
105 | 106 | type OwnProps = {
|
| 107 | + /** |
| 108 | + * An array of Action or [Action, ActionProps] to be applied to the element. |
| 109 | + */ |
106 | 110 | use?: ActionArray;
|
| 111 | + /** |
| 112 | + * A space separated list of CSS classes. |
| 113 | + */ |
107 | 114 | class?: string;
|
| 115 | + /** |
| 116 | + * Whether the dialog is open. |
| 117 | + */ |
108 | 118 | open?: boolean;
|
| 119 | + /** |
| 120 | + * Whether this is a selection dialog. |
| 121 | + */ |
109 | 122 | selection?: boolean;
|
| 123 | + /** |
| 124 | + * What action the escape key should trigger. |
| 125 | + * |
| 126 | + * Set to an empty string to not trigger an action or close the dialog. |
| 127 | + */ |
110 | 128 | escapeKeyAction?: string;
|
| 129 | + /** |
| 130 | + * What action clicking the scrim should trigger. |
| 131 | + * |
| 132 | + * Set to an empty string to not trigger an action or close the dialog. |
| 133 | + */ |
111 | 134 | scrimClickAction?: string;
|
| 135 | + /** |
| 136 | + * Automatically stack buttons that are too wide on mobile screens. |
| 137 | + */ |
112 | 138 | autoStackButtons?: boolean;
|
| 139 | + /** |
| 140 | + * Style as a full screen dialog on mobile screens. |
| 141 | + */ |
113 | 142 | fullscreen?: boolean;
|
114 | 143 | /**
|
| 144 | + * Style as a floating sheet. |
| 145 | + * |
115 | 146 | * Floating sheets are dialogs with a close icon button. Clicking the close
|
116 | 147 | * icon button closes the sheet. Having the close icon button is mutually
|
117 | 148 | * exclusive with having action bar buttons (e.g. cancel and OK buttons).
|
118 | 149 | * The icon button is absolutely positioned.
|
119 | 150 | */
|
120 | 151 | sheet?: boolean;
|
| 152 | + /** |
| 153 | + * Don't pad the content. |
| 154 | + */ |
121 | 155 | noContentPadding?: boolean;
|
| 156 | + /** |
| 157 | + * A space separated list of CSS classes. |
| 158 | + */ |
122 | 159 | container$class?: string;
|
| 160 | + /** |
| 161 | + * A space separated list of CSS classes. |
| 162 | + */ |
123 | 163 | surface$class?: string;
|
| 164 | +
|
| 165 | + children?: Snippet; |
| 166 | + /** |
| 167 | + * A spot to render another dialog over this one. |
| 168 | + * |
| 169 | + * According to the Material spec, you should only use this to put a choice |
| 170 | + * dialog over a fullscreen dialog. |
| 171 | + */ |
| 172 | + over?: Snippet; |
124 | 173 | };
|
125 |
| - type $$Props = OwnProps & |
| 174 | + let { |
| 175 | + use = [], |
| 176 | + class: className = '', |
| 177 | + open = $bindable(false), |
| 178 | + selection = false, |
| 179 | + escapeKeyAction = 'close', |
| 180 | + scrimClickAction = 'close', |
| 181 | + autoStackButtons = true, |
| 182 | + fullscreen = false, |
| 183 | + sheet = false, |
| 184 | + noContentPadding = false, |
| 185 | + container$class = '', |
| 186 | + surface$class = '', |
| 187 | + children, |
| 188 | + over, |
| 189 | + ...restProps |
| 190 | + }: OwnProps & |
126 | 191 | SmuiAttrs<'div', keyof OwnProps> & {
|
127 | 192 | [k in keyof SmuiElementPropMap['div'] as `container\$${k}`]?: SmuiElementPropMap['div'][k];
|
128 | 193 | } & {
|
129 | 194 | [k in keyof SmuiElementPropMap['div'] as `surface\$${k}`]?: SmuiElementPropMap['div'][k];
|
130 |
| - }; |
131 |
| -
|
132 |
| - // Remember to update $$Props if you add/remove/rename props. |
133 |
| - export let use: ActionArray = []; |
134 |
| - let className = ''; |
135 |
| - export { className as class }; |
136 |
| - export let open = false; |
137 |
| - export let selection = false; |
138 |
| - export let escapeKeyAction = 'close'; |
139 |
| - export let scrimClickAction = 'close'; |
140 |
| - export let autoStackButtons = true; |
141 |
| - export let fullscreen = false; |
142 |
| - export let sheet = false; |
143 |
| - export let noContentPadding = false; |
144 |
| - export let container$class = ''; |
145 |
| - export let surface$class = ''; |
| 195 | + } = $props(); |
146 | 196 |
|
147 | 197 | let element: HTMLDivElement;
|
148 |
| - let instance: MDCDialogFoundation; |
149 |
| - let internalClasses: { [k: string]: boolean } = {}; |
| 198 | + let instance: MDCDialogFoundation | undefined = $state(); |
| 199 | + let internalClasses: { [k: string]: boolean } = $state({}); |
150 | 200 | let focusTrap: domFocusTrap.FocusTrap;
|
151 | 201 | let actionButtonsReversed = writable(false);
|
152 | 202 | let aboveFullscreen = getContext<boolean | undefined>(
|
|
181 | 231 | setContext('SMUI:icon-button:context', 'dialog:sheet');
|
182 | 232 | }
|
183 | 233 |
|
184 |
| - $: if (instance && instance.getEscapeKeyAction() !== escapeKeyAction) { |
185 |
| - instance.setEscapeKeyAction(escapeKeyAction); |
186 |
| - } |
| 234 | + $effect(() => { |
| 235 | + if (instance && instance.getEscapeKeyAction() !== escapeKeyAction) { |
| 236 | + instance.setEscapeKeyAction(escapeKeyAction); |
| 237 | + } |
| 238 | + }); |
187 | 239 |
|
188 |
| - $: if (instance && instance.getScrimClickAction() !== scrimClickAction) { |
189 |
| - instance.setScrimClickAction(scrimClickAction); |
190 |
| - } |
| 240 | + $effect(() => { |
| 241 | + if (instance && instance.getScrimClickAction() !== scrimClickAction) { |
| 242 | + instance.setScrimClickAction(scrimClickAction); |
| 243 | + } |
| 244 | + }); |
191 | 245 |
|
192 |
| - $: if (instance && instance.getAutoStackButtons() !== autoStackButtons) { |
193 |
| - instance.setAutoStackButtons(autoStackButtons); |
194 |
| - } |
| 246 | + $effect(() => { |
| 247 | + if (instance && instance.getAutoStackButtons() !== autoStackButtons) { |
| 248 | + instance.setAutoStackButtons(autoStackButtons); |
| 249 | + } |
| 250 | + }); |
195 | 251 |
|
196 |
| - $: if (!autoStackButtons) { |
197 |
| - $actionButtonsReversed = true; |
198 |
| - } |
| 252 | + $effect(() => { |
| 253 | + if (!autoStackButtons) { |
| 254 | + $actionButtonsReversed = true; |
| 255 | + } |
| 256 | + }); |
199 | 257 |
|
200 | 258 | if (addLayoutListener) {
|
201 | 259 | removeLayoutListener = addLayoutListener(layout);
|
202 | 260 | }
|
203 | 261 |
|
204 |
| - $: if (instance && instance.isOpen() !== open) { |
205 |
| - if (open) { |
206 |
| - instance.open({ |
207 |
| - isAboveFullscreenDialog: !!aboveFullscreen, |
208 |
| - }); |
209 |
| - } else { |
210 |
| - instance.close(); |
| 262 | + $effect(() => { |
| 263 | + if (instance && instance.isOpen() !== open) { |
| 264 | + if (open) { |
| 265 | + instance.open({ |
| 266 | + isAboveFullscreenDialog: !!aboveFullscreen, |
| 267 | + }); |
| 268 | + } else { |
| 269 | + instance.close(); |
| 270 | + } |
211 | 271 | }
|
212 |
| - } |
| 272 | + }); |
213 | 273 |
|
214 | 274 | let previousAboveFullscreenShown = $aboveFullscreenShown;
|
215 |
| - $: if ( |
216 |
| - fullscreen && |
217 |
| - instance && |
218 |
| - previousAboveFullscreenShown !== $aboveFullscreenShown |
219 |
| - ) { |
220 |
| - previousAboveFullscreenShown = $aboveFullscreenShown; |
221 |
| - if ($aboveFullscreenShown) { |
222 |
| - instance.showSurfaceScrim(); |
223 |
| - } else { |
224 |
| - instance.hideSurfaceScrim(); |
| 275 | + $effect(() => { |
| 276 | + if ( |
| 277 | + fullscreen && |
| 278 | + instance && |
| 279 | + previousAboveFullscreenShown !== $aboveFullscreenShown |
| 280 | + ) { |
| 281 | + previousAboveFullscreenShown = $aboveFullscreenShown; |
| 282 | + if ($aboveFullscreenShown) { |
| 283 | + instance.showSurfaceScrim(); |
| 284 | + } else { |
| 285 | + instance.hideSurfaceScrim(); |
| 286 | + } |
225 | 287 | }
|
226 |
| - } |
| 288 | + }); |
227 | 289 |
|
228 | 290 | onMount(() => {
|
229 | 291 | focusTrap = new FocusTrap(element, {
|
|
299 | 361 | instance.init();
|
300 | 362 |
|
301 | 363 | return () => {
|
302 |
| - instance.destroy(); |
| 364 | + instance?.destroy(); |
303 | 365 | };
|
304 | 366 | });
|
305 | 367 |
|
|
377 | 439 | }
|
378 | 440 |
|
379 | 441 | export function layout() {
|
380 |
| - return instance.layout(); |
| 442 | + return instance?.layout(); |
381 | 443 | }
|
382 | 444 |
|
383 | 445 | export function getElement() {
|
|
0 commit comments