@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.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/providers/GlobalProvider.stories.d.ts +5 -0
- package/dist/providers/GlobalProvider.stories.js +419 -0
- package/dist/providers/GlobalProviderDemo.svelte +266 -0
- package/dist/providers/GlobalProviderDemo.svelte.d.ts +3 -0
- package/dist/providers/configuratorUtils.d.ts +11 -14
- package/dist/providers/configuratorUtils.js +68 -115
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.js +1 -1
- package/dist/router/Router.stories.d.ts +6 -0
- package/dist/router/Router.stories.js +564 -0
- package/dist/router/examples/RouterExample.svelte +271 -0
- package/dist/router/examples/RouterExample.svelte.d.ts +18 -0
- package/dist/router/examples/index.d.ts +4 -0
- package/dist/router/examples/index.js +4 -0
- package/dist/router/examples/pages/AboutPage.svelte +568 -0
- package/dist/router/examples/pages/AboutPage.svelte.d.ts +13 -0
- package/dist/router/examples/pages/HomePage.svelte +200 -0
- package/dist/router/examples/pages/HomePage.svelte.d.ts +14 -0
- package/dist/router/examples/pages/NotFoundPage.svelte +307 -0
- package/dist/router/examples/pages/NotFoundPage.svelte.d.ts +17 -0
- package/dist/router/hooks.svelte.d.ts +2 -2
- package/dist/router/index.d.ts +3 -0
- package/dist/router/index.js +3 -0
- package/dist/router/{Link.svelte → providers/Link.svelte} +1 -1
- package/dist/router/{Route.svelte → providers/Route.svelte} +1 -1
- package/dist/router/{Route.svelte.d.ts → providers/Route.svelte.d.ts} +1 -1
- package/dist/router/{Router.svelte → providers/RouterProvider.svelte} +22 -5
- package/dist/router/{Router.svelte.d.ts → providers/RouterProvider.svelte.d.ts} +8 -4
- package/dist/router/providers/index.d.ts +3 -0
- package/dist/router/providers/index.js +3 -0
- package/dist/router/{index.svelte.d.ts → router.svelte.d.ts} +1 -3
- package/dist/router/{index.svelte.js → router.svelte.js} +1 -4
- package/dist/stores/forms/Form.stories.d.ts +5 -0
- package/dist/stores/forms/Form.stories.js +342 -0
- package/dist/stores/forms/FormDemo.svelte +545 -0
- package/dist/stores/forms/FormDemo.svelte.d.ts +18 -0
- package/dist/stores/forms.d.ts +41 -4
- package/dist/stores/forms.js +86 -32
- package/dist/types/customCode.d.ts +1 -1
- package/dist/types/window.d.ts +1 -0
- package/dist/ui/components/button/Button.svelte +1 -1
- package/dist/ui/components/copy-text/CopyText.stories.d.ts +70 -0
- package/dist/ui/components/copy-text/CopyText.stories.js +241 -0
- package/dist/ui/components/copy-text/CopyText.svelte +247 -0
- package/dist/ui/components/copy-text/CopyText.svelte.d.ts +4 -0
- package/dist/ui/components/copy-text/index.d.ts +2 -0
- package/dist/ui/components/copy-text/index.js +1 -0
- package/dist/ui/components/copy-text/types.d.ts +52 -0
- package/dist/ui/components/copy-text/types.js +1 -0
- package/dist/ui/components/index.d.ts +1 -0
- package/dist/ui/components/index.js +1 -0
- package/dist/ui/components/input/Input.stories.d.ts +9 -0
- package/dist/ui/components/input/Input.stories.js +78 -0
- package/dist/ui/components/input/Input.svelte +39 -3
- package/dist/ui/components/input/types.d.ts +6 -0
- package/dist/ui/components/layout/Layout.svelte +45 -64
- package/dist/ui/components/layout/Layout.svelte.d.ts +26 -3
- package/dist/ui/components/layout/examples/ExampleLayout.svelte +32 -27
- package/dist/ui/components/layout/index.d.ts +1 -1
- package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte +20 -0
- package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte.d.ts +7 -0
- package/dist/ui/components/layout/types.d.ts +1 -10
- package/dist/ui/components/notification/Notification.stories.svelte +12 -1
- package/dist/ui/components/notification/Notification.svelte +10 -5
- package/dist/ui/components/notification/Notification.svelte.d.ts +1 -1
- package/dist/ui/components/notification/types.d.ts +1 -1
- package/dist/ui/components/section/Section.svelte +8 -4
- package/dist/ui/components/section/types.d.ts +8 -0
- package/dist/ui/components/text/Text.stories.svelte +67 -1
- package/dist/ui/components/text/Text.svelte +209 -8
- package/dist/ui/components/text/types.d.ts +4 -0
- package/dist/ui/index.css +6 -2
- package/dist/utils/animations/factory.d.ts +7 -0
- package/dist/utils/animations/factory.js +101 -0
- package/dist/utils/animations/index.d.ts +7 -0
- package/dist/utils/animations/index.js +62 -0
- package/dist/utils/animations/types.d.ts +39 -0
- package/dist/utils/animations/types.js +1 -0
- package/dist/utils/custom-code/configs.d.ts +22 -0
- package/dist/utils/custom-code/configs.js +40 -0
- package/dist/utils/custom-code/index.d.ts +1 -0
- package/dist/utils/custom-code/index.js +1 -0
- package/dist/utils/diff-mapper/DiffMapper.stories.d.ts +5 -0
- package/dist/utils/diff-mapper/DiffMapper.stories.js +185 -0
- package/dist/utils/diff-mapper/DiffMapperDemo.svelte +351 -0
- package/dist/utils/diff-mapper/DiffMapperDemo.svelte.d.ts +18 -0
- package/dist/utils/diff-mapper/deepDiffMapper.d.ts +31 -0
- package/dist/utils/diff-mapper/deepDiffMapper.js +264 -0
- package/dist/utils/diff-mapper/index.d.ts +1 -0
- package/dist/utils/diff-mapper/index.js +1 -0
- package/dist/utils/helpers/capitalizeFirstLetter.d.ts +4 -0
- package/dist/utils/helpers/capitalizeFirstLetter.js +9 -0
- package/dist/utils/helpers/getTimeNow.d.ts +4 -0
- package/dist/utils/helpers/getTimeNow.js +8 -0
- package/dist/utils/helpers/index.d.ts +4 -0
- package/dist/utils/helpers/index.js +4 -0
- package/dist/utils/helpers/minifyCode.d.ts +10 -0
- package/dist/utils/helpers/minifyCode.js +73 -0
- package/dist/utils/helpers/objectsToModuleExports.d.ts +1 -1
- package/dist/utils/helpers/objectsToModuleExports.js +1 -0
- package/dist/utils/helpers/toHumanReadableList.d.ts +4 -0
- package/dist/utils/helpers/toHumanReadableList.js +11 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/webflow-canvas/getAllChildren.d.ts +16 -0
- package/dist/utils/webflow-canvas/getAllChildren.js +65 -0
- package/dist/utils/webflow-canvas/getElementClassList.d.ts +9 -0
- package/dist/utils/webflow-canvas/getElementClassList.js +19 -0
- package/dist/utils/webflow-canvas/index.d.ts +2 -0
- package/dist/utils/webflow-canvas/index.js +2 -0
- package/package.json +6 -1
- package/dist/providers/GlobalProvider.mdx +0 -322
- package/dist/router/README.md +0 -397
- /package/dist/router/{Link.svelte.d.ts → providers/Link.svelte.d.ts} +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import DiffMapperDemo from './DiffMapperDemo.svelte';
|
|
2
|
+
const meta = {
|
|
3
|
+
title: 'Utils/DiffMapper',
|
|
4
|
+
component: DiffMapperDemo,
|
|
5
|
+
parameters: {
|
|
6
|
+
layout: 'centered',
|
|
7
|
+
backgrounds: {
|
|
8
|
+
default: 'dark',
|
|
9
|
+
values: [
|
|
10
|
+
{ name: 'dark', value: '#292929' },
|
|
11
|
+
{ name: 'light', value: '#ffffff' }
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
docs: {
|
|
15
|
+
description: {
|
|
16
|
+
component: `
|
|
17
|
+
# DiffMapper Utilities
|
|
18
|
+
|
|
19
|
+
The DiffMapper utility provides intelligent object comparison with type coercion, whitespace handling, and advanced diff detection. Built specifically for configurator state management and general object comparison needs.
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- **Smart Type Coercion**: Handles string/number/boolean conversions intelligently
|
|
24
|
+
- **Whitespace Handling**: Automatically trims and compares string values
|
|
25
|
+
- **Deep Comparison**: Recursively compares nested objects and arrays
|
|
26
|
+
- **Performance Optimized**: Includes caching and circular reference detection
|
|
27
|
+
- **Detailed Diff Output**: Provides granular change information
|
|
28
|
+
- **Type Safety**: Full TypeScript support with proper type definitions
|
|
29
|
+
|
|
30
|
+
## API Reference
|
|
31
|
+
|
|
32
|
+
### Core Functions
|
|
33
|
+
|
|
34
|
+
#### \`hasChangesViaDiff<T>(current: T, updated: T): boolean\`
|
|
35
|
+
|
|
36
|
+
Determines if there are any meaningful changes between two objects.
|
|
37
|
+
|
|
38
|
+
\`\`\`typescript
|
|
39
|
+
const config1 = { theme: 'dark', notifications: true };
|
|
40
|
+
const config2 = { theme: 'light', notifications: true };
|
|
41
|
+
|
|
42
|
+
const hasChanges = hasChangesViaDiff(config1, config2); // true
|
|
43
|
+
\`\`\`
|
|
44
|
+
|
|
45
|
+
**Features:**
|
|
46
|
+
- Automatic caching for performance
|
|
47
|
+
- Type coercion handling
|
|
48
|
+
- Whitespace normalization
|
|
49
|
+
- Deep nested comparison
|
|
50
|
+
|
|
51
|
+
#### \`getDetailedDiff<T>(current: T, updated: T): DiffResult | DiffMap\`
|
|
52
|
+
|
|
53
|
+
Returns a detailed diff map showing exactly what changed.
|
|
54
|
+
|
|
55
|
+
\`\`\`typescript
|
|
56
|
+
const user1 = {
|
|
57
|
+
profile: { name: 'John', age: 30 },
|
|
58
|
+
settings: { theme: 'dark' }
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const user2 = {
|
|
62
|
+
profile: { name: 'John', age: 31 },
|
|
63
|
+
settings: { theme: 'light', notifications: true }
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const diff = getDetailedDiff(user1, user2);
|
|
67
|
+
// Returns detailed diff structure showing exactly what changed
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
### Diff Types
|
|
71
|
+
|
|
72
|
+
\`\`\`typescript
|
|
73
|
+
enum DiffType {
|
|
74
|
+
UNCHANGED = 'UNCHANGED', // Value is identical
|
|
75
|
+
UPDATED = 'UPDATED', // Value was modified
|
|
76
|
+
CREATED = 'CREATED', // Property was added
|
|
77
|
+
DELETED = 'DELETED' // Property was removed
|
|
78
|
+
}
|
|
79
|
+
\`\`\`
|
|
80
|
+
|
|
81
|
+
## Type Coercion Examples
|
|
82
|
+
|
|
83
|
+
The diff mapper intelligently handles type coercion:
|
|
84
|
+
|
|
85
|
+
### String/Number Coercion
|
|
86
|
+
\`\`\`typescript
|
|
87
|
+
// These are considered UNCHANGED
|
|
88
|
+
hasChangesViaDiff({ value: '42' }, { value: 42 }); // false
|
|
89
|
+
hasChangesViaDiff({ value: '0' }, { value: 0 }); // false
|
|
90
|
+
hasChangesViaDiff({ value: '' }, { value: 0 }); // false
|
|
91
|
+
\`\`\`
|
|
92
|
+
|
|
93
|
+
### String/Boolean Coercion
|
|
94
|
+
\`\`\`typescript
|
|
95
|
+
// These are considered UNCHANGED
|
|
96
|
+
hasChangesViaDiff({ active: 'true' }, { active: true }); // false
|
|
97
|
+
hasChangesViaDiff({ active: 'false' }, { active: false }); // false
|
|
98
|
+
hasChangesViaDiff({ active: '' }, { active: false }); // false
|
|
99
|
+
\`\`\`
|
|
100
|
+
|
|
101
|
+
### Whitespace Handling
|
|
102
|
+
\`\`\`typescript
|
|
103
|
+
// These are considered UNCHANGED
|
|
104
|
+
hasChangesViaDiff({ name: 'John' }, { name: ' John ' }); // false
|
|
105
|
+
hasChangesViaDiff({ value: '42' }, { value: ' 42 ' }); // false
|
|
106
|
+
|
|
107
|
+
// But these are UPDATED (whitespace-only strings ≠ numbers)
|
|
108
|
+
hasChangesViaDiff({ value: ' ' }, { value: 0 }); // true
|
|
109
|
+
hasChangesViaDiff({ value: ' ' }, { value: false }); // true
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
## Performance Features
|
|
113
|
+
|
|
114
|
+
### Caching Strategy
|
|
115
|
+
Results are cached for 1 second to avoid expensive re-computation:
|
|
116
|
+
|
|
117
|
+
\`\`\`typescript
|
|
118
|
+
const cacheKey = JSON.stringify([current, updated]);
|
|
119
|
+
const cached = diffCache.get(cacheKey);
|
|
120
|
+
|
|
121
|
+
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
|
|
122
|
+
return cached.result;
|
|
123
|
+
}
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
### Memory Management
|
|
127
|
+
Automatic cache cleanup when size exceeds 100 entries or TTL expires.
|
|
128
|
+
|
|
129
|
+
## GlobalProvider Integration
|
|
130
|
+
|
|
131
|
+
The diff mapper is seamlessly integrated with the GlobalProvider system:
|
|
132
|
+
|
|
133
|
+
\`\`\`typescript
|
|
134
|
+
import { useConfiguratorContext } from '../../providers';
|
|
135
|
+
|
|
136
|
+
const configurator = useConfiguratorContext<MyConfigType>();
|
|
137
|
+
|
|
138
|
+
// Automatic change detection using diff mapper
|
|
139
|
+
const hasChanged = configurator.hasChanged; // Uses hasChangesViaDiff internally
|
|
140
|
+
|
|
141
|
+
// Manual comparison
|
|
142
|
+
const currentConfig = configurator.configurator;
|
|
143
|
+
const cachedConfig = configurator.configuratorCache;
|
|
144
|
+
const changes = getDetailedDiff(currentConfig, cachedConfig);
|
|
145
|
+
\`\`\`
|
|
146
|
+
|
|
147
|
+
## Usage with GlobalProvider
|
|
148
|
+
|
|
149
|
+
For manual configurator state management:
|
|
150
|
+
|
|
151
|
+
\`\`\`typescript
|
|
152
|
+
import {
|
|
153
|
+
createDefaultConfiguratorState,
|
|
154
|
+
hasConfiguratorChanged,
|
|
155
|
+
validateWatchOptions,
|
|
156
|
+
extractKeys,
|
|
157
|
+
createDebouncedUpdate
|
|
158
|
+
} from '../../providers';
|
|
159
|
+
|
|
160
|
+
// Create default configurator state
|
|
161
|
+
const defaultState = createDefaultConfiguratorState<MyConfigType>();
|
|
162
|
+
|
|
163
|
+
// Manual change detection with watch options
|
|
164
|
+
const watchOptions = { watchKeys: ['theme'], debounceMs: 100 };
|
|
165
|
+
const hasChanged = hasConfiguratorChanged(current, cached, watchOptions);
|
|
166
|
+
\`\`\`
|
|
167
|
+
|
|
168
|
+
Click the buttons in the interactive demo below to see these features in action!
|
|
169
|
+
`
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
tags: ['autodocs']
|
|
174
|
+
};
|
|
175
|
+
export default meta;
|
|
176
|
+
export const Interactive = {
|
|
177
|
+
name: 'Interactive Demo',
|
|
178
|
+
parameters: {
|
|
179
|
+
docs: {
|
|
180
|
+
description: {
|
|
181
|
+
story: 'Click the buttons to run diff examples and see results. All functionality is combined in a single interactive demo.'
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getDetailedDiff, hasChangesViaDiff } from '../../providers/configuratorUtils';
|
|
3
|
+
|
|
4
|
+
let output = '';
|
|
5
|
+
let coercionExamples = '';
|
|
6
|
+
let performanceResults = '';
|
|
7
|
+
let deepOutput = '';
|
|
8
|
+
|
|
9
|
+
function runDiffExamples() {
|
|
10
|
+
// Example 1: Basic object comparison
|
|
11
|
+
const obj1 = { name: 'John', age: 30, active: 'true' };
|
|
12
|
+
const obj2 = { name: 'John', age: 31, active: true };
|
|
13
|
+
|
|
14
|
+
// @ts-expect-error - intentional type mismatch for demo
|
|
15
|
+
const hasChanges = hasChangesViaDiff(obj1, obj2);
|
|
16
|
+
// @ts-expect-error - intentional type mismatch for demo
|
|
17
|
+
const detailedDiff = getDetailedDiff(obj1, obj2);
|
|
18
|
+
|
|
19
|
+
// Example 2: Nested object comparison
|
|
20
|
+
const nested1 = {
|
|
21
|
+
user: { profile: { name: 'John', settings: { theme: 'dark' } } },
|
|
22
|
+
items: [{ id: 1, name: 'Item 1' }]
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const nested2 = {
|
|
26
|
+
user: { profile: { name: 'John', settings: { theme: 'light' } } },
|
|
27
|
+
items: [
|
|
28
|
+
{ id: 1, name: 'Item 1' },
|
|
29
|
+
{ id: 2, name: 'Item 2' }
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const nestedChanges = hasChangesViaDiff(nested1, nested2);
|
|
34
|
+
const nestedDiff = getDetailedDiff(nested1, nested2);
|
|
35
|
+
|
|
36
|
+
// Example 3: Type coercion examples
|
|
37
|
+
const coercion1 = { count: '5', enabled: '', value: '0' };
|
|
38
|
+
const coercion2 = { count: 5, enabled: false, value: 0 };
|
|
39
|
+
// @ts-expect-error - intentional type mismatch for demo
|
|
40
|
+
const coercionChanges = hasChangesViaDiff(coercion1, coercion2);
|
|
41
|
+
|
|
42
|
+
output = `
|
|
43
|
+
📊 DIFF MAPPER RESULTS
|
|
44
|
+
|
|
45
|
+
1. Basic Object Comparison:
|
|
46
|
+
Object 1: ${JSON.stringify(obj1)}
|
|
47
|
+
Object 2: ${JSON.stringify(obj2)}
|
|
48
|
+
Has Changes: ${hasChanges}
|
|
49
|
+
Age changed from 30 to 31, but 'true' === true (type coercion)
|
|
50
|
+
|
|
51
|
+
2. Nested Object Comparison:
|
|
52
|
+
Has Changes: ${nestedChanges}
|
|
53
|
+
Theme changed from 'dark' to 'light'
|
|
54
|
+
New item added to array
|
|
55
|
+
|
|
56
|
+
3. Type Coercion Examples:
|
|
57
|
+
Object 1: ${JSON.stringify(coercion1)}
|
|
58
|
+
Object 2: ${JSON.stringify(coercion2)}
|
|
59
|
+
Has Changes: ${coercionChanges}
|
|
60
|
+
All values are equivalent due to intelligent type coercion!
|
|
61
|
+
|
|
62
|
+
📝 Check the browser console for detailed diff objects.
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
// Log detailed results to console
|
|
66
|
+
console.group('🔍 DiffMapper Detailed Results');
|
|
67
|
+
console.log('Basic diff:', detailedDiff);
|
|
68
|
+
console.log('Nested diff:', nestedDiff);
|
|
69
|
+
console.groupEnd();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function generateCoercionExamples() {
|
|
73
|
+
const examples = [
|
|
74
|
+
[{ value: '42' }, { value: 42 }, 'String "42" equals number 42'],
|
|
75
|
+
[{ active: 'true' }, { active: true }, 'String "true" equals boolean true'],
|
|
76
|
+
[{ empty: '' }, { empty: 0 }, 'Empty string equals number 0'],
|
|
77
|
+
[{ name: 'John' }, { name: ' John ' }, 'Whitespace is trimmed'],
|
|
78
|
+
[{ enabled: 'false' }, { enabled: false }, 'String "false" equals boolean false']
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
let html = '<div style="display: grid; gap: 10px;">';
|
|
82
|
+
|
|
83
|
+
examples.forEach(([obj1, obj2, description]) => {
|
|
84
|
+
const hasChanges = hasChangesViaDiff(obj1, obj2);
|
|
85
|
+
const status = hasChanges ? '❌ DIFFERENT' : '✅ SAME';
|
|
86
|
+
const color = hasChanges ? 'var(--redText)' : 'var(--greenText)';
|
|
87
|
+
|
|
88
|
+
html += `
|
|
89
|
+
<div class="coercion-example">
|
|
90
|
+
<div style="color: ${color}; font-weight: var(--font-weight-medium); margin-bottom: var(--spacing-4);">${status}</div>
|
|
91
|
+
<div style="color: var(--text1);"><strong>A:</strong> ${JSON.stringify(obj1)}</div>
|
|
92
|
+
<div style="color: var(--text1);"><strong>B:</strong> ${JSON.stringify(obj2)}</div>
|
|
93
|
+
<div style="color: var(--text3); font-style: italic; margin-top: var(--spacing-4);">${description}</div>
|
|
94
|
+
</div>
|
|
95
|
+
`;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
html += '</div>';
|
|
99
|
+
coercionExamples = html;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function runPerformanceTest() {
|
|
103
|
+
// Create large objects for testing
|
|
104
|
+
const createLargeObject = (size: number) => {
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
106
|
+
const obj: Record<string, any> = {};
|
|
107
|
+
for (let i = 0; i < size; i++) {
|
|
108
|
+
obj[`key${i}`] = {
|
|
109
|
+
id: i,
|
|
110
|
+
name: `Item ${i}`,
|
|
111
|
+
nested: {
|
|
112
|
+
value: Math.random(),
|
|
113
|
+
timestamp: Date.now()
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return obj;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const obj1 = createLargeObject(100);
|
|
121
|
+
const obj2 = { ...obj1 };
|
|
122
|
+
obj2.key50.nested.value = 999; // Change one value
|
|
123
|
+
|
|
124
|
+
// Measure performance
|
|
125
|
+
const start = performance.now();
|
|
126
|
+
const hasChanges = hasChangesViaDiff(obj1, obj2);
|
|
127
|
+
const end = performance.now();
|
|
128
|
+
|
|
129
|
+
// Test caching - second call should be faster
|
|
130
|
+
const start2 = performance.now();
|
|
131
|
+
hasChangesViaDiff(obj1, obj2);
|
|
132
|
+
const end2 = performance.now();
|
|
133
|
+
|
|
134
|
+
performanceResults = `
|
|
135
|
+
<div class="performance-result">
|
|
136
|
+
<h4>Performance Test Results</h4>
|
|
137
|
+
<div><strong>Object Size:</strong> 100 nested objects</div>
|
|
138
|
+
<div><strong>Change Detected:</strong> ${hasChanges ? 'Yes' : 'No'}</div>
|
|
139
|
+
<div><strong>First Call:</strong> ${(end - start).toFixed(2)}ms</div>
|
|
140
|
+
<div><strong>Cached Call:</strong> ${(end2 - start2).toFixed(2)}ms</div>
|
|
141
|
+
<div style="color: var(--greenText); margin-top: var(--spacing-12); font-weight: var(--font-weight-medium);">
|
|
142
|
+
⚡ ${((end - start) / (end2 - start2)).toFixed(1)}x faster with caching!
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
`;
|
|
146
|
+
|
|
147
|
+
console.log('Performance test completed:', {
|
|
148
|
+
hasChanges,
|
|
149
|
+
firstCall: end - start,
|
|
150
|
+
cachedCall: end2 - start2,
|
|
151
|
+
speedup: (end - start) / (end2 - start2)
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function runDeepTest() {
|
|
156
|
+
const deepObj1 = {
|
|
157
|
+
level1: {
|
|
158
|
+
level2: {
|
|
159
|
+
level3: {
|
|
160
|
+
level4: {
|
|
161
|
+
data: 'original',
|
|
162
|
+
count: 42,
|
|
163
|
+
items: [1, 2, 3]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const deepObj2 = {
|
|
171
|
+
level1: {
|
|
172
|
+
level2: {
|
|
173
|
+
level3: {
|
|
174
|
+
level4: {
|
|
175
|
+
data: 'modified',
|
|
176
|
+
count: 42,
|
|
177
|
+
items: [1, 2, 3, 4]
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const hasChanges = hasChangesViaDiff(deepObj1, deepObj2);
|
|
185
|
+
const diff = getDetailedDiff(deepObj1, deepObj2);
|
|
186
|
+
|
|
187
|
+
deepOutput = `
|
|
188
|
+
Deep Object Comparison Results:
|
|
189
|
+
|
|
190
|
+
Has Changes: ${hasChanges}
|
|
191
|
+
|
|
192
|
+
Changes detected:
|
|
193
|
+
- level1.level2.level3.level4.data: "original" → "modified"
|
|
194
|
+
- level1.level2.level3.level4.items: Array length changed (3 → 4)
|
|
195
|
+
|
|
196
|
+
The diff mapper successfully navigated 4 levels deep to detect specific changes!
|
|
197
|
+
|
|
198
|
+
See console for the complete diff structure.
|
|
199
|
+
`;
|
|
200
|
+
|
|
201
|
+
console.log('Deep nesting diff:', diff);
|
|
202
|
+
}
|
|
203
|
+
</script>
|
|
204
|
+
|
|
205
|
+
<div class="demo-container">
|
|
206
|
+
<h3>DiffMapper Utilities Demo</h3>
|
|
207
|
+
<p>Open the browser console to see diff results.</p>
|
|
208
|
+
<button class="btn btn--primary" onclick={runDiffExamples}>Run Diff Examples</button>
|
|
209
|
+
<pre class="output-block">{output}</pre>
|
|
210
|
+
|
|
211
|
+
<hr class="divider" />
|
|
212
|
+
|
|
213
|
+
<h3>Type Coercion Examples</h3>
|
|
214
|
+
<button class="btn btn--primary" onclick={generateCoercionExamples}>Show Type Coercion</button>
|
|
215
|
+
<div class="examples-container">
|
|
216
|
+
{@html coercionExamples}
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
<hr class="divider" />
|
|
220
|
+
|
|
221
|
+
<h3>Performance Features</h3>
|
|
222
|
+
<button class="btn btn--primary" onclick={runPerformanceTest}>Run Performance Test</button>
|
|
223
|
+
<div class="results-container">
|
|
224
|
+
{@html performanceResults}
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
<hr class="divider" />
|
|
228
|
+
|
|
229
|
+
<h3>Deep Nesting Comparison</h3>
|
|
230
|
+
<button class="btn btn--primary" onclick={runDeepTest}>Test Deep Objects</button>
|
|
231
|
+
<pre class="output-block small">{deepOutput}</pre>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<style>
|
|
235
|
+
.demo-container {
|
|
236
|
+
padding: var(--spacing-24);
|
|
237
|
+
font-family: var(--font-stack);
|
|
238
|
+
background: var(--background1);
|
|
239
|
+
color: var(--text1);
|
|
240
|
+
max-width: 800px;
|
|
241
|
+
margin: 0 auto;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
h3 {
|
|
245
|
+
color: var(--text1);
|
|
246
|
+
font-size: var(--font-size-large);
|
|
247
|
+
font-weight: var(--font-weight-medium);
|
|
248
|
+
margin: var(--spacing-16) 0 var(--spacing-8) 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
p {
|
|
252
|
+
color: var(--text2);
|
|
253
|
+
font-size: var(--font-size-small);
|
|
254
|
+
margin: var(--spacing-8) 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.btn {
|
|
258
|
+
padding: var(--padding-small) var(--padding-regular);
|
|
259
|
+
border: none;
|
|
260
|
+
border-radius: var(--border-radius);
|
|
261
|
+
cursor: pointer;
|
|
262
|
+
font-size: var(--font-size-small);
|
|
263
|
+
font-weight: var(--font-weight-normal);
|
|
264
|
+
font-family: var(--font-stack);
|
|
265
|
+
transition: all 0.2s ease;
|
|
266
|
+
margin: var(--spacing-8) 0;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.btn--primary {
|
|
270
|
+
background: var(--actionPrimaryBackground);
|
|
271
|
+
color: var(--actionPrimaryText);
|
|
272
|
+
box-shadow: var(--boxShadows-action-colored);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.btn--primary:hover {
|
|
276
|
+
background: var(--actionPrimaryBackgroundHover);
|
|
277
|
+
color: var(--actionPrimaryTextHover);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.output-block {
|
|
281
|
+
background: var(--background2);
|
|
282
|
+
border: 1px solid var(--border2);
|
|
283
|
+
padding: var(--spacing-12);
|
|
284
|
+
margin-top: var(--spacing-12);
|
|
285
|
+
white-space: pre-wrap;
|
|
286
|
+
border-radius: var(--border-radius);
|
|
287
|
+
font-family: monospace;
|
|
288
|
+
color: var(--text2);
|
|
289
|
+
font-size: var(--font-size-small);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.output-block.small {
|
|
293
|
+
font-size: var(--font-size-small);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.divider {
|
|
297
|
+
border: none;
|
|
298
|
+
border-top: 1px solid var(--border2);
|
|
299
|
+
margin: var(--spacing-32) 0;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.examples-container,
|
|
303
|
+
.results-container {
|
|
304
|
+
margin-top: var(--spacing-16);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* Dynamic HTML content styling */
|
|
308
|
+
:global(.examples-container > div) {
|
|
309
|
+
display: grid;
|
|
310
|
+
gap: var(--spacing-12);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
:global(.coercion-example) {
|
|
314
|
+
padding: var(--spacing-12);
|
|
315
|
+
border: 1px solid var(--border2);
|
|
316
|
+
border-radius: var(--border-radius);
|
|
317
|
+
background: var(--background2);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
:global(.performance-result) {
|
|
321
|
+
background: var(--background2);
|
|
322
|
+
border: 1px solid var(--border2);
|
|
323
|
+
padding: var(--spacing-16);
|
|
324
|
+
border-radius: var(--border-radius);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
:global(.results-container > div) {
|
|
328
|
+
background: var(--background2);
|
|
329
|
+
border: 1px solid var(--border2);
|
|
330
|
+
padding: var(--spacing-16);
|
|
331
|
+
border-radius: var(--border-radius);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
:global(.results-container h4) {
|
|
335
|
+
color: var(--text1);
|
|
336
|
+
font-size: var(--font-size-large);
|
|
337
|
+
font-weight: var(--font-weight-medium);
|
|
338
|
+
margin: 0 0 var(--spacing-8) 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
:global(.results-container div) {
|
|
342
|
+
color: var(--text2);
|
|
343
|
+
font-size: var(--font-size-small);
|
|
344
|
+
margin: var(--spacing-4) 0;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
:global(.results-container strong) {
|
|
348
|
+
color: var(--text1);
|
|
349
|
+
font-weight: var(--font-weight-medium);
|
|
350
|
+
}
|
|
351
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const DiffMapperDemo: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type DiffMapperDemo = InstanceType<typeof DiffMapperDemo>;
|
|
18
|
+
export default DiffMapperDemo;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare enum DiffType {
|
|
2
|
+
CREATED = "created",
|
|
3
|
+
UPDATED = "updated",
|
|
4
|
+
DELETED = "deleted",
|
|
5
|
+
UNCHANGED = "unchanged"
|
|
6
|
+
}
|
|
7
|
+
export interface DiffResult {
|
|
8
|
+
type: DiffType;
|
|
9
|
+
data: any;
|
|
10
|
+
}
|
|
11
|
+
export type DiffMap = {
|
|
12
|
+
[key: string]: DiffResult | DiffMap;
|
|
13
|
+
};
|
|
14
|
+
export type ComparableValue = any;
|
|
15
|
+
declare class DeepDiffMapper {
|
|
16
|
+
private visitedPairs;
|
|
17
|
+
private isFunction;
|
|
18
|
+
private isArray;
|
|
19
|
+
private isDate;
|
|
20
|
+
private isObject;
|
|
21
|
+
private isValue;
|
|
22
|
+
private compareValues;
|
|
23
|
+
private areEquivalentPrimitives;
|
|
24
|
+
private hasCircularReference;
|
|
25
|
+
private _map;
|
|
26
|
+
map(obj1: ComparableValue, obj2: ComparableValue): DiffResult | DiffMap;
|
|
27
|
+
compare(obj1: ComparableValue, obj2: ComparableValue): DiffResult | DiffMap;
|
|
28
|
+
}
|
|
29
|
+
export declare const deepDiffMapper: DeepDiffMapper;
|
|
30
|
+
export { DeepDiffMapper };
|
|
31
|
+
export declare function compareObjects(obj1: ComparableValue, obj2: ComparableValue): DiffResult | DiffMap;
|