@finsweet/webflow-apps-utils 1.0.1 → 1.0.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 +162 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/providers/GlobalProvider.mdx +322 -0
- package/dist/providers/GlobalProvider.svelte +58 -0
- package/dist/providers/GlobalProvider.svelte.d.ts +4 -0
- package/dist/providers/configuratorUtils.d.ts +37 -0
- package/dist/providers/configuratorUtils.js +219 -0
- package/dist/providers/globalContext.svelte.d.ts +18 -0
- package/dist/providers/globalContext.svelte.js +439 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.js +7 -0
- package/dist/providers/types.d.ts +103 -0
- package/dist/providers/types.js +6 -0
- package/dist/router/README.md +2 -2
- package/dist/stores/index.d.ts +0 -1
- package/dist/stores/index.js +0 -1
- package/dist/types/webflow.d.ts +31 -47
- package/dist/ui/components/LoadingScreen.svelte +2 -1
- package/dist/ui/components/button/Button.svelte +4 -1
- package/dist/ui/components/button-group/ButtonGroup.stories.js +112 -0
- package/dist/ui/components/{ButtonGroup.svelte → button-group/ButtonGroup.svelte} +20 -33
- package/dist/ui/components/button-group/ButtonGroup.svelte.d.ts +13 -0
- package/dist/ui/components/button-group/index.d.ts +2 -0
- package/dist/ui/components/button-group/index.js +1 -0
- package/dist/ui/components/button-group/types.d.ts +32 -0
- package/dist/ui/components/checkbox/Checkbox.stories.d.ts +55 -0
- package/dist/ui/components/checkbox/Checkbox.stories.js +162 -0
- package/dist/ui/components/checkbox/Checkbox.svelte +141 -0
- package/dist/ui/components/checkbox/Checkbox.svelte.d.ts +4 -0
- package/dist/ui/components/checkbox/index.d.ts +2 -0
- package/dist/ui/components/checkbox/index.js +1 -0
- package/dist/ui/components/checkbox/types.d.ts +32 -0
- package/dist/ui/components/controlled-buttons/ControlledButtons.stories.d.ts +32 -0
- package/dist/ui/components/controlled-buttons/ControlledButtons.stories.js +152 -0
- package/dist/ui/components/{buttons/FooterButton.svelte → controlled-buttons/ControlledButtons.svelte} +18 -67
- package/dist/ui/components/controlled-buttons/ControlledButtons.svelte.d.ts +4 -0
- package/dist/ui/components/controlled-buttons/index.d.ts +2 -0
- package/dist/ui/components/controlled-buttons/index.js +1 -0
- package/dist/ui/components/{buttons → controlled-buttons}/types.d.ts +11 -4
- package/dist/ui/components/divider/Divider.stories.svelte +134 -0
- package/dist/ui/components/{clickable/Clickable.stories.svelte.d.ts → divider/Divider.stories.svelte.d.ts} +4 -4
- package/dist/ui/components/divider/Divider.svelte +30 -0
- package/dist/ui/components/divider/Divider.svelte.d.ts +4 -0
- package/dist/ui/components/divider/index.d.ts +2 -0
- package/dist/ui/components/divider/index.js +1 -0
- package/dist/ui/components/divider/types.d.ts +23 -0
- package/dist/ui/components/divider/types.js +1 -0
- package/dist/ui/components/iframe/Iframe.stories.svelte +122 -0
- package/dist/ui/components/{ToggleItem.svelte.d.ts → iframe/Iframe.stories.svelte.d.ts} +7 -8
- package/dist/ui/components/iframe/Iframe.svelte +75 -0
- package/dist/ui/components/iframe/Iframe.svelte.d.ts +4 -0
- package/dist/ui/components/iframe/index.d.ts +2 -0
- package/dist/ui/components/iframe/index.js +1 -0
- package/dist/ui/components/iframe/types.d.ts +38 -0
- package/dist/ui/components/iframe/types.js +1 -0
- package/dist/ui/components/index.d.ts +12 -39
- package/dist/ui/components/index.js +12 -39
- package/dist/ui/components/input/Input.stories.d.ts +24 -0
- package/dist/ui/components/input/Input.stories.js +98 -0
- package/dist/ui/components/input/Input.svelte +321 -80
- package/dist/ui/components/input/types.d.ts +27 -1
- package/dist/ui/components/layout/Layout.stories.svelte +3 -3
- package/dist/ui/components/layout/Layout.svelte +3 -5
- package/dist/ui/components/layout/common/EditModeMessage.svelte +24 -12
- package/dist/ui/components/layout/{ExampleLayout.svelte → examples/ExampleLayout.svelte} +34 -22
- package/dist/ui/components/layout/examples/Wrapper.svelte +9 -0
- package/dist/ui/components/{NoSettingsNeeded.svelte.d.ts → layout/examples/Wrapper.svelte.d.ts} +3 -3
- package/dist/ui/components/layout/examples/index.d.ts +2 -0
- package/dist/ui/components/layout/examples/index.js +2 -0
- package/dist/ui/components/layout/index.d.ts +2 -1
- package/dist/ui/components/layout/index.js +2 -1
- package/dist/ui/components/modal/Example.svelte +320 -0
- package/dist/ui/components/modal/Example.svelte.d.ts +3 -0
- package/dist/ui/components/modal/Modal.stories.svelte +18 -0
- package/dist/ui/components/modal/Modal.stories.svelte.d.ts +26 -0
- package/dist/ui/components/modal/Modal.svelte +490 -0
- package/dist/ui/components/modal/Modal.svelte.d.ts +130 -0
- package/dist/ui/components/modal/index.d.ts +2 -0
- package/dist/ui/components/modal/index.js +1 -0
- package/dist/ui/components/modal/types.d.ts +75 -0
- package/dist/ui/components/modal/types.js +1 -0
- package/dist/ui/components/notification/Notification.stories.svelte +228 -0
- package/dist/ui/components/{ToggleList.svelte.d.ts → notification/Notification.stories.svelte.d.ts} +9 -21
- package/dist/ui/components/notification/Notification.svelte +289 -0
- package/dist/ui/components/notification/Notification.svelte.d.ts +67 -0
- package/dist/ui/components/notification/index.d.ts +2 -0
- package/dist/ui/components/notification/index.js +1 -0
- package/dist/ui/components/notification/types.d.ts +68 -0
- package/dist/ui/components/notification/types.js +1 -0
- package/dist/ui/components/section/Section.stories.svelte +263 -0
- package/dist/ui/components/section/Section.stories.svelte.d.ts +27 -0
- package/dist/ui/components/section/Section.svelte +324 -0
- package/dist/ui/components/section/Section.svelte.d.ts +5 -0
- package/dist/ui/components/section/index.d.ts +2 -0
- package/dist/ui/components/section/index.js +1 -0
- package/dist/ui/components/section/types.d.ts +106 -0
- package/dist/ui/components/section/types.js +1 -0
- package/dist/ui/components/{ImageUpload.svelte → shared/ImageUpload.svelte} +3 -3
- package/dist/ui/components/{SelectBodyOrDivBlock.svelte → shared/SelectBodyOrDivBlock.svelte} +1 -1
- package/dist/ui/components/shared/index.d.ts +2 -0
- package/dist/ui/components/shared/index.js +2 -0
- package/dist/ui/icons/LineChartIcon.svelte +8 -0
- package/dist/ui/icons/LineChartIcon.svelte.d.ts +26 -0
- package/dist/ui/icons/index.d.ts +2 -1
- package/dist/ui/icons/index.js +2 -1
- package/dist/ui/index.css +33 -5
- package/dist/utils/api/checkIfAppModeIsDesign.d.ts +1 -2
- package/dist/utils/api/checkIfAppModeIsDesign.js +1 -2
- package/dist/utils/api/clipboard/handlePaste.d.ts +6 -37
- package/dist/utils/api/clipboard/handlePaste.js +2 -6
- package/dist/utils/api/getAllAssets.d.ts +1 -2
- package/dist/utils/api/getAllAssets.js +1 -2
- package/dist/utils/api/getFinsweetComponentsEnvironment.d.ts +1 -2
- package/dist/utils/api/getFinsweetComponentsEnvironment.js +3 -6
- package/dist/utils/api/index.d.ts +0 -1
- package/dist/utils/api/index.js +0 -1
- package/dist/utils/api/insertWithXSCP.d.ts +1 -2
- package/dist/utils/api/insertWithXSCP.js +1 -2
- package/dist/utils/auth/crossWindowLogin.d.ts +3 -0
- package/dist/utils/auth/crossWindowLogin.js +3 -0
- package/dist/utils/auth/index.d.ts +9 -25
- package/dist/utils/auth/index.js +9 -25
- package/dist/utils/browser-storage/localStorage.d.ts +4 -12
- package/dist/utils/browser-storage/localStorage.js +4 -12
- package/dist/utils/browser-storage/sessionStorage.d.ts +4 -12
- package/dist/utils/browser-storage/sessionStorage.js +4 -12
- package/dist/utils/custom-code/api.d.ts +3 -7
- package/dist/utils/custom-code/api.js +3 -7
- package/dist/utils/helpers/cleanupTooltipMessage.d.ts +1 -2
- package/dist/utils/helpers/cleanupTooltipMessage.js +1 -2
- package/dist/utils/helpers/goto.d.ts +1 -4
- package/dist/utils/helpers/goto.js +2 -7
- package/dist/utils/helpers/index.d.ts +1 -0
- package/dist/utils/helpers/index.js +1 -0
- package/dist/utils/helpers/noop.d.ts +1 -1
- package/dist/utils/helpers/noop.js +1 -1
- package/dist/utils/helpers/numbers.d.ts +4 -14
- package/dist/utils/helpers/numbers.js +4 -14
- package/dist/utils/helpers/objectsToModuleExports.d.ts +1 -3
- package/dist/utils/helpers/objectsToModuleExports.js +1 -3
- package/dist/utils/helpers/trimText.d.ts +1 -8
- package/dist/utils/helpers/trimText.js +1 -8
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/logger/index.d.ts +0 -2
- package/dist/utils/logger/index.js +0 -2
- package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.d.ts +1 -3
- package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.js +1 -3
- package/dist/utils/webflow-canvas/attributes/getInstanceNamesFromObject.d.ts +1 -5
- package/dist/utils/webflow-canvas/attributes/getInstanceNamesFromObject.js +1 -5
- package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.d.ts +1 -4
- package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.js +1 -4
- package/dist/utils/webflow-canvas/attributes/getWebflowElementTextContent.d.ts +1 -3
- package/dist/utils/webflow-canvas/attributes/getWebflowElementTextContent.js +1 -3
- package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.d.ts +1 -4
- package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.js +1 -4
- package/dist/utils/webflow-canvas/attributes/setStyles.d.ts +1 -3
- package/dist/utils/webflow-canvas/attributes/setStyles.js +1 -3
- package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.d.ts +1 -8
- package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.js +1 -13
- package/dist/utils/webflow-canvas/findInstanceElement.d.ts +0 -6
- package/dist/utils/webflow-canvas/findInstanceElement.js +1 -7
- package/dist/utils/webflow-canvas/getAllPages.d.ts +3 -10
- package/dist/utils/webflow-canvas/getAllPages.js +3 -10
- package/dist/utils/webflow-canvas/getSiteStagingUrl.d.ts +1 -4
- package/dist/utils/webflow-canvas/getSiteStagingUrl.js +1 -4
- package/dist/utils/webflow-canvas/index.d.ts +1 -0
- package/dist/utils/webflow-canvas/index.js +1 -0
- package/package.json +9 -2
- package/dist/stores/globalStore.d.ts +0 -10
- package/dist/stores/globalStore.js +0 -10
- package/dist/ui/components/ButtonGroup.svelte.d.ts +0 -28
- package/dist/ui/components/Checkbox.svelte +0 -94
- package/dist/ui/components/Checkbox.svelte.d.ts +0 -36
- package/dist/ui/components/Copy.svelte +0 -329
- package/dist/ui/components/Copy.svelte.d.ts +0 -35
- package/dist/ui/components/CustomModal.svelte +0 -192
- package/dist/ui/components/CustomModal.svelte.d.ts +0 -45
- package/dist/ui/components/DisableInEditMode.svelte +0 -66
- package/dist/ui/components/DisableInEditMode.svelte.d.ts +0 -33
- package/dist/ui/components/Divider.svelte +0 -31
- package/dist/ui/components/Divider.svelte.d.ts +0 -31
- package/dist/ui/components/Header.svelte +0 -30
- package/dist/ui/components/Header.svelte.d.ts +0 -20
- package/dist/ui/components/Iframe.svelte +0 -89
- package/dist/ui/components/Iframe.svelte.d.ts +0 -40
- package/dist/ui/components/InjectComponent.svelte +0 -297
- package/dist/ui/components/InjectComponent.svelte.d.ts +0 -27
- package/dist/ui/components/Modal.svelte +0 -139
- package/dist/ui/components/Modal.svelte.d.ts +0 -42
- package/dist/ui/components/Navbar.svelte +0 -132
- package/dist/ui/components/Navbar.svelte.d.ts +0 -29
- package/dist/ui/components/NoSettingsNeeded.svelte +0 -31
- package/dist/ui/components/Notification.svelte +0 -193
- package/dist/ui/components/Notification.svelte.d.ts +0 -64
- package/dist/ui/components/PlusMinusButton.svelte +0 -91
- package/dist/ui/components/PlusMinusButton.svelte.d.ts +0 -22
- package/dist/ui/components/PreviewBar.svelte +0 -40
- package/dist/ui/components/PreviewBar.svelte.d.ts +0 -20
- package/dist/ui/components/ScrollableContent.svelte +0 -18
- package/dist/ui/components/ScrollableContent.svelte.d.ts +0 -31
- package/dist/ui/components/Section.svelte +0 -97
- package/dist/ui/components/Section.svelte.d.ts +0 -50
- package/dist/ui/components/Spacer.svelte +0 -9
- package/dist/ui/components/Spacer.svelte.d.ts +0 -22
- package/dist/ui/components/SpinnerPlusMinus.svelte +0 -75
- package/dist/ui/components/SpinnerPlusMinus.svelte.d.ts +0 -23
- package/dist/ui/components/SpinnerUpDown.svelte +0 -194
- package/dist/ui/components/SpinnerUpDown.svelte.d.ts +0 -31
- package/dist/ui/components/Tabs.svelte +0 -71
- package/dist/ui/components/Tabs.svelte.d.ts +0 -26
- package/dist/ui/components/ToggleItem.svelte +0 -29
- package/dist/ui/components/ToggleList.svelte +0 -57
- package/dist/ui/components/buttons/FooterButton.svelte.d.ts +0 -10
- package/dist/ui/components/buttons/index.d.ts +0 -5
- package/dist/ui/components/buttons/index.js +0 -5
- package/dist/ui/components/clickable/Clickable.stories.svelte +0 -213
- package/dist/ui/components/clickable/Clickable.svelte +0 -93
- package/dist/ui/components/clickable/Clickable.svelte.d.ts +0 -4
- package/dist/ui/components/clickable/index.d.ts +0 -2
- package/dist/ui/components/clickable/index.js +0 -1
- package/dist/ui/components/clickable/types.d.ts +0 -17
- package/dist/utils/api/copyPaste/index.d.ts +0 -18
- /package/dist/ui/components/{buttons → button-group}/types.js +0 -0
- /package/dist/ui/components/{clickable → checkbox}/types.js +0 -0
- /package/dist/{utils/api/copyPaste/index.js → ui/components/controlled-buttons/types.js} +0 -0
- /package/dist/ui/components/layout/{ExampleLayout.svelte.d.ts → examples/ExampleLayout.svelte.d.ts} +0 -0
- /package/dist/ui/components/{ImageUpload.svelte.d.ts → shared/ImageUpload.svelte.d.ts} +0 -0
- /package/dist/ui/components/{SelectBodyOrDivBlock.svelte.d.ts → shared/SelectBodyOrDivBlock.svelte.d.ts} +0 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Component, Snippet } from 'svelte';
|
|
3
|
+
import { onMount, tick } from 'svelte';
|
|
4
|
+
|
|
5
|
+
import { CloseIcon } from '../../icons';
|
|
6
|
+
import { Button, LoadingScreen, Text } from '../';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
/**
|
|
10
|
+
* Whether the modal is open/visible
|
|
11
|
+
*/
|
|
12
|
+
open?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Whether to show the header bar
|
|
15
|
+
*/
|
|
16
|
+
showHeader?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whether to show the footer bar
|
|
19
|
+
*/
|
|
20
|
+
showFooter?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether to show the close button in header
|
|
23
|
+
*/
|
|
24
|
+
showCloseButton?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Whether the modal can be closed by clicking overlay
|
|
27
|
+
*/
|
|
28
|
+
closeOnOverlayClick?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Whether the modal can be closed by pressing Escape key
|
|
31
|
+
*/
|
|
32
|
+
closeOnEscape?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the modal is in loading state
|
|
35
|
+
*/
|
|
36
|
+
loading?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Loading message to display
|
|
39
|
+
*/
|
|
40
|
+
loadingMessage?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Global padding for modal content
|
|
43
|
+
*/
|
|
44
|
+
padding?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Specific padding for header section
|
|
47
|
+
*/
|
|
48
|
+
headerPadding?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Specific padding for content section
|
|
51
|
+
*/
|
|
52
|
+
contentPadding?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Specific padding for footer section
|
|
55
|
+
*/
|
|
56
|
+
footerPadding?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Custom width for modal
|
|
59
|
+
*/
|
|
60
|
+
width?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Custom height for modal
|
|
63
|
+
*/
|
|
64
|
+
height?: string;
|
|
65
|
+
/**
|
|
66
|
+
* CSS position property for the modal overlay
|
|
67
|
+
*/
|
|
68
|
+
position?: 'fixed' | 'absolute';
|
|
69
|
+
/**
|
|
70
|
+
* Additional CSS classes
|
|
71
|
+
*/
|
|
72
|
+
class?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Custom styles
|
|
75
|
+
*/
|
|
76
|
+
style?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Z-index for the modal
|
|
79
|
+
*/
|
|
80
|
+
zIndex?: number;
|
|
81
|
+
/**
|
|
82
|
+
* Background color for overlay
|
|
83
|
+
*/
|
|
84
|
+
overlayColor?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Default header title text
|
|
87
|
+
*/
|
|
88
|
+
title?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Default action button text
|
|
91
|
+
*/
|
|
92
|
+
actionText?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Default cancel button text
|
|
95
|
+
*/
|
|
96
|
+
cancelText?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Header content snippet
|
|
99
|
+
*/
|
|
100
|
+
header?: Snippet;
|
|
101
|
+
/**
|
|
102
|
+
* Main content snippet
|
|
103
|
+
*/
|
|
104
|
+
children?: Snippet;
|
|
105
|
+
/**
|
|
106
|
+
* Footer content snippet
|
|
107
|
+
*/
|
|
108
|
+
footer?: Snippet;
|
|
109
|
+
/**
|
|
110
|
+
* Custom close button icon
|
|
111
|
+
*/
|
|
112
|
+
closeIcon?: Component;
|
|
113
|
+
/**
|
|
114
|
+
* Event handler for when modal requests to close
|
|
115
|
+
*/
|
|
116
|
+
onOpenChange?: (open: boolean) => void;
|
|
117
|
+
/**
|
|
118
|
+
* Event handler for overlay click
|
|
119
|
+
*/
|
|
120
|
+
onOverlayClick?: () => void;
|
|
121
|
+
/**
|
|
122
|
+
* Event handler for escape key press
|
|
123
|
+
*/
|
|
124
|
+
onEscapeKeyDown?: () => void;
|
|
125
|
+
/**
|
|
126
|
+
* Event handler for default action button click
|
|
127
|
+
*/
|
|
128
|
+
onAction?: () => void;
|
|
129
|
+
/**
|
|
130
|
+
* Event handler for default cancel button click
|
|
131
|
+
*/
|
|
132
|
+
onCancel?: () => void;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let {
|
|
136
|
+
open = false,
|
|
137
|
+
showHeader = true,
|
|
138
|
+
showFooter = true,
|
|
139
|
+
showCloseButton = true,
|
|
140
|
+
closeOnOverlayClick = true,
|
|
141
|
+
closeOnEscape = true,
|
|
142
|
+
loading = false,
|
|
143
|
+
loadingMessage = 'Loading content...',
|
|
144
|
+
padding = '8px 12px',
|
|
145
|
+
headerPadding,
|
|
146
|
+
contentPadding,
|
|
147
|
+
footerPadding,
|
|
148
|
+
width = '28em',
|
|
149
|
+
height = 'auto',
|
|
150
|
+
position = 'fixed',
|
|
151
|
+
class: className = '',
|
|
152
|
+
style: customStyle = '',
|
|
153
|
+
zIndex = 99999999997,
|
|
154
|
+
overlayColor = 'rgba(0, 0, 0, 0.4)',
|
|
155
|
+
title = 'Modal',
|
|
156
|
+
actionText = 'Action',
|
|
157
|
+
cancelText = 'Cancel',
|
|
158
|
+
header,
|
|
159
|
+
children,
|
|
160
|
+
footer,
|
|
161
|
+
closeIcon = CloseIcon,
|
|
162
|
+
onOpenChange,
|
|
163
|
+
onOverlayClick,
|
|
164
|
+
onEscapeKeyDown,
|
|
165
|
+
onAction,
|
|
166
|
+
onCancel,
|
|
167
|
+
...restProps
|
|
168
|
+
}: Props = $props();
|
|
169
|
+
|
|
170
|
+
// Component state
|
|
171
|
+
let modalElement = $state<HTMLElement>();
|
|
172
|
+
let overlayElement = $state<HTMLElement>();
|
|
173
|
+
let closeButtonElement = $state<HTMLButtonElement>();
|
|
174
|
+
let previouslyFocusedElement = $state<HTMLElement>();
|
|
175
|
+
|
|
176
|
+
// Track if modal was opened in this render cycle
|
|
177
|
+
let previousOpen = $state(open);
|
|
178
|
+
|
|
179
|
+
// Icon component binding
|
|
180
|
+
let CloseIconComponent = $derived(closeIcon);
|
|
181
|
+
|
|
182
|
+
// Computed CSS classes
|
|
183
|
+
let overlayClasses = $derived.by(() => {
|
|
184
|
+
const classes = ['modal-overlay'];
|
|
185
|
+
if (!closeOnOverlayClick) classes.push('prevent-overlay-close');
|
|
186
|
+
if (className) classes.push(className);
|
|
187
|
+
return classes.join(' ');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Computed CSS styles for modal container
|
|
191
|
+
let modalStyles = $derived.by(() => {
|
|
192
|
+
const styles = [`width: ${width}`, `height: ${height}`];
|
|
193
|
+
if (customStyle) styles.push(customStyle);
|
|
194
|
+
return styles.join('; ');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Computed padding styles for each section
|
|
198
|
+
let headerStyles = $derived(`padding: ${headerPadding || padding}`);
|
|
199
|
+
let contentStyles = $derived(`padding: ${contentPadding || padding}`);
|
|
200
|
+
let footerStyles = $derived(`padding: ${footerPadding || padding}`);
|
|
201
|
+
|
|
202
|
+
// Computed overlay styles
|
|
203
|
+
let overlayStyles = $derived.by(() => {
|
|
204
|
+
const styles = [`position: ${position}`, `background: ${overlayColor}`, `z-index: ${zIndex}`];
|
|
205
|
+
return styles.join('; ');
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Focus management - Store the previously focused element when modal opens
|
|
209
|
+
$effect(() => {
|
|
210
|
+
if (open && !previousOpen) {
|
|
211
|
+
// Modal is opening
|
|
212
|
+
previouslyFocusedElement = document.activeElement as HTMLElement;
|
|
213
|
+
} else if (!open && previousOpen) {
|
|
214
|
+
// Modal is closing
|
|
215
|
+
if (previouslyFocusedElement) {
|
|
216
|
+
tick().then(() => {
|
|
217
|
+
previouslyFocusedElement?.focus();
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
previousOpen = open;
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Body scroll lock effect
|
|
225
|
+
$effect(() => {
|
|
226
|
+
if (open) {
|
|
227
|
+
document.body.style.overflow = 'hidden';
|
|
228
|
+
} else {
|
|
229
|
+
document.body.style.overflow = '';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Cleanup when component unmounts
|
|
233
|
+
return () => {
|
|
234
|
+
document.body.style.overflow = '';
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Focus the close button when modal opens
|
|
239
|
+
onMount(async () => {
|
|
240
|
+
if (open) {
|
|
241
|
+
await tick();
|
|
242
|
+
closeButtonElement?.focus();
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Watch for open changes and focus management
|
|
247
|
+
$effect(() => {
|
|
248
|
+
if (open && closeButtonElement) {
|
|
249
|
+
tick().then(() => {
|
|
250
|
+
closeButtonElement?.focus();
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Close the modal
|
|
257
|
+
*/
|
|
258
|
+
function closeModal() {
|
|
259
|
+
onOpenChange?.(false);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Handle overlay click
|
|
264
|
+
*/
|
|
265
|
+
function handleOverlayClick() {
|
|
266
|
+
onOverlayClick?.();
|
|
267
|
+
|
|
268
|
+
if (closeOnOverlayClick) {
|
|
269
|
+
closeModal();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Handle escape key press
|
|
275
|
+
*/
|
|
276
|
+
function handleEscapeKey() {
|
|
277
|
+
onEscapeKeyDown?.();
|
|
278
|
+
|
|
279
|
+
if (closeOnEscape) {
|
|
280
|
+
closeModal();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Handle keydown events for modal
|
|
286
|
+
*/
|
|
287
|
+
function handleKeyDown(event: KeyboardEvent) {
|
|
288
|
+
if (event.key === 'Escape') {
|
|
289
|
+
event.preventDefault();
|
|
290
|
+
handleEscapeKey();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Focus trap implementation
|
|
296
|
+
*/
|
|
297
|
+
function trapFocus(event: KeyboardEvent) {
|
|
298
|
+
if (!modalElement || event.key !== 'Tab') return;
|
|
299
|
+
|
|
300
|
+
const focusableElements = modalElement.querySelectorAll(
|
|
301
|
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
302
|
+
) as NodeListOf<HTMLElement>;
|
|
303
|
+
|
|
304
|
+
const firstElement = focusableElements[0];
|
|
305
|
+
const lastElement = focusableElements[focusableElements.length - 1];
|
|
306
|
+
|
|
307
|
+
if (event.shiftKey) {
|
|
308
|
+
// Shift + Tab
|
|
309
|
+
if (document.activeElement === firstElement) {
|
|
310
|
+
event.preventDefault();
|
|
311
|
+
lastElement?.focus();
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
// Tab
|
|
315
|
+
if (document.activeElement === lastElement) {
|
|
316
|
+
event.preventDefault();
|
|
317
|
+
firstElement?.focus();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
</script>
|
|
322
|
+
|
|
323
|
+
{#if open}
|
|
324
|
+
<div
|
|
325
|
+
class={overlayClasses}
|
|
326
|
+
bind:this={overlayElement}
|
|
327
|
+
style={overlayStyles}
|
|
328
|
+
onclick={handleOverlayClick}
|
|
329
|
+
onkeydown={handleKeyDown}
|
|
330
|
+
tabindex="-1"
|
|
331
|
+
role="dialog"
|
|
332
|
+
aria-modal="true"
|
|
333
|
+
aria-labelledby={showHeader ? 'modal-header' : undefined}
|
|
334
|
+
{...restProps}
|
|
335
|
+
>
|
|
336
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
337
|
+
<div
|
|
338
|
+
class="modal-content"
|
|
339
|
+
bind:this={modalElement}
|
|
340
|
+
style={modalStyles}
|
|
341
|
+
onclick={(e) => e.stopPropagation()}
|
|
342
|
+
onkeydown={trapFocus}
|
|
343
|
+
role="document"
|
|
344
|
+
>
|
|
345
|
+
{#if loading}
|
|
346
|
+
<LoadingScreen
|
|
347
|
+
message={loadingMessage}
|
|
348
|
+
active={true}
|
|
349
|
+
spinnerSize={20}
|
|
350
|
+
position="absolute"
|
|
351
|
+
/>
|
|
352
|
+
{/if}
|
|
353
|
+
|
|
354
|
+
{#if showHeader}
|
|
355
|
+
<div class="header-bar" id="modal-header" style={headerStyles}>
|
|
356
|
+
{#if header}
|
|
357
|
+
{@render header()}
|
|
358
|
+
{:else}
|
|
359
|
+
<Text label={title} fontWeight="600" />
|
|
360
|
+
{/if}
|
|
361
|
+
|
|
362
|
+
{#if showCloseButton}
|
|
363
|
+
<button
|
|
364
|
+
bind:this={closeButtonElement}
|
|
365
|
+
onclick={closeModal}
|
|
366
|
+
aria-label="Close modal"
|
|
367
|
+
type="button"
|
|
368
|
+
>
|
|
369
|
+
<CloseIconComponent />
|
|
370
|
+
</button>
|
|
371
|
+
{/if}
|
|
372
|
+
</div>
|
|
373
|
+
{/if}
|
|
374
|
+
|
|
375
|
+
<div class="modal-body" style={contentStyles}>
|
|
376
|
+
{#if children}
|
|
377
|
+
{@render children()}
|
|
378
|
+
{/if}
|
|
379
|
+
</div>
|
|
380
|
+
|
|
381
|
+
{#if showFooter}
|
|
382
|
+
<div class="modal-footer" style={footerStyles}>
|
|
383
|
+
{#if footer}
|
|
384
|
+
{@render footer()}
|
|
385
|
+
{:else}
|
|
386
|
+
<div class="footer-buttons">
|
|
387
|
+
<Button variant="secondary" onclick={onCancel}>{cancelText}</Button>
|
|
388
|
+
<Button variant="primary" onclick={onAction}>{actionText}</Button>
|
|
389
|
+
</div>
|
|
390
|
+
{/if}
|
|
391
|
+
</div>
|
|
392
|
+
{/if}
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
{/if}
|
|
396
|
+
|
|
397
|
+
<style>
|
|
398
|
+
.modal-overlay {
|
|
399
|
+
top: 0;
|
|
400
|
+
left: 0;
|
|
401
|
+
width: 100vw;
|
|
402
|
+
height: 100vh;
|
|
403
|
+
display: flex;
|
|
404
|
+
align-items: center;
|
|
405
|
+
justify-content: center;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.modal-content {
|
|
409
|
+
border-radius: var(--border-radius);
|
|
410
|
+
background: var(--background1);
|
|
411
|
+
color: var(--text1);
|
|
412
|
+
animation: zoom 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
413
|
+
position: relative;
|
|
414
|
+
display: flex;
|
|
415
|
+
flex-direction: column;
|
|
416
|
+
min-height: 0;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
@keyframes zoom {
|
|
420
|
+
from {
|
|
421
|
+
transform: scale(0.95);
|
|
422
|
+
}
|
|
423
|
+
to {
|
|
424
|
+
transform: scale(1);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
@keyframes fade {
|
|
429
|
+
from {
|
|
430
|
+
opacity: 0;
|
|
431
|
+
}
|
|
432
|
+
to {
|
|
433
|
+
opacity: 1;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
button {
|
|
438
|
+
border: none;
|
|
439
|
+
user-select: none;
|
|
440
|
+
width: 24px;
|
|
441
|
+
padding: 0px 4px;
|
|
442
|
+
font-family: inherit;
|
|
443
|
+
font-size: inherit;
|
|
444
|
+
position: relative;
|
|
445
|
+
display: flex;
|
|
446
|
+
align-items: center;
|
|
447
|
+
justify-content: center;
|
|
448
|
+
height: 24px;
|
|
449
|
+
border-radius: 4px;
|
|
450
|
+
color: rgb(171, 171, 171);
|
|
451
|
+
background: transparent;
|
|
452
|
+
box-sizing: border-box;
|
|
453
|
+
box-shadow: none;
|
|
454
|
+
align-self: center;
|
|
455
|
+
cursor: pointer;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
button:hover {
|
|
459
|
+
filter: brightness(1.1);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.header-bar {
|
|
463
|
+
display: flex;
|
|
464
|
+
align-items: center;
|
|
465
|
+
justify-content: space-between;
|
|
466
|
+
border-bottom: 1px solid var(--border1);
|
|
467
|
+
gap: 4px;
|
|
468
|
+
width: 100%;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.prevent-overlay-close {
|
|
472
|
+
cursor: progress;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.modal-body {
|
|
476
|
+
flex: 1;
|
|
477
|
+
min-height: 0;
|
|
478
|
+
overflow: auto;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.modal-footer {
|
|
482
|
+
border-top: 1px solid var(--border1);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.footer-buttons {
|
|
486
|
+
display: flex;
|
|
487
|
+
gap: 8px;
|
|
488
|
+
justify-content: flex-end;
|
|
489
|
+
}
|
|
490
|
+
</style>
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { Component, Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the modal is open/visible
|
|
5
|
+
*/
|
|
6
|
+
open?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Whether to show the header bar
|
|
9
|
+
*/
|
|
10
|
+
showHeader?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Whether to show the footer bar
|
|
13
|
+
*/
|
|
14
|
+
showFooter?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Whether to show the close button in header
|
|
17
|
+
*/
|
|
18
|
+
showCloseButton?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Whether the modal can be closed by clicking overlay
|
|
21
|
+
*/
|
|
22
|
+
closeOnOverlayClick?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Whether the modal can be closed by pressing Escape key
|
|
25
|
+
*/
|
|
26
|
+
closeOnEscape?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the modal is in loading state
|
|
29
|
+
*/
|
|
30
|
+
loading?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Loading message to display
|
|
33
|
+
*/
|
|
34
|
+
loadingMessage?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Global padding for modal content
|
|
37
|
+
*/
|
|
38
|
+
padding?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Specific padding for header section
|
|
41
|
+
*/
|
|
42
|
+
headerPadding?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Specific padding for content section
|
|
45
|
+
*/
|
|
46
|
+
contentPadding?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Specific padding for footer section
|
|
49
|
+
*/
|
|
50
|
+
footerPadding?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Custom width for modal
|
|
53
|
+
*/
|
|
54
|
+
width?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Custom height for modal
|
|
57
|
+
*/
|
|
58
|
+
height?: string;
|
|
59
|
+
/**
|
|
60
|
+
* CSS position property for the modal overlay
|
|
61
|
+
*/
|
|
62
|
+
position?: 'fixed' | 'absolute';
|
|
63
|
+
/**
|
|
64
|
+
* Additional CSS classes
|
|
65
|
+
*/
|
|
66
|
+
class?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Custom styles
|
|
69
|
+
*/
|
|
70
|
+
style?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Z-index for the modal
|
|
73
|
+
*/
|
|
74
|
+
zIndex?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Background color for overlay
|
|
77
|
+
*/
|
|
78
|
+
overlayColor?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Default header title text
|
|
81
|
+
*/
|
|
82
|
+
title?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Default action button text
|
|
85
|
+
*/
|
|
86
|
+
actionText?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Default cancel button text
|
|
89
|
+
*/
|
|
90
|
+
cancelText?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Header content snippet
|
|
93
|
+
*/
|
|
94
|
+
header?: Snippet;
|
|
95
|
+
/**
|
|
96
|
+
* Main content snippet
|
|
97
|
+
*/
|
|
98
|
+
children?: Snippet;
|
|
99
|
+
/**
|
|
100
|
+
* Footer content snippet
|
|
101
|
+
*/
|
|
102
|
+
footer?: Snippet;
|
|
103
|
+
/**
|
|
104
|
+
* Custom close button icon
|
|
105
|
+
*/
|
|
106
|
+
closeIcon?: Component;
|
|
107
|
+
/**
|
|
108
|
+
* Event handler for when modal requests to close
|
|
109
|
+
*/
|
|
110
|
+
onOpenChange?: (open: boolean) => void;
|
|
111
|
+
/**
|
|
112
|
+
* Event handler for overlay click
|
|
113
|
+
*/
|
|
114
|
+
onOverlayClick?: () => void;
|
|
115
|
+
/**
|
|
116
|
+
* Event handler for escape key press
|
|
117
|
+
*/
|
|
118
|
+
onEscapeKeyDown?: () => void;
|
|
119
|
+
/**
|
|
120
|
+
* Event handler for default action button click
|
|
121
|
+
*/
|
|
122
|
+
onAction?: () => void;
|
|
123
|
+
/**
|
|
124
|
+
* Event handler for default cancel button click
|
|
125
|
+
*/
|
|
126
|
+
onCancel?: () => void;
|
|
127
|
+
}
|
|
128
|
+
declare const Modal: Component<Props, {}, "">;
|
|
129
|
+
type Modal = ReturnType<typeof Modal>;
|
|
130
|
+
export default Modal;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Modal } from './Modal.svelte';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Component, Snippet } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* Modal component props interface
|
|
4
|
+
*/
|
|
5
|
+
export interface ModalProps {
|
|
6
|
+
/** Whether the modal is open/visible */
|
|
7
|
+
open?: boolean;
|
|
8
|
+
/** Whether to show the header bar */
|
|
9
|
+
showHeader?: boolean;
|
|
10
|
+
/** Whether to show the footer bar */
|
|
11
|
+
showFooter?: boolean;
|
|
12
|
+
/** Whether to show the close button in header */
|
|
13
|
+
showCloseButton?: boolean;
|
|
14
|
+
/** Whether the modal can be closed by clicking overlay */
|
|
15
|
+
closeOnOverlayClick?: boolean;
|
|
16
|
+
/** Whether the modal can be closed by pressing Escape key */
|
|
17
|
+
closeOnEscape?: boolean;
|
|
18
|
+
/** Whether the modal is in loading state */
|
|
19
|
+
loading?: boolean;
|
|
20
|
+
/** Loading message to display */
|
|
21
|
+
loadingMessage?: string;
|
|
22
|
+
/** Global padding for modal content (fallback for individual sections) */
|
|
23
|
+
padding?: string;
|
|
24
|
+
/** Specific padding for header section */
|
|
25
|
+
headerPadding?: string;
|
|
26
|
+
/** Specific padding for content section */
|
|
27
|
+
contentPadding?: string;
|
|
28
|
+
/** Specific padding for footer section */
|
|
29
|
+
footerPadding?: string;
|
|
30
|
+
/** Custom width for modal */
|
|
31
|
+
width?: string;
|
|
32
|
+
/** Custom height for modal */
|
|
33
|
+
height?: string;
|
|
34
|
+
/** CSS position property for the modal overlay */
|
|
35
|
+
position?: 'fixed' | 'absolute';
|
|
36
|
+
/** Additional CSS classes */
|
|
37
|
+
class?: string;
|
|
38
|
+
/** Custom styles */
|
|
39
|
+
style?: string;
|
|
40
|
+
/** Z-index for the modal */
|
|
41
|
+
zIndex?: number;
|
|
42
|
+
/** Background color for overlay */
|
|
43
|
+
overlayColor?: string;
|
|
44
|
+
/** Default header title text */
|
|
45
|
+
title?: string;
|
|
46
|
+
/** Default action button text */
|
|
47
|
+
actionText?: string;
|
|
48
|
+
/** Default cancel button text */
|
|
49
|
+
cancelText?: string;
|
|
50
|
+
/** Header content snippet */
|
|
51
|
+
header?: Snippet;
|
|
52
|
+
/** Main content snippet */
|
|
53
|
+
children?: Snippet;
|
|
54
|
+
/** Footer content snippet */
|
|
55
|
+
footer?: Snippet;
|
|
56
|
+
/** Custom close button icon */
|
|
57
|
+
closeIcon?: Component;
|
|
58
|
+
/** Event handler for when modal requests to close */
|
|
59
|
+
onOpenChange?: (open: boolean) => void;
|
|
60
|
+
/** Event handler for overlay click */
|
|
61
|
+
onOverlayClick?: () => void;
|
|
62
|
+
/** Event handler for escape key press */
|
|
63
|
+
onEscapeKeyDown?: () => void;
|
|
64
|
+
/** Event handler for default action button click */
|
|
65
|
+
onAction?: () => void;
|
|
66
|
+
/** Event handler for default cancel button click */
|
|
67
|
+
onCancel?: () => void;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Modal context for compound components
|
|
71
|
+
*/
|
|
72
|
+
export interface ModalContext {
|
|
73
|
+
open: boolean;
|
|
74
|
+
close: () => void;
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|