@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
|
@@ -1,322 +0,0 @@
|
|
|
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
|
-
```
|
package/dist/router/README.md
DELETED
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
# Custom Svelte 5 Router
|
|
2
|
-
|
|
3
|
-
A lightweight, type-safe client-side router built specifically for Svelte 5 using runes. Designed to replace svelte-routing with modern reactivity patterns and support for persistent app version hashes.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- 🚀 **Svelte 5 Native**: Built with runes for optimal reactivity
|
|
8
|
-
- 🎯 **Type-Safe**: Full TypeScript support with comprehensive type definitions
|
|
9
|
-
- 📦 **Lightweight**: Minimal bundle size with no external dependencies
|
|
10
|
-
- 🔄 **Reactive**: All router state is reactive using Svelte 5 runes
|
|
11
|
-
- 🛣️ **Parameter Support**: URL parameters like `/users/:id`
|
|
12
|
-
- 🔍 **Query Params**: Built-in query parameter handling
|
|
13
|
-
- 🏠 **App Version Support**: Persistent app version hashes across navigation
|
|
14
|
-
- 📱 **Hash Mode**: Optional hash-based routing
|
|
15
|
-
- 🎣 **Rich Hooks**: Comprehensive set of utility hooks
|
|
16
|
-
- ♿ **Accessible**: Built-in accessibility features for navigation
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
The router is included in your project. Import from:
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
import { Router, RouterComponent, Route, Link } from './router';
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Quick Start
|
|
27
|
-
|
|
28
|
-
### 1. Create and Configure Router
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
// router.ts
|
|
32
|
-
import { createRouter } from './lib/router';
|
|
33
|
-
|
|
34
|
-
export const appRouter = createRouter({
|
|
35
|
-
autoInit: true
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// Export the router instance for use throughout the app
|
|
39
|
-
export default appRouter;
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### 2. Initialize with App Version
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
// In your app initialization
|
|
46
|
-
const awaitRouter = async () => {
|
|
47
|
-
const current = new URL(window.location.href);
|
|
48
|
-
const appVersionID = current.pathname.split('/')[1] || 'dev-mode';
|
|
49
|
-
|
|
50
|
-
// Initialize app version - this persists across all navigation
|
|
51
|
-
appRouter.initAppVersion(`/${appVersionID}`);
|
|
52
|
-
|
|
53
|
-
// Define routes without app version prefix
|
|
54
|
-
appRouter.addRoutes([
|
|
55
|
-
{ path: '/', component: MyComponentsLinks },
|
|
56
|
-
{ path: '/finsweetbuilder', component: BuilderLinks },
|
|
57
|
-
{ path: '/finsweetlibrary', component: LibraryLinks },
|
|
58
|
-
{ path: '/finsweetlibrary-admin', component: LibraryAdminLinks }
|
|
59
|
-
]);
|
|
60
|
-
|
|
61
|
-
// Update your existing router store
|
|
62
|
-
routerStore.set({
|
|
63
|
-
hash: appVersionID,
|
|
64
|
-
url: current
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### 3. Setup Router in Your App
|
|
70
|
-
|
|
71
|
-
```svelte
|
|
72
|
-
<!-- App.svelte -->
|
|
73
|
-
<script lang="ts">
|
|
74
|
-
import { RouterComponent, Route } from './lib/router';
|
|
75
|
-
import appRouter from './router.ts';
|
|
76
|
-
import { routerStore } from '@finsweet/components-utils';
|
|
77
|
-
|
|
78
|
-
const awaitRouter = async () => {
|
|
79
|
-
const current = new URL(window.location.href);
|
|
80
|
-
const appVersionID = current.pathname.split('/')[1] || 'dev-mode';
|
|
81
|
-
|
|
82
|
-
// Initialize app version - this persists across all navigation
|
|
83
|
-
appRouter.initAppVersion(`/${appVersionID}`);
|
|
84
|
-
|
|
85
|
-
// Update your existing router store
|
|
86
|
-
routerStore.set({
|
|
87
|
-
hash: appVersionID,
|
|
88
|
-
url: current
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// Update configurator if needed
|
|
92
|
-
configurator.update((state) => ({
|
|
93
|
-
...state,
|
|
94
|
-
pathname: current.pathname,
|
|
95
|
-
appVersionID: appVersionID
|
|
96
|
-
}));
|
|
97
|
-
|
|
98
|
-
await delay(50);
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// ... rest of your init logic
|
|
102
|
-
</script>
|
|
103
|
-
|
|
104
|
-
<!-- Replace your existing Router with RouterComponent -->
|
|
105
|
-
<RouterComponent router={appRouter}>
|
|
106
|
-
<!-- Define routes without app version prefix -->
|
|
107
|
-
<Route path="/" component={MyComponentsLinks} />
|
|
108
|
-
<Route path="/finsweetbuilder" component={BuilderLinks} />
|
|
109
|
-
<Route path="/finsweetlibrary" component={LibraryLinks} />
|
|
110
|
-
<Route path="/finsweetlibrary-admin" component={LibraryAdminLinks} />
|
|
111
|
-
|
|
112
|
-
<!-- Dynamic component routes -->
|
|
113
|
-
{#each $finsweetComponentsList as { solution, live, key }}
|
|
114
|
-
{#if live}
|
|
115
|
-
<Route path="/finsweetbuilder/{key}" component={solution} />
|
|
116
|
-
{/if}
|
|
117
|
-
{/each}
|
|
118
|
-
</RouterComponent>
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### 4. Navigate with Links
|
|
122
|
-
|
|
123
|
-
```svelte
|
|
124
|
-
<!-- LeftNavBarLinks.svelte -->
|
|
125
|
-
<script lang="ts">
|
|
126
|
-
import { Link, useAppVersion, useLocation } from '../lib/router';
|
|
127
|
-
|
|
128
|
-
const appVersionPath = useAppVersion();
|
|
129
|
-
const location = useLocation();
|
|
130
|
-
|
|
131
|
-
// Routes are now clean without app version prefix
|
|
132
|
-
const navLinks = [
|
|
133
|
-
{ path: '/', label: 'My Components', icon: ComponentsIcon },
|
|
134
|
-
{ path: '/finsweetbuilder', label: 'Builder', icon: BuilderIcon },
|
|
135
|
-
{ path: '/finsweetlibrary', label: 'Library', icon: FinsweetLibraryIcon }
|
|
136
|
-
];
|
|
137
|
-
</script>
|
|
138
|
-
|
|
139
|
-
<div class="nav-container">
|
|
140
|
-
{#each navLinks as link}
|
|
141
|
-
<Link to={link.path} activeClass="active" class="nav-links parent-link">
|
|
142
|
-
<svelte:component this={link.icon} />
|
|
143
|
-
<Text label={link.label} fontSize="normal" />
|
|
144
|
-
</Link>
|
|
145
|
-
{/each}
|
|
146
|
-
</div>
|
|
147
|
-
|
|
148
|
-
<style>
|
|
149
|
-
.active {
|
|
150
|
-
font-weight: bold;
|
|
151
|
-
color: blue;
|
|
152
|
-
}
|
|
153
|
-
</style>
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### 5. Use Router Hooks for Navigation
|
|
157
|
-
|
|
158
|
-
```svelte
|
|
159
|
-
<!-- BackNavLink.svelte -->
|
|
160
|
-
<script lang="ts">
|
|
161
|
-
import { useNavigate, useAppVersion } from '../lib/router';
|
|
162
|
-
|
|
163
|
-
export let fsComponent: string;
|
|
164
|
-
|
|
165
|
-
const navigate = useNavigate();
|
|
166
|
-
const appVersionPath = useAppVersion();
|
|
167
|
-
|
|
168
|
-
const goBack = () => {
|
|
169
|
-
// Navigate to builder page - app version is automatically included
|
|
170
|
-
navigate('/finsweetbuilder');
|
|
171
|
-
|
|
172
|
-
// Update your existing store if needed
|
|
173
|
-
const appVersionID = appVersionPath.slice(1); // Remove leading slash
|
|
174
|
-
routerStore.set({
|
|
175
|
-
hash: appVersionID,
|
|
176
|
-
url: new URL(`${appVersionPath}/finsweetbuilder`, window.location.origin)
|
|
177
|
-
});
|
|
178
|
-
};
|
|
179
|
-
</script>
|
|
180
|
-
|
|
181
|
-
<div class="nav-links-wrapper">
|
|
182
|
-
<Section clickable onclick={goBack}>
|
|
183
|
-
<!-- ... rest of your template -->
|
|
184
|
-
</Section>
|
|
185
|
-
</div>
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
## Core Concepts
|
|
189
|
-
|
|
190
|
-
### App Version Hash Support
|
|
191
|
-
|
|
192
|
-
The router's key feature is maintaining app version hashes across all navigation:
|
|
193
|
-
|
|
194
|
-
```typescript
|
|
195
|
-
// Once initialized, all routes automatically include the app version
|
|
196
|
-
appRouter.initAppVersion('/test-app-hash');
|
|
197
|
-
|
|
198
|
-
// These routes work automatically with app version:
|
|
199
|
-
navigate('/'); // Goes to /test-app-hash/
|
|
200
|
-
navigate('/finsweetbuilder'); // Goes to /test-app-hash/finsweetbuilder
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
### Links with App Version
|
|
204
|
-
|
|
205
|
-
Links automatically include the app version prefix:
|
|
206
|
-
|
|
207
|
-
```svelte
|
|
208
|
-
<!-- These automatically include the app version prefix -->
|
|
209
|
-
<Link to="/">Home</Link>
|
|
210
|
-
<!-- Renders as href="/test-app-hash/" -->
|
|
211
|
-
|
|
212
|
-
<Link to="/finsweetbuilder">Builder</Link>
|
|
213
|
-
<!-- Renders as href="/test-app-hash/finsweetbuilder" -->
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### App Version Utility Hooks
|
|
217
|
-
|
|
218
|
-
```svelte
|
|
219
|
-
<script lang="ts">
|
|
220
|
-
import { useAppVersion, useFullPathname, useLocation } from './router';
|
|
221
|
-
|
|
222
|
-
const appVersionPath = useAppVersion(); // Returns '/test-app-hash'
|
|
223
|
-
const fullPathname = useFullPathname(); // Returns '/test-app-hash/users/123'
|
|
224
|
-
const location = useLocation(); // location.pathname is clean: '/users/123'
|
|
225
|
-
</script>
|
|
226
|
-
|
|
227
|
-
<p>App Version: {appVersionPath}</p>
|
|
228
|
-
<p>Full Path: {fullPathname}</p>
|
|
229
|
-
<p>Clean Path: {location.pathname}</p>
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Working with Route Parameters
|
|
233
|
-
|
|
234
|
-
```svelte
|
|
235
|
-
<!-- UserDetail.svelte -->
|
|
236
|
-
<script lang="ts">
|
|
237
|
-
import { useParams, useNavigate, useLocation } from './router';
|
|
238
|
-
|
|
239
|
-
const params = useParams();
|
|
240
|
-
const navigate = useNavigate();
|
|
241
|
-
const location = useLocation();
|
|
242
|
-
|
|
243
|
-
// Reactive access to route parameters
|
|
244
|
-
$: userId = params.id;
|
|
245
|
-
|
|
246
|
-
function goBack() {
|
|
247
|
-
navigate('/users');
|
|
248
|
-
}
|
|
249
|
-
</script>
|
|
250
|
-
|
|
251
|
-
<h1>User {userId}</h1>
|
|
252
|
-
<button onclick={goBack}>Back to Users</button>
|
|
253
|
-
<p>Current path: {location.pathname}</p>
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
### Component Modal Updates
|
|
257
|
-
|
|
258
|
-
```svelte
|
|
259
|
-
<!-- NewComponent.svelte -->
|
|
260
|
-
<script lang="ts">
|
|
261
|
-
import { useNavigate } from '../lib/router';
|
|
262
|
-
|
|
263
|
-
const navigate = useNavigate();
|
|
264
|
-
|
|
265
|
-
const handleBuilderClick = () => {
|
|
266
|
-
// Navigate to builder - app version automatically included
|
|
267
|
-
navigate('/finsweetbuilder');
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const handleLibraryClick = () => {
|
|
271
|
-
// Navigate to library - app version automatically included
|
|
272
|
-
navigate('/finsweetlibrary');
|
|
273
|
-
};
|
|
274
|
-
</script>
|
|
275
|
-
|
|
276
|
-
<!-- Navigation calls with new navigate function -->
|
|
277
|
-
<WebflowTooltip>
|
|
278
|
-
<div slot="tooltip">
|
|
279
|
-
<Section clickable on:click={handleBuilderClick}>
|
|
280
|
-
<!-- Builder option -->
|
|
281
|
-
</Section>
|
|
282
|
-
<Section clickable on:click={handleLibraryClick}>
|
|
283
|
-
<!-- Library option -->
|
|
284
|
-
</Section>
|
|
285
|
-
</div>
|
|
286
|
-
</WebflowTooltip>
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
## API Reference
|
|
290
|
-
|
|
291
|
-
### Router Class
|
|
292
|
-
|
|
293
|
-
```typescript
|
|
294
|
-
const router = createRouter({
|
|
295
|
-
basePath: '/app', // Optional base path
|
|
296
|
-
hashMode: false, // Use hash-based routing
|
|
297
|
-
fallbackRoute: '/404', // Fallback for unmatched routes
|
|
298
|
-
autoInit: true // Auto-initialize in browser
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// Methods
|
|
302
|
-
router.navigate('/path', { replace: false, state: {} });
|
|
303
|
-
router.addRoute({ path: '/users/:id', component: UserComponent });
|
|
304
|
-
router.addRoutes([...routes]);
|
|
305
|
-
router.initAppVersion('/app-version'); // Set persistent app version
|
|
306
|
-
router.isActive('/path', (exact = false));
|
|
307
|
-
router.getParams();
|
|
308
|
-
router.getQuery();
|
|
309
|
-
router.back();
|
|
310
|
-
router.forward();
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### Hooks
|
|
314
|
-
|
|
315
|
-
```typescript
|
|
316
|
-
// Get router instance
|
|
317
|
-
const router = useRouter();
|
|
318
|
-
|
|
319
|
-
// Reactive location information
|
|
320
|
-
const location = useLocation();
|
|
321
|
-
|
|
322
|
-
// Current route information
|
|
323
|
-
const route = useRoute();
|
|
324
|
-
|
|
325
|
-
// Route parameters
|
|
326
|
-
const params = useParams();
|
|
327
|
-
|
|
328
|
-
// Query parameters
|
|
329
|
-
const query = useQuery();
|
|
330
|
-
|
|
331
|
-
// Navigation function
|
|
332
|
-
const navigate = useNavigate();
|
|
333
|
-
|
|
334
|
-
// Check if path is active
|
|
335
|
-
const isActive = useIsActiveRoute();
|
|
336
|
-
|
|
337
|
-
// App version utilities
|
|
338
|
-
const appVersionPath = useAppVersion();
|
|
339
|
-
const fullPathname = useFullPathname();
|
|
340
|
-
|
|
341
|
-
// Navigation state
|
|
342
|
-
const isNavigating = useNavigating();
|
|
343
|
-
|
|
344
|
-
// History tracking
|
|
345
|
-
const history = useHistory();
|
|
346
|
-
|
|
347
|
-
// Search params helper
|
|
348
|
-
const search = useSearchParams();
|
|
349
|
-
search.set('page', '2');
|
|
350
|
-
search.get('page');
|
|
351
|
-
search.delete('page');
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
### Components
|
|
355
|
-
|
|
356
|
-
#### RouterComponent
|
|
357
|
-
|
|
358
|
-
```svelte
|
|
359
|
-
<RouterComponent {router} autoInit={true}>
|
|
360
|
-
<!-- Route components go here -->
|
|
361
|
-
</RouterComponent>
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
#### Route
|
|
365
|
-
|
|
366
|
-
```svelte
|
|
367
|
-
<Route path="/users/:id" component={UserComponent} exact={true} meta={{ requiresAuth: true }} />
|
|
368
|
-
|
|
369
|
-
<!-- Or with slot content -->
|
|
370
|
-
<Route path="/about">
|
|
371
|
-
<AboutPage />
|
|
372
|
-
</Route>
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
#### Link
|
|
376
|
-
|
|
377
|
-
```svelte
|
|
378
|
-
<Link
|
|
379
|
-
to="/users/123"
|
|
380
|
-
activeClass="active"
|
|
381
|
-
exact={false}
|
|
382
|
-
replace={false}
|
|
383
|
-
disabled={false}
|
|
384
|
-
element="a">View User</Link
|
|
385
|
-
>
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
## Key Benefits
|
|
389
|
-
|
|
390
|
-
1. **Persistent App Version**: Once `initAppVersion` is called, the app version hash persists across all navigation
|
|
391
|
-
2. **Clean Route Definitions**: Define routes without app version prefixes (`/finsweetbuilder` instead of `/{appVersionID}/finsweetbuilder`)
|
|
392
|
-
3. **Automatic URL Generation**: Links and navigation automatically include the app version prefix
|
|
393
|
-
4. **Backward Compatibility**: Works with your existing `routerStore` and other components
|
|
394
|
-
5. **Type Safety**: Full TypeScript support with proper typing
|
|
395
|
-
6. **Modern Reactivity**: Built on Svelte 5 runes for optimal performance
|
|
396
|
-
|
|
397
|
-
The router handles all the app version complexity automatically while maintaining compatibility with your existing application structure and providing a modern, type-safe routing solution for Svelte 5.
|
|
File without changes
|