@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.
Files changed (230) hide show
  1. package/README.md +162 -1
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +1 -0
  4. package/dist/providers/GlobalProvider.mdx +322 -0
  5. package/dist/providers/GlobalProvider.svelte +58 -0
  6. package/dist/providers/GlobalProvider.svelte.d.ts +4 -0
  7. package/dist/providers/configuratorUtils.d.ts +37 -0
  8. package/dist/providers/configuratorUtils.js +219 -0
  9. package/dist/providers/globalContext.svelte.d.ts +18 -0
  10. package/dist/providers/globalContext.svelte.js +439 -0
  11. package/dist/providers/index.d.ts +5 -0
  12. package/dist/providers/index.js +7 -0
  13. package/dist/providers/types.d.ts +103 -0
  14. package/dist/providers/types.js +6 -0
  15. package/dist/router/README.md +2 -2
  16. package/dist/stores/index.d.ts +0 -1
  17. package/dist/stores/index.js +0 -1
  18. package/dist/types/webflow.d.ts +31 -47
  19. package/dist/ui/components/LoadingScreen.svelte +2 -1
  20. package/dist/ui/components/button/Button.svelte +4 -1
  21. package/dist/ui/components/button-group/ButtonGroup.stories.js +112 -0
  22. package/dist/ui/components/{ButtonGroup.svelte → button-group/ButtonGroup.svelte} +20 -33
  23. package/dist/ui/components/button-group/ButtonGroup.svelte.d.ts +13 -0
  24. package/dist/ui/components/button-group/index.d.ts +2 -0
  25. package/dist/ui/components/button-group/index.js +1 -0
  26. package/dist/ui/components/button-group/types.d.ts +32 -0
  27. package/dist/ui/components/checkbox/Checkbox.stories.d.ts +55 -0
  28. package/dist/ui/components/checkbox/Checkbox.stories.js +162 -0
  29. package/dist/ui/components/checkbox/Checkbox.svelte +141 -0
  30. package/dist/ui/components/checkbox/Checkbox.svelte.d.ts +4 -0
  31. package/dist/ui/components/checkbox/index.d.ts +2 -0
  32. package/dist/ui/components/checkbox/index.js +1 -0
  33. package/dist/ui/components/checkbox/types.d.ts +32 -0
  34. package/dist/ui/components/controlled-buttons/ControlledButtons.stories.d.ts +32 -0
  35. package/dist/ui/components/controlled-buttons/ControlledButtons.stories.js +152 -0
  36. package/dist/ui/components/{buttons/FooterButton.svelte → controlled-buttons/ControlledButtons.svelte} +18 -67
  37. package/dist/ui/components/controlled-buttons/ControlledButtons.svelte.d.ts +4 -0
  38. package/dist/ui/components/controlled-buttons/index.d.ts +2 -0
  39. package/dist/ui/components/controlled-buttons/index.js +1 -0
  40. package/dist/ui/components/{buttons → controlled-buttons}/types.d.ts +11 -4
  41. package/dist/ui/components/divider/Divider.stories.svelte +134 -0
  42. package/dist/ui/components/{clickable/Clickable.stories.svelte.d.ts → divider/Divider.stories.svelte.d.ts} +4 -4
  43. package/dist/ui/components/divider/Divider.svelte +30 -0
  44. package/dist/ui/components/divider/Divider.svelte.d.ts +4 -0
  45. package/dist/ui/components/divider/index.d.ts +2 -0
  46. package/dist/ui/components/divider/index.js +1 -0
  47. package/dist/ui/components/divider/types.d.ts +23 -0
  48. package/dist/ui/components/divider/types.js +1 -0
  49. package/dist/ui/components/iframe/Iframe.stories.svelte +122 -0
  50. package/dist/ui/components/{ToggleItem.svelte.d.ts → iframe/Iframe.stories.svelte.d.ts} +7 -8
  51. package/dist/ui/components/iframe/Iframe.svelte +75 -0
  52. package/dist/ui/components/iframe/Iframe.svelte.d.ts +4 -0
  53. package/dist/ui/components/iframe/index.d.ts +2 -0
  54. package/dist/ui/components/iframe/index.js +1 -0
  55. package/dist/ui/components/iframe/types.d.ts +38 -0
  56. package/dist/ui/components/iframe/types.js +1 -0
  57. package/dist/ui/components/index.d.ts +12 -39
  58. package/dist/ui/components/index.js +12 -39
  59. package/dist/ui/components/input/Input.stories.d.ts +24 -0
  60. package/dist/ui/components/input/Input.stories.js +98 -0
  61. package/dist/ui/components/input/Input.svelte +321 -80
  62. package/dist/ui/components/input/types.d.ts +27 -1
  63. package/dist/ui/components/layout/Layout.stories.svelte +3 -3
  64. package/dist/ui/components/layout/Layout.svelte +3 -5
  65. package/dist/ui/components/layout/common/EditModeMessage.svelte +24 -12
  66. package/dist/ui/components/layout/{ExampleLayout.svelte → examples/ExampleLayout.svelte} +34 -22
  67. package/dist/ui/components/layout/examples/Wrapper.svelte +9 -0
  68. package/dist/ui/components/{NoSettingsNeeded.svelte.d.ts → layout/examples/Wrapper.svelte.d.ts} +3 -3
  69. package/dist/ui/components/layout/examples/index.d.ts +2 -0
  70. package/dist/ui/components/layout/examples/index.js +2 -0
  71. package/dist/ui/components/layout/index.d.ts +2 -1
  72. package/dist/ui/components/layout/index.js +2 -1
  73. package/dist/ui/components/modal/Example.svelte +320 -0
  74. package/dist/ui/components/modal/Example.svelte.d.ts +3 -0
  75. package/dist/ui/components/modal/Modal.stories.svelte +18 -0
  76. package/dist/ui/components/modal/Modal.stories.svelte.d.ts +26 -0
  77. package/dist/ui/components/modal/Modal.svelte +490 -0
  78. package/dist/ui/components/modal/Modal.svelte.d.ts +130 -0
  79. package/dist/ui/components/modal/index.d.ts +2 -0
  80. package/dist/ui/components/modal/index.js +1 -0
  81. package/dist/ui/components/modal/types.d.ts +75 -0
  82. package/dist/ui/components/modal/types.js +1 -0
  83. package/dist/ui/components/notification/Notification.stories.svelte +228 -0
  84. package/dist/ui/components/{ToggleList.svelte.d.ts → notification/Notification.stories.svelte.d.ts} +9 -21
  85. package/dist/ui/components/notification/Notification.svelte +289 -0
  86. package/dist/ui/components/notification/Notification.svelte.d.ts +67 -0
  87. package/dist/ui/components/notification/index.d.ts +2 -0
  88. package/dist/ui/components/notification/index.js +1 -0
  89. package/dist/ui/components/notification/types.d.ts +68 -0
  90. package/dist/ui/components/notification/types.js +1 -0
  91. package/dist/ui/components/section/Section.stories.svelte +263 -0
  92. package/dist/ui/components/section/Section.stories.svelte.d.ts +27 -0
  93. package/dist/ui/components/section/Section.svelte +324 -0
  94. package/dist/ui/components/section/Section.svelte.d.ts +5 -0
  95. package/dist/ui/components/section/index.d.ts +2 -0
  96. package/dist/ui/components/section/index.js +1 -0
  97. package/dist/ui/components/section/types.d.ts +106 -0
  98. package/dist/ui/components/section/types.js +1 -0
  99. package/dist/ui/components/{ImageUpload.svelte → shared/ImageUpload.svelte} +3 -3
  100. package/dist/ui/components/{SelectBodyOrDivBlock.svelte → shared/SelectBodyOrDivBlock.svelte} +1 -1
  101. package/dist/ui/components/shared/index.d.ts +2 -0
  102. package/dist/ui/components/shared/index.js +2 -0
  103. package/dist/ui/icons/LineChartIcon.svelte +8 -0
  104. package/dist/ui/icons/LineChartIcon.svelte.d.ts +26 -0
  105. package/dist/ui/icons/index.d.ts +2 -1
  106. package/dist/ui/icons/index.js +2 -1
  107. package/dist/ui/index.css +33 -5
  108. package/dist/utils/api/checkIfAppModeIsDesign.d.ts +1 -2
  109. package/dist/utils/api/checkIfAppModeIsDesign.js +1 -2
  110. package/dist/utils/api/clipboard/handlePaste.d.ts +6 -37
  111. package/dist/utils/api/clipboard/handlePaste.js +2 -6
  112. package/dist/utils/api/getAllAssets.d.ts +1 -2
  113. package/dist/utils/api/getAllAssets.js +1 -2
  114. package/dist/utils/api/getFinsweetComponentsEnvironment.d.ts +1 -2
  115. package/dist/utils/api/getFinsweetComponentsEnvironment.js +3 -6
  116. package/dist/utils/api/index.d.ts +0 -1
  117. package/dist/utils/api/index.js +0 -1
  118. package/dist/utils/api/insertWithXSCP.d.ts +1 -2
  119. package/dist/utils/api/insertWithXSCP.js +1 -2
  120. package/dist/utils/auth/crossWindowLogin.d.ts +3 -0
  121. package/dist/utils/auth/crossWindowLogin.js +3 -0
  122. package/dist/utils/auth/index.d.ts +9 -25
  123. package/dist/utils/auth/index.js +9 -25
  124. package/dist/utils/browser-storage/localStorage.d.ts +4 -12
  125. package/dist/utils/browser-storage/localStorage.js +4 -12
  126. package/dist/utils/browser-storage/sessionStorage.d.ts +4 -12
  127. package/dist/utils/browser-storage/sessionStorage.js +4 -12
  128. package/dist/utils/custom-code/api.d.ts +3 -7
  129. package/dist/utils/custom-code/api.js +3 -7
  130. package/dist/utils/helpers/cleanupTooltipMessage.d.ts +1 -2
  131. package/dist/utils/helpers/cleanupTooltipMessage.js +1 -2
  132. package/dist/utils/helpers/goto.d.ts +1 -4
  133. package/dist/utils/helpers/goto.js +2 -7
  134. package/dist/utils/helpers/index.d.ts +1 -0
  135. package/dist/utils/helpers/index.js +1 -0
  136. package/dist/utils/helpers/noop.d.ts +1 -1
  137. package/dist/utils/helpers/noop.js +1 -1
  138. package/dist/utils/helpers/numbers.d.ts +4 -14
  139. package/dist/utils/helpers/numbers.js +4 -14
  140. package/dist/utils/helpers/objectsToModuleExports.d.ts +1 -3
  141. package/dist/utils/helpers/objectsToModuleExports.js +1 -3
  142. package/dist/utils/helpers/trimText.d.ts +1 -8
  143. package/dist/utils/helpers/trimText.js +1 -8
  144. package/dist/utils/index.d.ts +4 -0
  145. package/dist/utils/index.js +4 -0
  146. package/dist/utils/logger/index.d.ts +0 -2
  147. package/dist/utils/logger/index.js +0 -2
  148. package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.d.ts +1 -3
  149. package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.js +1 -3
  150. package/dist/utils/webflow-canvas/attributes/getInstanceNamesFromObject.d.ts +1 -5
  151. package/dist/utils/webflow-canvas/attributes/getInstanceNamesFromObject.js +1 -5
  152. package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.d.ts +1 -4
  153. package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.js +1 -4
  154. package/dist/utils/webflow-canvas/attributes/getWebflowElementTextContent.d.ts +1 -3
  155. package/dist/utils/webflow-canvas/attributes/getWebflowElementTextContent.js +1 -3
  156. package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.d.ts +1 -4
  157. package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.js +1 -4
  158. package/dist/utils/webflow-canvas/attributes/setStyles.d.ts +1 -3
  159. package/dist/utils/webflow-canvas/attributes/setStyles.js +1 -3
  160. package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.d.ts +1 -8
  161. package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.js +1 -13
  162. package/dist/utils/webflow-canvas/findInstanceElement.d.ts +0 -6
  163. package/dist/utils/webflow-canvas/findInstanceElement.js +1 -7
  164. package/dist/utils/webflow-canvas/getAllPages.d.ts +3 -10
  165. package/dist/utils/webflow-canvas/getAllPages.js +3 -10
  166. package/dist/utils/webflow-canvas/getSiteStagingUrl.d.ts +1 -4
  167. package/dist/utils/webflow-canvas/getSiteStagingUrl.js +1 -4
  168. package/dist/utils/webflow-canvas/index.d.ts +1 -0
  169. package/dist/utils/webflow-canvas/index.js +1 -0
  170. package/package.json +9 -2
  171. package/dist/stores/globalStore.d.ts +0 -10
  172. package/dist/stores/globalStore.js +0 -10
  173. package/dist/ui/components/ButtonGroup.svelte.d.ts +0 -28
  174. package/dist/ui/components/Checkbox.svelte +0 -94
  175. package/dist/ui/components/Checkbox.svelte.d.ts +0 -36
  176. package/dist/ui/components/Copy.svelte +0 -329
  177. package/dist/ui/components/Copy.svelte.d.ts +0 -35
  178. package/dist/ui/components/CustomModal.svelte +0 -192
  179. package/dist/ui/components/CustomModal.svelte.d.ts +0 -45
  180. package/dist/ui/components/DisableInEditMode.svelte +0 -66
  181. package/dist/ui/components/DisableInEditMode.svelte.d.ts +0 -33
  182. package/dist/ui/components/Divider.svelte +0 -31
  183. package/dist/ui/components/Divider.svelte.d.ts +0 -31
  184. package/dist/ui/components/Header.svelte +0 -30
  185. package/dist/ui/components/Header.svelte.d.ts +0 -20
  186. package/dist/ui/components/Iframe.svelte +0 -89
  187. package/dist/ui/components/Iframe.svelte.d.ts +0 -40
  188. package/dist/ui/components/InjectComponent.svelte +0 -297
  189. package/dist/ui/components/InjectComponent.svelte.d.ts +0 -27
  190. package/dist/ui/components/Modal.svelte +0 -139
  191. package/dist/ui/components/Modal.svelte.d.ts +0 -42
  192. package/dist/ui/components/Navbar.svelte +0 -132
  193. package/dist/ui/components/Navbar.svelte.d.ts +0 -29
  194. package/dist/ui/components/NoSettingsNeeded.svelte +0 -31
  195. package/dist/ui/components/Notification.svelte +0 -193
  196. package/dist/ui/components/Notification.svelte.d.ts +0 -64
  197. package/dist/ui/components/PlusMinusButton.svelte +0 -91
  198. package/dist/ui/components/PlusMinusButton.svelte.d.ts +0 -22
  199. package/dist/ui/components/PreviewBar.svelte +0 -40
  200. package/dist/ui/components/PreviewBar.svelte.d.ts +0 -20
  201. package/dist/ui/components/ScrollableContent.svelte +0 -18
  202. package/dist/ui/components/ScrollableContent.svelte.d.ts +0 -31
  203. package/dist/ui/components/Section.svelte +0 -97
  204. package/dist/ui/components/Section.svelte.d.ts +0 -50
  205. package/dist/ui/components/Spacer.svelte +0 -9
  206. package/dist/ui/components/Spacer.svelte.d.ts +0 -22
  207. package/dist/ui/components/SpinnerPlusMinus.svelte +0 -75
  208. package/dist/ui/components/SpinnerPlusMinus.svelte.d.ts +0 -23
  209. package/dist/ui/components/SpinnerUpDown.svelte +0 -194
  210. package/dist/ui/components/SpinnerUpDown.svelte.d.ts +0 -31
  211. package/dist/ui/components/Tabs.svelte +0 -71
  212. package/dist/ui/components/Tabs.svelte.d.ts +0 -26
  213. package/dist/ui/components/ToggleItem.svelte +0 -29
  214. package/dist/ui/components/ToggleList.svelte +0 -57
  215. package/dist/ui/components/buttons/FooterButton.svelte.d.ts +0 -10
  216. package/dist/ui/components/buttons/index.d.ts +0 -5
  217. package/dist/ui/components/buttons/index.js +0 -5
  218. package/dist/ui/components/clickable/Clickable.stories.svelte +0 -213
  219. package/dist/ui/components/clickable/Clickable.svelte +0 -93
  220. package/dist/ui/components/clickable/Clickable.svelte.d.ts +0 -4
  221. package/dist/ui/components/clickable/index.d.ts +0 -2
  222. package/dist/ui/components/clickable/index.js +0 -1
  223. package/dist/ui/components/clickable/types.d.ts +0 -17
  224. package/dist/utils/api/copyPaste/index.d.ts +0 -18
  225. /package/dist/ui/components/{buttons → button-group}/types.js +0 -0
  226. /package/dist/ui/components/{clickable → checkbox}/types.js +0 -0
  227. /package/dist/{utils/api/copyPaste/index.js → ui/components/controlled-buttons/types.js} +0 -0
  228. /package/dist/ui/components/layout/{ExampleLayout.svelte.d.ts → examples/ExampleLayout.svelte.d.ts} +0 -0
  229. /package/dist/ui/components/{ImageUpload.svelte.d.ts → shared/ImageUpload.svelte.d.ts} +0 -0
  230. /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,2 @@
1
+ export { default as Modal } from './Modal.svelte';
2
+ export type { ModalProps, ModalContext } from './types.js';
@@ -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 {};