@finsweet/webflow-apps-utils 1.0.2 → 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 (226) 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 +1 -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/index.css +33 -5
  104. package/dist/utils/api/checkIfAppModeIsDesign.d.ts +1 -2
  105. package/dist/utils/api/checkIfAppModeIsDesign.js +1 -2
  106. package/dist/utils/api/clipboard/handlePaste.d.ts +6 -37
  107. package/dist/utils/api/clipboard/handlePaste.js +2 -6
  108. package/dist/utils/api/getAllAssets.d.ts +1 -2
  109. package/dist/utils/api/getAllAssets.js +1 -2
  110. package/dist/utils/api/getFinsweetComponentsEnvironment.d.ts +1 -2
  111. package/dist/utils/api/getFinsweetComponentsEnvironment.js +3 -6
  112. package/dist/utils/api/index.d.ts +0 -1
  113. package/dist/utils/api/index.js +0 -1
  114. package/dist/utils/api/insertWithXSCP.d.ts +1 -2
  115. package/dist/utils/api/insertWithXSCP.js +1 -2
  116. package/dist/utils/auth/crossWindowLogin.d.ts +3 -0
  117. package/dist/utils/auth/crossWindowLogin.js +3 -0
  118. package/dist/utils/auth/index.d.ts +9 -25
  119. package/dist/utils/auth/index.js +9 -25
  120. package/dist/utils/browser-storage/localStorage.d.ts +4 -12
  121. package/dist/utils/browser-storage/localStorage.js +4 -12
  122. package/dist/utils/browser-storage/sessionStorage.d.ts +4 -12
  123. package/dist/utils/browser-storage/sessionStorage.js +4 -12
  124. package/dist/utils/custom-code/api.d.ts +3 -7
  125. package/dist/utils/custom-code/api.js +3 -7
  126. package/dist/utils/helpers/cleanupTooltipMessage.d.ts +1 -2
  127. package/dist/utils/helpers/cleanupTooltipMessage.js +1 -2
  128. package/dist/utils/helpers/goto.d.ts +1 -4
  129. package/dist/utils/helpers/goto.js +2 -7
  130. package/dist/utils/helpers/index.d.ts +1 -0
  131. package/dist/utils/helpers/index.js +1 -0
  132. package/dist/utils/helpers/noop.d.ts +1 -1
  133. package/dist/utils/helpers/noop.js +1 -1
  134. package/dist/utils/helpers/numbers.d.ts +4 -14
  135. package/dist/utils/helpers/numbers.js +4 -14
  136. package/dist/utils/helpers/objectsToModuleExports.d.ts +1 -3
  137. package/dist/utils/helpers/objectsToModuleExports.js +1 -3
  138. package/dist/utils/helpers/trimText.d.ts +1 -8
  139. package/dist/utils/helpers/trimText.js +1 -8
  140. package/dist/utils/index.d.ts +4 -0
  141. package/dist/utils/index.js +4 -0
  142. package/dist/utils/logger/index.d.ts +0 -2
  143. package/dist/utils/logger/index.js +0 -2
  144. package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.d.ts +1 -3
  145. package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.js +1 -3
  146. package/dist/utils/webflow-canvas/attributes/getInstanceNamesFromObject.d.ts +1 -5
  147. package/dist/utils/webflow-canvas/attributes/getInstanceNamesFromObject.js +1 -5
  148. package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.d.ts +1 -4
  149. package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.js +1 -4
  150. package/dist/utils/webflow-canvas/attributes/getWebflowElementTextContent.d.ts +1 -3
  151. package/dist/utils/webflow-canvas/attributes/getWebflowElementTextContent.js +1 -3
  152. package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.d.ts +1 -4
  153. package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.js +1 -4
  154. package/dist/utils/webflow-canvas/attributes/setStyles.d.ts +1 -3
  155. package/dist/utils/webflow-canvas/attributes/setStyles.js +1 -3
  156. package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.d.ts +1 -8
  157. package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.js +1 -13
  158. package/dist/utils/webflow-canvas/findInstanceElement.d.ts +0 -6
  159. package/dist/utils/webflow-canvas/findInstanceElement.js +1 -7
  160. package/dist/utils/webflow-canvas/getAllPages.d.ts +3 -10
  161. package/dist/utils/webflow-canvas/getAllPages.js +3 -10
  162. package/dist/utils/webflow-canvas/getSiteStagingUrl.d.ts +1 -4
  163. package/dist/utils/webflow-canvas/getSiteStagingUrl.js +1 -4
  164. package/dist/utils/webflow-canvas/index.d.ts +1 -0
  165. package/dist/utils/webflow-canvas/index.js +1 -0
  166. package/package.json +9 -2
  167. package/dist/stores/globalStore.d.ts +0 -10
  168. package/dist/stores/globalStore.js +0 -10
  169. package/dist/ui/components/ButtonGroup.svelte.d.ts +0 -28
  170. package/dist/ui/components/Checkbox.svelte +0 -94
  171. package/dist/ui/components/Checkbox.svelte.d.ts +0 -36
  172. package/dist/ui/components/Copy.svelte +0 -329
  173. package/dist/ui/components/Copy.svelte.d.ts +0 -35
  174. package/dist/ui/components/CustomModal.svelte +0 -192
  175. package/dist/ui/components/CustomModal.svelte.d.ts +0 -45
  176. package/dist/ui/components/DisableInEditMode.svelte +0 -66
  177. package/dist/ui/components/DisableInEditMode.svelte.d.ts +0 -33
  178. package/dist/ui/components/Divider.svelte +0 -31
  179. package/dist/ui/components/Divider.svelte.d.ts +0 -31
  180. package/dist/ui/components/Header.svelte +0 -30
  181. package/dist/ui/components/Header.svelte.d.ts +0 -20
  182. package/dist/ui/components/Iframe.svelte +0 -89
  183. package/dist/ui/components/Iframe.svelte.d.ts +0 -40
  184. package/dist/ui/components/InjectComponent.svelte +0 -297
  185. package/dist/ui/components/InjectComponent.svelte.d.ts +0 -27
  186. package/dist/ui/components/Modal.svelte +0 -139
  187. package/dist/ui/components/Modal.svelte.d.ts +0 -42
  188. package/dist/ui/components/Navbar.svelte +0 -132
  189. package/dist/ui/components/Navbar.svelte.d.ts +0 -29
  190. package/dist/ui/components/NoSettingsNeeded.svelte +0 -31
  191. package/dist/ui/components/Notification.svelte +0 -193
  192. package/dist/ui/components/Notification.svelte.d.ts +0 -64
  193. package/dist/ui/components/PlusMinusButton.svelte +0 -91
  194. package/dist/ui/components/PlusMinusButton.svelte.d.ts +0 -22
  195. package/dist/ui/components/PreviewBar.svelte +0 -40
  196. package/dist/ui/components/PreviewBar.svelte.d.ts +0 -20
  197. package/dist/ui/components/ScrollableContent.svelte +0 -18
  198. package/dist/ui/components/ScrollableContent.svelte.d.ts +0 -31
  199. package/dist/ui/components/Section.svelte +0 -97
  200. package/dist/ui/components/Section.svelte.d.ts +0 -50
  201. package/dist/ui/components/Spacer.svelte +0 -9
  202. package/dist/ui/components/Spacer.svelte.d.ts +0 -22
  203. package/dist/ui/components/SpinnerPlusMinus.svelte +0 -75
  204. package/dist/ui/components/SpinnerPlusMinus.svelte.d.ts +0 -23
  205. package/dist/ui/components/SpinnerUpDown.svelte +0 -194
  206. package/dist/ui/components/SpinnerUpDown.svelte.d.ts +0 -31
  207. package/dist/ui/components/Tabs.svelte +0 -71
  208. package/dist/ui/components/Tabs.svelte.d.ts +0 -26
  209. package/dist/ui/components/ToggleItem.svelte +0 -29
  210. package/dist/ui/components/ToggleList.svelte +0 -57
  211. package/dist/ui/components/buttons/FooterButton.svelte.d.ts +0 -10
  212. package/dist/ui/components/buttons/index.d.ts +0 -5
  213. package/dist/ui/components/buttons/index.js +0 -5
  214. package/dist/ui/components/clickable/Clickable.stories.svelte +0 -213
  215. package/dist/ui/components/clickable/Clickable.svelte +0 -93
  216. package/dist/ui/components/clickable/Clickable.svelte.d.ts +0 -4
  217. package/dist/ui/components/clickable/index.d.ts +0 -2
  218. package/dist/ui/components/clickable/index.js +0 -1
  219. package/dist/ui/components/clickable/types.d.ts +0 -17
  220. package/dist/utils/api/copyPaste/index.d.ts +0 -18
  221. /package/dist/ui/components/{buttons → button-group}/types.js +0 -0
  222. /package/dist/ui/components/{clickable → checkbox}/types.js +0 -0
  223. /package/dist/{utils/api/copyPaste/index.js → ui/components/controlled-buttons/types.js} +0 -0
  224. /package/dist/ui/components/layout/{ExampleLayout.svelte.d.ts → examples/ExampleLayout.svelte.d.ts} +0 -0
  225. /package/dist/ui/components/{ImageUpload.svelte.d.ts → shared/ImageUpload.svelte.d.ts} +0 -0
  226. /package/dist/ui/components/{SelectBodyOrDivBlock.svelte.d.ts → shared/SelectBodyOrDivBlock.svelte.d.ts} +0 -0
package/README.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  Shared UI components and utilities for Finsweet's Webflow applications.
6
6
 
7
+ 🔗 **[Live Storybook Documentation](https://webflow-apps-utils.pages.dev)**
8
+
7
9
  ## Installation
8
10
 
9
11
  ```bash
@@ -15,7 +17,165 @@ pnpm add @finsweet/webflow-apps-utils
15
17
  ```typescript
16
18
  import '@finsweet/webflow-apps-utils/index.css';
17
19
 
18
- import { Button, Modal, Input, breakpointStore } from '@finsweet/webflow-apps-utils';
20
+ import { Button, Modal, Input, siteInfo } from '@finsweet/webflow-apps-utils';
21
+ ```
22
+
23
+ ## Project Structure
24
+
25
+ ```
26
+ src/
27
+ ├── lib/
28
+ │ ├── router/ # Client-side routing utilities
29
+ │ ├── stores/ # Stores for state management
30
+ │ ├── types/ # TypeScript type definitions
31
+ │ ├── ui/ # UI components and styling
32
+ │ │ ├── components/ # Reusable UI components
33
+ │ │ └── icons/ # SVG icon components
34
+ │ └── utils/ # Helper functions and utilities
35
+ ```
36
+
37
+ ## Coding Standards
38
+
39
+ ### Naming Conventions
40
+
41
+ #### File and Folder Names
42
+
43
+ - **Folders**: Use `kebab-case` for all directory names
44
+
45
+ ```
46
+ ✅ custom-code/
47
+ ✅ webflow-canvas/
48
+ ✅ browser-storage/
49
+ ❌ customCode/
50
+ ❌ WebflowCanvas/
51
+ ```
52
+
53
+ - **Files**: Use `camelCase` and `PascalCase` for all file names
54
+
55
+ ```
56
+ ✅ localStorage.ts
57
+ ✅ handlePaste.ts
58
+ ✅ getAllAssets.ts
59
+ ✅ Button.svelte
60
+ ✅ Form.svelte
61
+ ❌ local-storage.ts
62
+ ❌ handle_paste.ts
63
+ ❌ form.svelte
64
+
65
+ ```
66
+
67
+ #### Code Naming
68
+
69
+ - **Components**: Use `PascalCase` for component names
70
+ - **Functions**: Use `camelCase` for function names
71
+ - **Variables**: Use `camelCase` for variable names
72
+ - **Constants**: Use `UPPERCASE` for constants
73
+ - **Types/Interfaces**: Use `PascalCase` for type definitions
74
+
75
+ ### Documentation Standards
76
+
77
+ - Keep function documentation concise
78
+
79
+ ## Testing UI Components
80
+
81
+ ### Testing Strategy
82
+
83
+ All UI components should include comprehensive tests covering:
84
+
85
+ - **Basic Rendering**: Default props, custom props, and various configurations
86
+ - **Component Variants**: All available variants (primary, secondary, danger, etc.)
87
+ - **Interactive States**: Disabled, loading, invalid, and other state combinations
88
+ - **User Interactions**: Click events, keyboard navigation, and form submissions
89
+ - **Accessibility**: ARIA attributes, focus management, and screen reader support
90
+ - **Visual Features**: Icons, tooltips, custom styling, and layout variations
91
+
92
+ ### Test Structure
93
+
94
+ Use Vitest and Testing Library for component testing:
95
+
96
+ ```typescript
97
+ import { fireEvent, render, screen, waitFor } from '@testing-library/svelte';
98
+ import { describe, expect, it, vi } from 'vitest';
99
+ import Component from './Component.svelte';
100
+
101
+ describe('Component Name', () => {
102
+ describe('Basic Rendering', () => {
103
+ it('renders with default props', () => {
104
+ render(Component);
105
+ const element = screen.getByRole('...');
106
+ expect(element).toBeInTheDocument();
107
+ });
108
+ });
109
+
110
+ describe('Variants', () => {
111
+ // Test all component variants
112
+ });
113
+
114
+ describe('States', () => {
115
+ // Test disabled, loading, invalid states
116
+ });
117
+
118
+ describe('Events', () => {
119
+ // Test user interactions
120
+ });
121
+
122
+ describe('Accessibility', () => {
123
+ // Test ARIA attributes and keyboard navigation
124
+ });
125
+ });
126
+ ```
127
+
128
+ ### Testing Best Practices
129
+
130
+ - **Comprehensive Coverage**: Test all props, variants, and states
131
+ - **User-Centric Tests**: Focus on user interactions rather than implementation details
132
+ - **Accessibility Testing**: Verify ARIA attributes, keyboard navigation, and screen reader support
133
+ - **Async Behavior**: Use `waitFor` for testing tooltips, modals, and dynamic content
134
+ - **Event Mocking**: Mock external dependencies and event handlers properly
135
+ - **State Verification**: Check both visual state and underlying attributes
136
+
137
+ ### Example: Button Component Testing
138
+
139
+ ```typescript
140
+ // Testing component variants
141
+ const variants: ButtonVariant[] = ['primary', 'secondary', 'danger', 'cms'];
142
+ variants.forEach((variant) => {
143
+ it(`renders ${variant} variant correctly`, () => {
144
+ render(Button, { variant });
145
+ const button = screen.getByRole('button');
146
+ expect(button).toHaveClass(`button--${variant}`);
147
+ });
148
+ });
149
+
150
+ // Testing interactive states
151
+ it('renders loading state', () => {
152
+ render(Button, { loading: true });
153
+ const button = screen.getByRole('button');
154
+ expect(button).toBeDisabled();
155
+ expect(button).toHaveAttribute('aria-busy', 'true');
156
+ expect(button).toHaveClass('button--loading');
157
+ });
158
+
159
+ // Testing accessibility
160
+ it('has proper ARIA attributes', () => {
161
+ render(Button, { ariaLabel: 'Custom label', loading: true });
162
+ const button = screen.getByRole('button');
163
+ expect(button).toHaveAttribute('aria-label', 'Custom label');
164
+ expect(button).toHaveAttribute('aria-busy', 'true');
165
+ });
166
+
167
+ // Testing async interactions (tooltips)
168
+ it('shows tooltip on hover', async () => {
169
+ render(Button, {
170
+ tooltip: { message: 'Help text', listener: 'hover', listenerout: 'hover' }
171
+ });
172
+
173
+ const button = screen.getByRole('button');
174
+ const tooltipTarget = button.closest('.target');
175
+ await fireEvent.mouseEnter(tooltipTarget || button);
176
+
177
+ expect(screen.getByText('Help text')).toBeInTheDocument();
178
+ });
19
179
  ```
20
180
 
21
181
  ## Development
@@ -32,6 +192,7 @@ pnpm storybook # Component development
32
192
  pnpm build # Build library
33
193
  pnpm test # Run tests
34
194
  pnpm lint # Check code quality
195
+ pnpm check # Check code quality
35
196
  ```
36
197
 
37
198
  ## Publishing
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './ui';
2
2
  export * from './router/index.svelte';
3
3
  export * from './stores';
4
+ export * from './providers';
4
5
  export * from './utils';
5
6
  export * from './types';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './ui';
2
2
  export * from './router/index.svelte';
3
3
  export * from './stores';
4
+ export * from './providers';
4
5
  export * from './utils';
5
6
  export * from './types';
@@ -0,0 +1,322 @@
1
+ # GlobalProvider
2
+
3
+ The `GlobalProvider` is a context management system built on Svelte 5 that manages multiple application contexts in a type-safe and reactive way.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Contexts**: Manage different types of state (form, app, data, etc.) in separate contexts
8
+ - **Type Safety**: Full TypeScript support with branded types and generics
9
+ - **Reactive**: Built on Svelte 5 runes for optimal reactivity
10
+ - **Event System**: Subscribe to context changes and global events (batched for performance)
11
+
12
+ ## Basic Usage
13
+
14
+ ### Wrap Your App
15
+
16
+ ```svelte
17
+ <script lang="ts">
18
+ import { GlobalProvider } from '$lib/providers';
19
+
20
+ const initialContexts = {
21
+ app: {
22
+ editMode: false,
23
+ repairMode: false,
24
+ title: 'My App'
25
+ },
26
+ form: {
27
+ formKey: null,
28
+ formUpdateKey: null
29
+ }
30
+ };
31
+ </script>
32
+
33
+ <GlobalProvider {initialContexts} debug={true}>
34
+ <App />
35
+ </GlobalProvider>
36
+ ```
37
+
38
+ ### Default Contexts
39
+
40
+ The `GlobalProvider` automatically creates these default contexts:
41
+
42
+ - **`app`**: Application state (editMode, repairMode, title, configurator)
43
+ - **`form`**: Form state (formKey, formUpdateKey)
44
+ - **`data`**: General data state
45
+
46
+ ### Use Contexts in Components
47
+
48
+ ```svelte
49
+ <script lang="ts">
50
+ import { useAppContext, useFormContext, useDataContext } from '$lib/providers';
51
+
52
+ const appContext = useAppContext();
53
+ const formContext = useFormContext();
54
+ const dataContext = useDataContext();
55
+
56
+ let appData = $derived(appContext.get());
57
+ let formData = $derived(formContext.get());
58
+
59
+ function toggleEditMode() {
60
+ appContext.update((current) => ({
61
+ ...current,
62
+ editMode: !current?.editMode
63
+ }));
64
+ }
65
+ </script>
66
+
67
+ <div>
68
+ <p>Edit Mode: {appData?.editMode}</p>
69
+ <p>Form Key: {formData?.formKey}</p>
70
+ <button onclick={toggleEditMode}>Toggle Edit Mode</button>
71
+ </div>
72
+ ```
73
+
74
+ ## API Reference
75
+
76
+ ### Context Operations
77
+
78
+ #### `get(): T | null`
79
+
80
+ Returns the current context data. Returns `undefined` if the context has been reset (completely removed).
81
+
82
+ #### `set(data: Partial<T>): void`
83
+
84
+ Sets context data (merges with existing data).
85
+
86
+ #### `update(updater: (current: T | null) => T): void`
87
+
88
+ Updates context data using an updater function.
89
+
90
+ #### `clear(): void`
91
+
92
+ Clears context data (sets to null). The context remains active but with null data.
93
+
94
+ #### `reset(): void`
95
+
96
+ Completely removes the context. After reset, `hasContext()` returns false and `get()` returns `undefined`.
97
+
98
+ #### `subscribe(callback: (data: T | null) => void): () => void`
99
+
100
+ Subscribes to context changes. Returns unsubscribe function. **Note**: Events are batched and emitted asynchronously for performance.
101
+
102
+ ### Global Operations
103
+
104
+ - `getContext<T>(key: string): ContextOperations<T>` - Get context operations for a key
105
+ - `hasContext(key: string): boolean` - Check if context exists
106
+ - `removeContext(key: string): void` - Remove a specific context
107
+ - `clearAll(): void` - Clear all context data (set to null)
108
+ - `resetAll(): void` - Reset all contexts (completely remove them)
109
+ - `resetByKey(key: string): void` - Reset a specific context by key
110
+ - `getActiveContexts(): string[]` - Get list of active context keys
111
+ - `getAllContexts(): Record<string, unknown>` - Get all context data
112
+ - `getContextMetadata(key: string)` - Get metadata (version, updatedAt, isActive) for a context
113
+ - `subscribe(callback): () => void` - Subscribe to global context events
114
+
115
+ ## Examples
116
+
117
+ ### App State Management
118
+
119
+ ```svelte
120
+ <script lang="ts">
121
+ import { useAppContext } from '$lib/providers';
122
+
123
+ const appContext = useAppContext();
124
+ let appData = $derived(appContext.get());
125
+
126
+ function handleSubmit() {
127
+ appContext.set({ editMode: true });
128
+ }
129
+ </script>
130
+
131
+ <form onsubmit={handleSubmit}>
132
+ <p>Edit Mode: {appData?.editMode}</p>
133
+ <button type="submit">Submit</button>
134
+ </form>
135
+ ```
136
+
137
+ ### Custom Context
138
+
139
+ ```svelte
140
+ <script lang="ts">
141
+ import { useContext } from '$lib/providers';
142
+
143
+ type UserContext = {
144
+ id: string;
145
+ name: string;
146
+ preferences: { theme: 'light' | 'dark' };
147
+ };
148
+
149
+ const userContext = useContext<UserContext>('user');
150
+ let userData = $derived(userContext.get());
151
+
152
+ function updateTheme(theme: 'light' | 'dark') {
153
+ userContext.update((current) => ({
154
+ ...current!,
155
+ preferences: { ...current!.preferences, theme }
156
+ }));
157
+ }
158
+ </script>
159
+ ```
160
+
161
+ ### Typed Data Context
162
+
163
+ ```svelte
164
+ <script lang="ts">
165
+ import { useDataContext } from '$lib/providers';
166
+
167
+ type AppDataType = {
168
+ users: Array<{ id: string; name: string; email: string }>;
169
+ products: Array<{ id: string; title: string; price: number }>;
170
+ currentPage: number;
171
+ totalPages: number;
172
+ };
173
+
174
+ const dataContext = useDataContext<AppDataType>();
175
+ let appData = $derived(dataContext.get());
176
+
177
+ function loadUsers(users: AppDataType['users']) {
178
+ dataContext.set({
179
+ state: {
180
+ ...appData?.state,
181
+ users,
182
+ currentPage: 1
183
+ }
184
+ });
185
+ }
186
+
187
+ function nextPage() {
188
+ if (appData?.state && appData.state.currentPage < appData.state.totalPages) {
189
+ dataContext.update((current) => ({
190
+ state: {
191
+ ...current!.state!,
192
+ currentPage: current!.state!.currentPage + 1
193
+ }
194
+ }));
195
+ }
196
+ }
197
+ </script>
198
+
199
+ <div>
200
+ <p>Users: {appData?.state?.users?.length || 0}</p>
201
+ <p>Page: {appData?.state?.currentPage || 1} of {appData?.state?.totalPages || 1}</p>
202
+ <button onclick={nextPage}>Next Page</button>
203
+ </div>
204
+ ```
205
+
206
+ ## Configurator Support
207
+
208
+ The `GlobalProvider` includes built-in support for configurator state management with automatic change detection.
209
+
210
+ ### Using the Configurator Context
211
+
212
+ ```svelte
213
+ <script lang="ts">
214
+ import { useConfiguratorContext, useAppContext } from '$lib/providers';
215
+
216
+ // Define your configurator type
217
+ type MyConfiguratorType = {
218
+ theme: 'light' | 'dark';
219
+ layout: 'grid' | 'list';
220
+ itemsPerPage: number;
221
+ };
222
+
223
+ // Use typed configurator context
224
+ const configurator = useConfiguratorContext<MyConfiguratorType>();
225
+
226
+ // Or use typed app context
227
+ const appContext = useAppContext<MyConfiguratorType>();
228
+
229
+ // Set configurator data with watch options (fully typed)
230
+ configurator.setConfigurator(
231
+ { theme: 'dark', layout: 'grid', itemsPerPage: 10 },
232
+ { watchKeys: ['theme'], debounceMs: 100 }
233
+ );
234
+
235
+ // Check if configurator has changed
236
+ let hasChanged = $derived(configurator.hasChanged);
237
+ let currentConfig = $derived(configurator.configurator); // Type: MyConfiguratorType | null
238
+ let cachedConfig = $derived(configurator.configuratorCache); // Type: MyConfiguratorType | null
239
+
240
+ // Save current state to cache
241
+ function saveToCache() {
242
+ configurator.saveToCache();
243
+ }
244
+ </script>
245
+
246
+ <div>
247
+ <p>Has Changed: {hasChanged}</p>
248
+ <p>Current Theme: {currentConfig?.theme}</p>
249
+ <p>Cached Theme: {cachedConfig?.theme}</p>
250
+ <button onclick={saveToCache}>Save to Cache</button>
251
+ </div>
252
+ ```
253
+
254
+ ### Configurator API
255
+
256
+ - `configurator` - Current configurator data
257
+ - `configuratorCache` - Cached configurator data
258
+ - `hasChanged` - Boolean indicating if configurator differs from cache
259
+ - `watchOptions` - Current watch configuration
260
+ - `setConfigurator(data, watchOptions?)` - Set configurator data
261
+ - `setConfiguratorCache(data)` - Set cache data
262
+ - `saveToCache()` - Save current configurator to cache
263
+ - `updateWatchOptions(options)` - Update watch configuration
264
+
265
+ ### Watch Options
266
+
267
+ ```typescript
268
+ interface ConfiguratorWatchOptions {
269
+ watchAll?: boolean; // Watch all keys (default: true)
270
+ watchKeys?: string[]; // Specific keys to watch
271
+ debounceMs?: number; // Debounce delay (default: 50ms)
272
+ }
273
+ ```
274
+
275
+ ## TypeScript Support
276
+
277
+ ### Generic Context Usage
278
+
279
+ ```typescript
280
+ import type { ContextOperations, AppContextData, DataContextData } from '$lib/providers';
281
+
282
+ // For custom contexts
283
+ const userContext: ContextOperations<UserType> = useContext<UserType>('user');
284
+
285
+ // For typed app context with configurator
286
+ type MyConfiguratorType = {
287
+ theme: 'light' | 'dark';
288
+ layout: 'grid' | 'list';
289
+ };
290
+
291
+ const appContext = useAppContext<MyConfiguratorType>();
292
+ const configurator = useConfiguratorContext<MyConfiguratorType>();
293
+
294
+ // For typed data context
295
+ type MyDataType = {
296
+ users: User[];
297
+ products: Product[];
298
+ currentPage: number;
299
+ };
300
+
301
+ const dataContext = useDataContext<MyDataType>();
302
+
303
+ // The configurator and configuratorCache will both be typed as MyConfiguratorType | null
304
+ // The data context state will be typed as MyDataType | null
305
+ ```
306
+
307
+ ### Type Definitions
308
+
309
+ ```typescript
310
+ // Your configurator type
311
+ type MyConfiguratorType = {
312
+ theme: 'light' | 'dark';
313
+ layout: 'grid' | 'list';
314
+ itemsPerPage: number;
315
+ };
316
+
317
+ // App context will be typed as AppContextData<MyConfiguratorType>
318
+ type MyAppContextType = AppContextData<MyConfiguratorType>;
319
+
320
+ // Data context will be typed as DataContextData<MyDataType>
321
+ type MyDataContextType = DataContextData<MyDataType>;
322
+ ```
@@ -0,0 +1,58 @@
1
+ <script lang="ts">
2
+ import { getFinsweetComponentsEnvironment } from '../utils/index.js';
3
+
4
+ import { createGlobalContext, setGlobalContext } from './globalContext.svelte';
5
+ import type { GlobalProviderProps } from './types';
6
+
7
+ let { initialContexts = {}, debug = false, children }: GlobalProviderProps = $props();
8
+
9
+ // Default contexts with configurator support
10
+ const defaultContexts = {
11
+ app: {
12
+ editMode: false,
13
+ repairMode: false,
14
+ title: null,
15
+ configurator: {
16
+ configurator: null,
17
+ configuratorCache: null,
18
+ hasChanged: false,
19
+ watchOptions: {
20
+ watchAll: true,
21
+ watchKeys: [],
22
+ debounceMs: 100
23
+ }
24
+ }
25
+ },
26
+ form: {
27
+ formKey: null,
28
+ formUpdateKey: null
29
+ },
30
+ data: {
31
+ state: null
32
+ }
33
+ };
34
+
35
+ // Merge provided contexts with defaults
36
+ const mergedContexts = {
37
+ ...defaultContexts,
38
+ ...initialContexts
39
+ };
40
+
41
+ // Create and set the global context
42
+ const globalContext = createGlobalContext(mergedContexts, debug);
43
+ setGlobalContext(globalContext);
44
+ const { development } = getFinsweetComponentsEnvironment();
45
+
46
+ // Development mode debugging
47
+ if (development && typeof window !== 'undefined') {
48
+ globalContext.subscribe((event) => {
49
+ console.log('🌍 Global Context Event:', event);
50
+ });
51
+ }
52
+ </script>
53
+
54
+ {#if children}{@render children()}{/if}
55
+
56
+ <style>
57
+ /* Global provider styles - currently using display: contents */
58
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { GlobalProviderProps } from './types';
2
+ declare const GlobalProvider: import("svelte").Component<GlobalProviderProps, {}, "">;
3
+ type GlobalProvider = ReturnType<typeof GlobalProvider>;
4
+ export default GlobalProvider;
@@ -0,0 +1,37 @@
1
+ import type { ConfiguratorState, ConfiguratorWatchOptions } from './types';
2
+ /**
3
+ * Create default configurator state
4
+ */
5
+ export declare function createDefaultConfiguratorState<T = Record<string, any>>(): ConfiguratorState<T>;
6
+ /**
7
+ * Deep compare two objects with performance optimizations
8
+ */
9
+ export declare function deepCompare<T>(obj1: T, obj2: T): boolean;
10
+ /**
11
+ * Compare specific keys of two objects with optimization
12
+ */
13
+ export declare function compareKeys<T extends Record<string, any>>(obj1: T | null, obj2: T | null, keys: string[]): boolean;
14
+ /**
15
+ * Determine if configurator has changed with performance optimization
16
+ */
17
+ export declare function hasConfiguratorChanged<T extends Record<string, any>>(configurator: T | null, configuratorCache: T | null, watchOptions: ConfiguratorWatchOptions): boolean;
18
+ /**
19
+ * Create a debounced function for configurator updates
20
+ */
21
+ export declare function createDebouncedUpdate<T extends (...args: any[]) => void>(fn: T, delay: number): T;
22
+ /**
23
+ * Extract specific keys from an object
24
+ */
25
+ export declare function extractKeys<T extends Record<string, any>>(obj: T | null, keys: string[]): Partial<T> | null;
26
+ /**
27
+ * Get all keys from an object (for watchAll mode)
28
+ */
29
+ export declare function getAllKeys<T extends Record<string, any>>(obj: T | null): string[];
30
+ /**
31
+ * Validate watch options
32
+ */
33
+ export declare function validateWatchOptions(options: ConfiguratorWatchOptions): ConfiguratorWatchOptions;
34
+ /**
35
+ * Create a snapshot of configurator state for comparison
36
+ */
37
+ export declare function createConfiguratorSnapshot<T extends Record<string, any>>(configurator: T | null, watchOptions: ConfiguratorWatchOptions): T | Partial<T> | null;