|
1 | 1 | <script lang="ts"> |
2 | | - import { fade, scale } from 'svelte/transition'; |
3 | | - import { cubicOut } from 'svelte/easing'; |
| 2 | + import { onDestroy } from 'svelte'; |
4 | 3 | import { confirmationStore, type ConfirmationOptions } from '$lib/stores/confirmation'; |
5 | 4 | import Icon from '$lib/components/icons/Icon.svelte'; |
| 5 | + import DialogShell from '$lib/components/dialogs/shared/DialogShell.svelte'; |
6 | 6 |
|
7 | 7 | let state = $state<{ |
8 | 8 | open: boolean; |
9 | 9 | options: ConfirmationOptions | null; |
10 | 10 | }>({ open: false, options: null }); |
11 | 11 |
|
12 | | - confirmationStore.subscribe((s) => { |
| 12 | + const unsubscribe = confirmationStore.subscribe((s) => { |
13 | 13 | state = { open: s.open, options: s.options }; |
14 | 14 | }); |
| 15 | + onDestroy(unsubscribe); |
15 | 16 |
|
16 | 17 | function handleConfirm() { |
17 | 18 | confirmationStore.confirm(); |
|
21 | 22 | confirmationStore.cancel(); |
22 | 23 | } |
23 | 24 |
|
24 | | - function handleBackdropClick(event: MouseEvent) { |
25 | | - if (event.target === event.currentTarget) { |
26 | | - handleCancel(); |
27 | | - } |
28 | | - } |
29 | | -
|
30 | | - function handleKeydown(event: KeyboardEvent) { |
31 | | - if (!state.open) return; |
32 | | - if (event.key === 'Escape') { |
33 | | - handleCancel(); |
34 | | - } else if (event.key === 'Enter') { |
| 25 | + function handleEnterKey(event: KeyboardEvent) { |
| 26 | + if (state.open && event.key === 'Enter') { |
35 | 27 | handleConfirm(); |
36 | 28 | } |
37 | 29 | } |
38 | 30 | </script> |
39 | 31 |
|
40 | | -<svelte:window onkeydown={handleKeydown} /> |
41 | | - |
42 | | -{#if state.open && state.options} |
43 | | - <div |
44 | | - class="dialog-backdrop" |
45 | | - onclick={handleBackdropClick} |
46 | | - transition:fade={{ duration: 150 }} |
47 | | - role="presentation" |
48 | | - > |
49 | | - <div |
50 | | - class="confirmation-dialog glass-panel" |
51 | | - transition:scale={{ start: 0.95, duration: 150, easing: cubicOut }} |
52 | | - role="alertdialog" |
53 | | - aria-modal="true" |
54 | | - aria-labelledby="confirmation-title" |
55 | | - aria-describedby="confirmation-message" |
56 | | - > |
57 | | - <div class="dialog-header"> |
58 | | - <span id="confirmation-title">{state.options.title}</span> |
59 | | - <button class="icon-btn" onclick={handleCancel} aria-label="Close"> |
60 | | - <Icon name="x" size={16} /> |
61 | | - </button> |
62 | | - </div> |
63 | | - |
64 | | - <div class="dialog-body"> |
65 | | - <p id="confirmation-message">{state.options.message}</p> |
66 | | - </div> |
67 | | - |
68 | | - <div class="dialog-actions"> |
69 | | - <button class="ghost" onclick={handleCancel}> |
70 | | - {state.options.cancelText} |
71 | | - </button> |
72 | | - <button onclick={handleConfirm}> |
73 | | - {state.options.confirmText} |
74 | | - </button> |
75 | | - </div> |
| 32 | +<svelte:window onkeydown={handleEnterKey} /> |
| 33 | + |
| 34 | +<DialogShell |
| 35 | + open={state.open && state.options !== null} |
| 36 | + onClose={handleCancel} |
| 37 | + ariaLabelledby="confirmation-title" |
| 38 | + role="alertdialog" |
| 39 | + dialogClass="confirmation-dialog glass-panel" |
| 40 | +> |
| 41 | + {#if state.options} |
| 42 | + <div class="dialog-header"> |
| 43 | + <span id="confirmation-title">{state.options.title}</span> |
| 44 | + <button class="icon-btn" onclick={handleCancel} aria-label="Close"> |
| 45 | + <Icon name="x" size={16} /> |
| 46 | + </button> |
| 47 | + </div> |
| 48 | + |
| 49 | + <div class="dialog-body"> |
| 50 | + <p id="confirmation-message">{state.options.message}</p> |
| 51 | + </div> |
| 52 | + |
| 53 | + <div class="dialog-actions"> |
| 54 | + <button class="ghost" onclick={handleCancel}> |
| 55 | + {state.options.cancelText} |
| 56 | + </button> |
| 57 | + <button onclick={handleConfirm}> |
| 58 | + {state.options.confirmText} |
| 59 | + </button> |
76 | 60 | </div> |
77 | | - </div> |
78 | | -{/if} |
| 61 | + {/if} |
| 62 | +</DialogShell> |
79 | 63 |
|
80 | 64 | <style> |
81 | | - .confirmation-dialog { |
| 65 | + :global(.confirmation-dialog) { |
82 | 66 | width: 90%; |
83 | 67 | max-width: 320px; |
84 | 68 | display: flex; |
|
0 commit comments