@finsweet/webflow-apps-utils 1.0.3 → 1.0.5

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 (116) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/providers/GlobalProvider.stories.d.ts +5 -0
  4. package/dist/providers/GlobalProvider.stories.js +419 -0
  5. package/dist/providers/GlobalProviderDemo.svelte +266 -0
  6. package/dist/providers/GlobalProviderDemo.svelte.d.ts +3 -0
  7. package/dist/providers/configuratorUtils.d.ts +11 -14
  8. package/dist/providers/configuratorUtils.js +68 -115
  9. package/dist/providers/index.d.ts +1 -1
  10. package/dist/providers/index.js +1 -1
  11. package/dist/router/Router.stories.d.ts +6 -0
  12. package/dist/router/Router.stories.js +564 -0
  13. package/dist/router/examples/RouterExample.svelte +271 -0
  14. package/dist/router/examples/RouterExample.svelte.d.ts +18 -0
  15. package/dist/router/examples/index.d.ts +4 -0
  16. package/dist/router/examples/index.js +4 -0
  17. package/dist/router/examples/pages/AboutPage.svelte +568 -0
  18. package/dist/router/examples/pages/AboutPage.svelte.d.ts +13 -0
  19. package/dist/router/examples/pages/HomePage.svelte +200 -0
  20. package/dist/router/examples/pages/HomePage.svelte.d.ts +14 -0
  21. package/dist/router/examples/pages/NotFoundPage.svelte +307 -0
  22. package/dist/router/examples/pages/NotFoundPage.svelte.d.ts +17 -0
  23. package/dist/router/hooks.svelte.d.ts +2 -2
  24. package/dist/router/index.d.ts +3 -0
  25. package/dist/router/index.js +3 -0
  26. package/dist/router/{Link.svelte → providers/Link.svelte} +1 -1
  27. package/dist/router/{Route.svelte → providers/Route.svelte} +1 -1
  28. package/dist/router/{Route.svelte.d.ts → providers/Route.svelte.d.ts} +1 -1
  29. package/dist/router/{Router.svelte → providers/RouterProvider.svelte} +22 -5
  30. package/dist/router/{Router.svelte.d.ts → providers/RouterProvider.svelte.d.ts} +8 -4
  31. package/dist/router/providers/index.d.ts +3 -0
  32. package/dist/router/providers/index.js +3 -0
  33. package/dist/router/{index.svelte.d.ts → router.svelte.d.ts} +1 -3
  34. package/dist/router/{index.svelte.js → router.svelte.js} +1 -4
  35. package/dist/stores/forms/Form.stories.d.ts +5 -0
  36. package/dist/stores/forms/Form.stories.js +342 -0
  37. package/dist/stores/forms/FormDemo.svelte +545 -0
  38. package/dist/stores/forms/FormDemo.svelte.d.ts +18 -0
  39. package/dist/stores/forms.d.ts +41 -4
  40. package/dist/stores/forms.js +86 -32
  41. package/dist/types/customCode.d.ts +1 -1
  42. package/dist/types/window.d.ts +1 -0
  43. package/dist/ui/components/button/Button.svelte +1 -1
  44. package/dist/ui/components/copy-text/CopyText.stories.d.ts +70 -0
  45. package/dist/ui/components/copy-text/CopyText.stories.js +241 -0
  46. package/dist/ui/components/copy-text/CopyText.svelte +247 -0
  47. package/dist/ui/components/copy-text/CopyText.svelte.d.ts +4 -0
  48. package/dist/ui/components/copy-text/index.d.ts +2 -0
  49. package/dist/ui/components/copy-text/index.js +1 -0
  50. package/dist/ui/components/copy-text/types.d.ts +52 -0
  51. package/dist/ui/components/copy-text/types.js +1 -0
  52. package/dist/ui/components/index.d.ts +1 -0
  53. package/dist/ui/components/index.js +1 -0
  54. package/dist/ui/components/input/Input.stories.d.ts +9 -0
  55. package/dist/ui/components/input/Input.stories.js +78 -0
  56. package/dist/ui/components/input/Input.svelte +39 -3
  57. package/dist/ui/components/input/types.d.ts +6 -0
  58. package/dist/ui/components/layout/Layout.svelte +45 -64
  59. package/dist/ui/components/layout/Layout.svelte.d.ts +26 -3
  60. package/dist/ui/components/layout/examples/ExampleLayout.svelte +32 -27
  61. package/dist/ui/components/layout/index.d.ts +1 -1
  62. package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte +20 -0
  63. package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte.d.ts +7 -0
  64. package/dist/ui/components/layout/types.d.ts +1 -10
  65. package/dist/ui/components/notification/Notification.stories.svelte +12 -1
  66. package/dist/ui/components/notification/Notification.svelte +10 -5
  67. package/dist/ui/components/notification/Notification.svelte.d.ts +1 -1
  68. package/dist/ui/components/notification/types.d.ts +1 -1
  69. package/dist/ui/components/section/Section.svelte +8 -4
  70. package/dist/ui/components/section/types.d.ts +8 -0
  71. package/dist/ui/components/text/Text.stories.svelte +67 -1
  72. package/dist/ui/components/text/Text.svelte +209 -8
  73. package/dist/ui/components/text/types.d.ts +4 -0
  74. package/dist/ui/index.css +6 -2
  75. package/dist/utils/animations/factory.d.ts +7 -0
  76. package/dist/utils/animations/factory.js +101 -0
  77. package/dist/utils/animations/index.d.ts +7 -0
  78. package/dist/utils/animations/index.js +62 -0
  79. package/dist/utils/animations/types.d.ts +39 -0
  80. package/dist/utils/animations/types.js +1 -0
  81. package/dist/utils/custom-code/configs.d.ts +22 -0
  82. package/dist/utils/custom-code/configs.js +40 -0
  83. package/dist/utils/custom-code/index.d.ts +1 -0
  84. package/dist/utils/custom-code/index.js +1 -0
  85. package/dist/utils/diff-mapper/DiffMapper.stories.d.ts +5 -0
  86. package/dist/utils/diff-mapper/DiffMapper.stories.js +185 -0
  87. package/dist/utils/diff-mapper/DiffMapperDemo.svelte +351 -0
  88. package/dist/utils/diff-mapper/DiffMapperDemo.svelte.d.ts +18 -0
  89. package/dist/utils/diff-mapper/deepDiffMapper.d.ts +31 -0
  90. package/dist/utils/diff-mapper/deepDiffMapper.js +264 -0
  91. package/dist/utils/diff-mapper/index.d.ts +1 -0
  92. package/dist/utils/diff-mapper/index.js +1 -0
  93. package/dist/utils/helpers/capitalizeFirstLetter.d.ts +4 -0
  94. package/dist/utils/helpers/capitalizeFirstLetter.js +9 -0
  95. package/dist/utils/helpers/getTimeNow.d.ts +4 -0
  96. package/dist/utils/helpers/getTimeNow.js +8 -0
  97. package/dist/utils/helpers/index.d.ts +4 -0
  98. package/dist/utils/helpers/index.js +4 -0
  99. package/dist/utils/helpers/minifyCode.d.ts +10 -0
  100. package/dist/utils/helpers/minifyCode.js +73 -0
  101. package/dist/utils/helpers/objectsToModuleExports.d.ts +1 -1
  102. package/dist/utils/helpers/objectsToModuleExports.js +1 -0
  103. package/dist/utils/helpers/toHumanReadableList.d.ts +4 -0
  104. package/dist/utils/helpers/toHumanReadableList.js +11 -0
  105. package/dist/utils/index.d.ts +2 -0
  106. package/dist/utils/index.js +2 -0
  107. package/dist/utils/webflow-canvas/getAllChildren.d.ts +16 -0
  108. package/dist/utils/webflow-canvas/getAllChildren.js +65 -0
  109. package/dist/utils/webflow-canvas/getElementClassList.d.ts +9 -0
  110. package/dist/utils/webflow-canvas/getElementClassList.js +19 -0
  111. package/dist/utils/webflow-canvas/index.d.ts +2 -0
  112. package/dist/utils/webflow-canvas/index.js +2 -0
  113. package/package.json +6 -1
  114. package/dist/providers/GlobalProvider.mdx +0 -322
  115. package/dist/router/README.md +0 -397
  116. /package/dist/router/{Link.svelte.d.ts → providers/Link.svelte.d.ts} +0 -0
@@ -0,0 +1,264 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ export var DiffType;
3
+ (function (DiffType) {
4
+ DiffType["CREATED"] = "created";
5
+ DiffType["UPDATED"] = "updated";
6
+ DiffType["DELETED"] = "deleted";
7
+ DiffType["UNCHANGED"] = "unchanged";
8
+ })(DiffType || (DiffType = {}));
9
+ class DeepDiffMapper {
10
+ visitedPairs = new WeakMap();
11
+ isFunction(x) {
12
+ return Object.prototype.toString.call(x) === '[object Function]';
13
+ }
14
+ isArray(x) {
15
+ return Object.prototype.toString.call(x) === '[object Array]';
16
+ }
17
+ isDate(x) {
18
+ return Object.prototype.toString.call(x) === '[object Date]';
19
+ }
20
+ isObject(x) {
21
+ return Object.prototype.toString.call(x) === '[object Object]';
22
+ }
23
+ isValue(x) {
24
+ return !this.isObject(x) && !this.isArray(x);
25
+ }
26
+ compareValues(value1, value2) {
27
+ if (value1 === value2 || this.areEquivalentPrimitives(value1, value2)) {
28
+ return DiffType.UNCHANGED;
29
+ }
30
+ if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
31
+ return DiffType.UNCHANGED;
32
+ }
33
+ if (value1 === undefined) {
34
+ return DiffType.CREATED;
35
+ }
36
+ if (value2 === undefined) {
37
+ return DiffType.DELETED;
38
+ }
39
+ return DiffType.UPDATED;
40
+ }
41
+ areEquivalentPrimitives(value1, value2) {
42
+ // Handle null and undefined
43
+ if (value1 == null && value2 == null) {
44
+ return true;
45
+ }
46
+ // Handle string trimming - if both are strings, compare trimmed versions
47
+ if (typeof value1 === 'string' && typeof value2 === 'string') {
48
+ return value1.trim() === value2.trim();
49
+ }
50
+ // Handle string/boolean coercion with specific string values
51
+ if ((typeof value1 === 'string' || typeof value1 === 'boolean') &&
52
+ (typeof value2 === 'string' || typeof value2 === 'boolean')) {
53
+ const val1 = typeof value1 === 'string' ? value1.trim().toLowerCase() : value1;
54
+ const val2 = typeof value2 === 'string' ? value2.trim().toLowerCase() : value2;
55
+ // Handle specific string-boolean equivalences
56
+ if (typeof val1 === 'string' && typeof val2 === 'boolean') {
57
+ if ((val1 === 'true' && val2 === true) || (val1 === 'false' && val2 === false)) {
58
+ return true;
59
+ }
60
+ // Handle empty string as false
61
+ if (val1 === '' && val2 === false) {
62
+ return true;
63
+ }
64
+ }
65
+ if (typeof val2 === 'string' && typeof val1 === 'boolean') {
66
+ if ((val2 === 'true' && val1 === true) || (val2 === 'false' && val1 === false)) {
67
+ return true;
68
+ }
69
+ // Handle empty string as false
70
+ if (val2 === '' && val1 === false) {
71
+ return true;
72
+ }
73
+ }
74
+ }
75
+ // Handle string/number coercion
76
+ if ((typeof value1 === 'string' || typeof value1 === 'number') &&
77
+ (typeof value2 === 'string' || typeof value2 === 'number')) {
78
+ // For string to number comparison, trim the string first
79
+ const str1 = typeof value1 === 'string' ? value1.trim() : value1.toString();
80
+ const str2 = typeof value2 === 'string' ? value2.trim() : value2.toString();
81
+ // Only treat truly empty strings (not whitespace-only) as equivalent to 0
82
+ // Distinguish between empty string ('') and whitespace-only strings (' ', ' ')
83
+ if (typeof value1 === 'string' && value1 === '' && typeof value2 === 'number') {
84
+ return value2 === 0;
85
+ }
86
+ if (typeof value2 === 'string' && value2 === '' && typeof value1 === 'number') {
87
+ return value1 === 0;
88
+ }
89
+ // Don't treat whitespace-only strings as equivalent to numbers
90
+ if (typeof value1 === 'string' && value1.trim() === '' && value1 !== '') {
91
+ return false; // ' ', ' ', etc. should not be equivalent to numbers
92
+ }
93
+ if (typeof value2 === 'string' && value2.trim() === '' && value2 !== '') {
94
+ return false; // ' ', ' ', etc. should not be equivalent to numbers
95
+ }
96
+ // Convert both to numbers and compare
97
+ const num1 = Number(str1);
98
+ const num2 = Number(str2);
99
+ // Handle NaN case specifically - only consider equal if both are exactly NaN
100
+ if (isNaN(num1) || isNaN(num2)) {
101
+ return Number.isNaN(value1) && Number.isNaN(value2);
102
+ }
103
+ if (!isNaN(num1) && !isNaN(num2)) {
104
+ return num1 === num2;
105
+ }
106
+ }
107
+ return false;
108
+ }
109
+ hasCircularReference(obj1, obj2) {
110
+ if (typeof obj1 !== 'object' || typeof obj2 !== 'object' || obj1 === null || obj2 === null) {
111
+ return false;
112
+ }
113
+ if (!this.visitedPairs.has(obj1)) {
114
+ this.visitedPairs.set(obj1, new WeakSet());
115
+ }
116
+ const visited = this.visitedPairs.get(obj1);
117
+ if (visited.has(obj2)) {
118
+ return true;
119
+ }
120
+ visited.add(obj2);
121
+ return false;
122
+ }
123
+ _map(obj1, obj2) {
124
+ if (this.isFunction(obj1) || this.isFunction(obj2)) {
125
+ throw new Error('Invalid argument. Function given, object expected.');
126
+ }
127
+ // Only treat as values if both are values, or if one is undefined and the other is also a value
128
+ // This prevents treating undefined vs complex object as a value comparison
129
+ if (this.isValue(obj1) && this.isValue(obj2)) {
130
+ const diffType = this.compareValues(obj1, obj2);
131
+ return {
132
+ type: diffType,
133
+ data: diffType === DiffType.CREATED ? obj2 : obj1
134
+ };
135
+ }
136
+ // Special case: one is undefined/null and the other is a complex object
137
+ if ((obj1 === undefined || obj1 === null) && (this.isArray(obj2) || this.isObject(obj2))) {
138
+ // Recursively process the non-undefined object as if it was created
139
+ return this._map({}, obj2);
140
+ }
141
+ if ((obj2 === undefined || obj2 === null) && (this.isArray(obj1) || this.isObject(obj1))) {
142
+ // Recursively process the non-undefined object as if it was deleted
143
+ return this._map(obj1, {});
144
+ }
145
+ // Handle primitive value cases (one or both are primitives but not both complex)
146
+ if (this.isValue(obj1) || this.isValue(obj2)) {
147
+ const diffType = this.compareValues(obj1, obj2);
148
+ return {
149
+ type: diffType,
150
+ data: diffType === DiffType.CREATED ? obj2 : obj1
151
+ };
152
+ }
153
+ // Check if both are complex types but of different specific types (array vs object)
154
+ const isArrayVsObject = (this.isArray(obj1) && this.isObject(obj2)) || (this.isObject(obj1) && this.isArray(obj2));
155
+ // For mixed types (array vs object), check if they have the same structure first
156
+ if (isArrayVsObject) {
157
+ // If both are empty, they're still different types
158
+ const keys1 = Object.keys(obj1 || {});
159
+ const keys2 = Object.keys(obj2 || {});
160
+ if (keys1.length === 0 && keys2.length === 0) {
161
+ return {
162
+ type: DiffType.UPDATED,
163
+ data: obj1
164
+ };
165
+ }
166
+ // Continue with property comparison for non-empty mixed types
167
+ }
168
+ // Check for circular references
169
+ if (this.hasCircularReference(obj1, obj2)) {
170
+ return {
171
+ type: DiffType.UNCHANGED,
172
+ data: obj1
173
+ };
174
+ }
175
+ const diff = {};
176
+ // Get all property keys including symbols and own properties
177
+ const getAllKeys = (obj) => {
178
+ if (!obj)
179
+ return [];
180
+ const keys = [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
181
+ // Include inherited enumerable properties
182
+ for (const key in obj) {
183
+ if (!keys.includes(key)) {
184
+ keys.push(key);
185
+ }
186
+ }
187
+ return keys;
188
+ };
189
+ const keys1 = getAllKeys(obj1);
190
+ const keys2 = getAllKeys(obj2);
191
+ const allKeys = new Set([...keys1, ...keys2]);
192
+ // Check if prototypes are different and add __proto__ to comparison
193
+ const proto1 = obj1 ? Object.getPrototypeOf(obj1) : null;
194
+ const proto2 = obj2 ? Object.getPrototypeOf(obj2) : null;
195
+ // Add __proto__ to comparison if prototypes differ
196
+ if (proto1 !== proto2) {
197
+ allKeys.add('__proto__');
198
+ }
199
+ // Check all properties from both objects
200
+ for (const key of allKeys) {
201
+ if (this.isFunction(obj1?.[key]) || this.isFunction(obj2?.[key])) {
202
+ continue;
203
+ }
204
+ let value1;
205
+ let value2;
206
+ // Special handling for __proto__
207
+ if (key === '__proto__') {
208
+ // We already know prototypes differ if we got here (since we added __proto__ to allKeys)
209
+ // For prototypes, we'll do a shallow comparison to avoid infinite recursion
210
+ if (proto1 === proto2) {
211
+ continue; // Should not happen since we only added this key when they differ
212
+ }
213
+ // Compare prototypes - treat default Object.prototype as "undefined" for comparison purposes
214
+ const isDefaultProto1 = proto1 === Object.prototype || proto1 === null;
215
+ const isDefaultProto2 = proto2 === Object.prototype || proto2 === null;
216
+ // If one has default prototype and other has custom, treat as create/delete
217
+ if (isDefaultProto1 && !isDefaultProto2) {
218
+ diff[key] = {
219
+ type: DiffType.CREATED,
220
+ data: proto2
221
+ };
222
+ continue;
223
+ }
224
+ if (!isDefaultProto1 && isDefaultProto2) {
225
+ diff[key] = {
226
+ type: DiffType.DELETED,
227
+ data: proto1
228
+ };
229
+ continue;
230
+ }
231
+ // Both have custom prototypes but they're different
232
+ if (!isDefaultProto1 && !isDefaultProto2 && proto1 !== proto2) {
233
+ diff[key] = {
234
+ type: DiffType.UPDATED,
235
+ data: proto1
236
+ };
237
+ continue;
238
+ }
239
+ }
240
+ else {
241
+ value1 = obj1?.[key];
242
+ value2 = obj2?.[key];
243
+ }
244
+ diff[key] = this._map(value1, value2);
245
+ }
246
+ return diff;
247
+ }
248
+ map(obj1, obj2) {
249
+ // Reset visited pairs for each new comparison
250
+ this.visitedPairs = new WeakMap();
251
+ return this._map(obj1, obj2);
252
+ }
253
+ compare(obj1, obj2) {
254
+ return this.map(obj1, obj2);
255
+ }
256
+ }
257
+ // Export singleton instance
258
+ export const deepDiffMapper = new DeepDiffMapper();
259
+ // Export class for custom instances if needed
260
+ export { DeepDiffMapper };
261
+ // Export convenience function
262
+ export function compareObjects(obj1, obj2) {
263
+ return deepDiffMapper.compare(obj1, obj2);
264
+ }
@@ -0,0 +1 @@
1
+ export * from './deepDiffMapper';
@@ -0,0 +1 @@
1
+ export * from './deepDiffMapper';
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Capitalizes the first letter of each word in a comma-separated string and adds a space after commas.
3
+ */
4
+ export declare const capitalizeFirstLetter: (input: string) => string;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Capitalizes the first letter of each word in a comma-separated string and adds a space after commas.
3
+ */
4
+ export const capitalizeFirstLetter = (input) => {
5
+ return input
6
+ .split(',')
7
+ .map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)
8
+ .join(', ');
9
+ };
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Generate a string with the current date and time in ISO format.
3
+ */
4
+ export declare const getTimeNow: () => string;
@@ -0,0 +1,8 @@
1
+ import { DateTime } from 'luxon';
2
+ /**
3
+ * Generate a string with the current date and time in ISO format.
4
+ */
5
+ export const getTimeNow = () => {
6
+ const now = DateTime.local();
7
+ return `${now.toFormat('MMMM d, yyyy, h:mma')}`;
8
+ };
@@ -1,6 +1,10 @@
1
+ export * from './capitalizeFirstLetter';
1
2
  export * from './cleanupTooltipMessage';
2
3
  export * from './goto';
4
+ export * from './getTimeNow';
5
+ export * from './minifyCode';
3
6
  export * from './noop';
4
7
  export * from './numbers';
5
8
  export * from './objectsToModuleExports';
6
9
  export * from './trimText';
10
+ export * from './toHumanReadableList';
@@ -1,6 +1,10 @@
1
+ export * from './capitalizeFirstLetter';
1
2
  export * from './cleanupTooltipMessage';
2
3
  export * from './goto';
4
+ export * from './getTimeNow';
5
+ export * from './minifyCode';
3
6
  export * from './noop';
4
7
  export * from './numbers';
5
8
  export * from './objectsToModuleExports';
6
9
  export * from './trimText';
10
+ export * from './toHumanReadableList';
@@ -0,0 +1,10 @@
1
+ import { type MinifyOptions } from 'terser';
2
+ /**
3
+ * Minifies the provided JavaScript code string.
4
+ */
5
+ export declare const minifyCode: (code: string, options?: MinifyOptions) => Promise<string>;
6
+ /**
7
+ * Core script as a string.
8
+ * TODO: temporary, migrate it to a re-usable util
9
+ */
10
+ export declare const createScriptContent: (coreScript: string) => string;
@@ -0,0 +1,73 @@
1
+ import { minify } from 'terser';
2
+ /**
3
+ * Minifies the provided JavaScript code string.
4
+ */
5
+ export const minifyCode = async (code, options) => {
6
+ try {
7
+ const result = await minify(code, options);
8
+ if (result.code) {
9
+ return result.code;
10
+ }
11
+ throw new Error('Minification failed: No output code produced.');
12
+ }
13
+ catch (error) {
14
+ if (error instanceof Error) {
15
+ // Handle specific Error object
16
+ throw new Error(`Minification error: ${error.message}`);
17
+ }
18
+ else {
19
+ // Handle unknown error types
20
+ throw new Error(`Unexpected error: ${String(error)}`);
21
+ }
22
+ }
23
+ };
24
+ /**
25
+ * Core script as a string.
26
+ * TODO: temporary, migrate it to a re-usable util
27
+ */
28
+ export const createScriptContent = (coreScript) => {
29
+ const scriptToAdd = `
30
+ const injectStyles = () => {
31
+ const curr = document.querySelector(\`style[fs-components-cloak]\`);
32
+ curr?.remove();
33
+ const cloak = document.createElement('style');
34
+ cloak.setAttribute('fs-components-cloak', 'cloak');
35
+ cloak.textContent = \`
36
+ [fs-marquee-instance],[fs-cnumbercount-instance]{ opacity: 0; }
37
+ [fs-consent-element="internal-component"],[fs-consent-element="banner"],[fs-consent-element="fixed-preferences"],[fs-consent-element="preferences"],[fs-consent-element="interaction"]{display:none}
38
+ \`;
39
+ document.head.appendChild(cloak);
40
+ };
41
+ const initFsComponents = async (url) => {
42
+ injectStyles();
43
+ // happens in-app, check to prevent script being invoked in-app
44
+ const configsLoading = window?.finsweetComponentsConfigLoading;
45
+
46
+ const found = document?.querySelector("script[fs-components-src]");
47
+ if (typeof import.meta !== "undefined" && !(found || configsLoading)) {
48
+ const corescript = document?.querySelector(
49
+ 'script[finsweet="components"][async][type="module"]'
50
+ );
51
+
52
+ const appConfigs = (await import(/* @vite-ignore */ import.meta.url));
53
+ const components = Object.keys(appConfigs) || [];
54
+
55
+ return new Promise((resolve, reject) => {
56
+ const script = document.createElement("script");
57
+ const srcUrl = url + "?v=" + new Date().getTime();
58
+ script.src = srcUrl;
59
+ script.type = "module";
60
+ script.async = true;
61
+ script.setAttribute("fs-components-src", import.meta.url);
62
+ script.setAttribute("fs-components-installed", components?.join(","));
63
+ script.onload = () => resolve();
64
+ script.onerror = () => reject(new Error("Failed to load script"));
65
+ document.head.appendChild(script);
66
+ });
67
+ }
68
+ };
69
+
70
+ // Load dev script
71
+ initFsComponents("${coreScript}");`;
72
+ return scriptToAdd;
73
+ };
@@ -3,5 +3,5 @@
3
3
  */
4
4
  export declare const objectsToModuleExports: (exportsArray: Array<{
5
5
  moduleName: string;
6
- data: object;
6
+ data: any;
7
7
  }>) => string;
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  /**
2
3
  * Converts an array of objects to module export statements.
3
4
  */
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Converts an array of strings into a human-readable list by adding commas and "and" before the last item.
3
+ */
4
+ export declare const toHumanReadableList: (arr: string[], conjunction?: string) => string;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Converts an array of strings into a human-readable list by adding commas and "and" before the last item.
3
+ */
4
+ export const toHumanReadableList = (arr, conjunction = 'and') => {
5
+ const len = arr.length;
6
+ if (len === 0)
7
+ return '';
8
+ if (len === 1)
9
+ return arr[0];
10
+ return `${arr.slice(0, -1).join(', ')} ${conjunction} ${arr[len - 1]}`;
11
+ };
@@ -1,8 +1,10 @@
1
+ export * from './animations';
1
2
  export * from './api';
2
3
  export * from './auth';
3
4
  export * from './browser-storage';
4
5
  export * from './constants';
5
6
  export * from './custom-code';
7
+ export * from './diff-mapper';
6
8
  export * from './helpers';
7
9
  export * from './logger';
8
10
  export * from './webflow-canvas';
@@ -1,8 +1,10 @@
1
+ export * from './animations';
1
2
  export * from './api';
2
3
  export * from './auth';
3
4
  export * from './browser-storage';
4
5
  export * from './constants';
5
6
  export * from './custom-code';
7
+ export * from './diff-mapper';
6
8
  export * from './helpers';
7
9
  export * from './logger';
8
10
  export * from './webflow-canvas';
@@ -0,0 +1,16 @@
1
+ export interface ElementChildren {
2
+ attribute: string | null;
3
+ customAttributes: NamedValue[] | null;
4
+ element: AnyElement;
5
+ parent: AnyElement | null;
6
+ }
7
+ /**
8
+ * Recursively fetches children elements and attributes.
9
+ *
10
+ * @param element - The root element.
11
+ * @param attributeName - The attribute name to fetch.
12
+ * @param parent - The parent of the current element.
13
+ * @param className - The class name to fetch.
14
+ * @returns - Promise of array containing elements and their children recursively.
15
+ */
16
+ export declare const getAllChildren: (element: AnyElement, attributeName?: string, parent?: AnyElement | null, className?: string) => Promise<ElementChildren[]>;
@@ -0,0 +1,65 @@
1
+ import { getWebflowElementAttribute } from './attributes';
2
+ /**
3
+ * Recursively fetches children elements and attributes.
4
+ *
5
+ * @param element - The root element.
6
+ * @param attributeName - The attribute name to fetch.
7
+ * @param parent - The parent of the current element.
8
+ * @param className - The class name to fetch.
9
+ * @returns - Promise of array containing elements and their children recursively.
10
+ */
11
+ export const getAllChildren = async (element, attributeName, parent, className = 'fs-consent') => {
12
+ let attribute = '';
13
+ let customAttributes = [];
14
+ if (attributeName) {
15
+ if (attributeName === 'wized' || attributeName === 'w-el') {
16
+ // wized may have old attribute name "w-el" so we check for both
17
+ attribute =
18
+ (await getWebflowElementAttribute(element, 'wized')) ||
19
+ (await getWebflowElementAttribute(element, 'w-el')) ||
20
+ null;
21
+ }
22
+ else {
23
+ attribute = (await getWebflowElementAttribute(element, attributeName)) || null;
24
+ }
25
+ }
26
+ if (element?.customAttributes) {
27
+ // Get All Custom Attributes
28
+ const attributesList = await element.getAllCustomAttributes();
29
+ if (attributesList) {
30
+ customAttributes = attributesList;
31
+ }
32
+ }
33
+ const children = element?.children ? await element?.getChildren() : [];
34
+ // const styles: ElementChildren['styles'] = [];
35
+ // if (element?.styles) {
36
+ // const stylesData = await element?.getStyles();
37
+ // const isArray = Array.isArray(stylesData);
38
+ // if (isArray && stylesData.length > 0) {
39
+ // for (const style of stylesData) {
40
+ // try {
41
+ // const name = (await style?.getName()) || undefined;
42
+ // const properties = (await style?.getProperties()) || undefined;
43
+ // if (name && properties && style) {
44
+ // styles.push({ style, name, properties });
45
+ // }
46
+ // } catch (error) {
47
+ // }
48
+ // }
49
+ // }
50
+ // }
51
+ const current = {
52
+ element,
53
+ parent: parent,
54
+ attribute,
55
+ customAttributes
56
+ // styles,
57
+ // defaultClassName: styles?.find((style) => style?.name?.includes(className))?.name || '',
58
+ };
59
+ if (children.length === 0) {
60
+ return [current];
61
+ }
62
+ const childrenArrays = await Promise.all(children.map((child) => getAllChildren(child, attributeName, element, className)));
63
+ const flattenedChildren = childrenArrays.flat();
64
+ return [current, ...flattenedChildren];
65
+ };
@@ -0,0 +1,9 @@
1
+ type ClassList = {
2
+ name: string;
3
+ style: Style;
4
+ };
5
+ /**
6
+ * Returns the class list of the element
7
+ */
8
+ export declare const getElementClassList: (element: AnyElement) => Promise<ClassList[]>;
9
+ export {};
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Returns the class list of the element
3
+ */
4
+ export const getElementClassList = async (element) => {
5
+ const classList = [];
6
+ if (element?.styles) {
7
+ const stylesData = await element.getStyles();
8
+ const isArray = Array.isArray(stylesData);
9
+ if (isArray) {
10
+ for (const style of stylesData) {
11
+ const clsName = await style?.getName();
12
+ if (style && clsName) {
13
+ classList.push({ name: clsName, style });
14
+ }
15
+ }
16
+ }
17
+ }
18
+ return classList?.filter(Boolean);
19
+ };
@@ -1,4 +1,6 @@
1
1
  export * from './attributes';
2
2
  export * from './findInstanceElement';
3
3
  export * from './getAllPages';
4
+ export * from './getAllChildren';
4
5
  export * from './getSiteStagingUrl';
6
+ export * from './getElementClassList';
@@ -1,4 +1,6 @@
1
1
  export * from './attributes';
2
2
  export * from './findInstanceElement';
3
3
  export * from './getAllPages';
4
+ export * from './getAllChildren';
4
5
  export * from './getSiteStagingUrl';
6
+ export * from './getElementClassList';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finsweet/webflow-apps-utils",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Shared utilities for Webflow apps",
5
5
  "homepage": "https://github.com/finsweet/webflow-apps-utils",
6
6
  "repository": {
@@ -51,6 +51,7 @@
51
51
  "@types/lodash": "^4.17.18",
52
52
  "@types/lodash-es": "^4.17.12",
53
53
  "@types/lodash.isequal": "^4.5.8",
54
+ "@types/luxon": "^3.6.2",
54
55
  "@types/node": "^22",
55
56
  "@vitest/browser": "3.2.3",
56
57
  "@vitest/coverage-v8": "3.2.3",
@@ -85,10 +86,13 @@
85
86
  "lodash-es": "^4.17.21",
86
87
  "lodash.isequal": "^4.5.0",
87
88
  "logrocket": "^10.1.0",
89
+ "luxon": "^3.6.1",
90
+ "motion": "^10.18.0",
88
91
  "overlayscrollbars": "^2.11.4",
89
92
  "overlayscrollbars-svelte": "^0.5.5",
90
93
  "svelte-routing": "^2.13.0",
91
94
  "swiper": "^11.2.8",
95
+ "terser": "^5.43.1",
92
96
  "uuid": "^11.1.0",
93
97
  "zod": "^3.25.64"
94
98
  },
@@ -96,6 +100,7 @@
96
100
  "dev": "vite dev",
97
101
  "build": "vite build && npm run prepack",
98
102
  "preview": "vite preview",
103
+ "watch": "svelte-kit sync && svelte-package --watch",
99
104
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
100
105
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
101
106
  "format": "prettier --write .",