@finsweet/webflow-apps-utils 1.0.3 → 1.0.4
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/router/Router.mdx +958 -0
- package/dist/router/Router.stories.d.ts +6 -0
- package/dist/router/Router.stories.js +47 -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/docs/Form.mdx +542 -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/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 +249 -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 +7 -59
- package/dist/ui/components/layout/Layout.svelte.d.ts +2 -2
- package/dist/ui/components/layout/examples/ExampleLayout.svelte +22 -17
- 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 +4 -2
- 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/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/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 +1 -0
- package/dist/utils/index.js +1 -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/router/README.md +0 -397
- /package/dist/router/{Link.svelte.d.ts → providers/Link.svelte.d.ts} +0 -0
|
@@ -0,0 +1,958 @@
|
|
|
1
|
+
# Router API Documentation
|
|
2
|
+
|
|
3
|
+
A comprehensive client-side router for Svelte 5 applications with support for reactive state management, dynamic routing, and app version persistence.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Core Classes](#core-classes)
|
|
9
|
+
- [Router](#router)
|
|
10
|
+
- [createRouter()](#createrouter)
|
|
11
|
+
- [Components](#components)
|
|
12
|
+
- [RouterProvider](#routerprovider)
|
|
13
|
+
- [Route](#route)
|
|
14
|
+
- [Link](#link)
|
|
15
|
+
- [Hooks](#hooks)
|
|
16
|
+
- [Interfaces](#interfaces)
|
|
17
|
+
- [Examples](#examples)
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import {
|
|
23
|
+
createRouter,
|
|
24
|
+
RouterProvider,
|
|
25
|
+
Route,
|
|
26
|
+
Link,
|
|
27
|
+
useRouter,
|
|
28
|
+
useLocation,
|
|
29
|
+
useNavigate
|
|
30
|
+
} from '@finsweet/webflow-apps-utils';
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Core Classes
|
|
34
|
+
|
|
35
|
+
### Router
|
|
36
|
+
|
|
37
|
+
The main router class that handles navigation, route matching, and state management.
|
|
38
|
+
|
|
39
|
+
#### Constructor
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
new Router(config?: RouterConfig)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
#### Configuration Options
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
interface RouterConfig {
|
|
49
|
+
basePath?: string; // Base path for all routes (default: '')
|
|
50
|
+
hashMode?: boolean; // Use hash-based routing (default: false)
|
|
51
|
+
fallbackRoute?: string; // Fallback route when no match (default: '/')
|
|
52
|
+
autoInit?: boolean; // Auto-initialize on creation (default: true)
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Methods
|
|
57
|
+
|
|
58
|
+
##### Navigation Methods
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Navigate to a path
|
|
62
|
+
navigate(pathname: string, options?: { replace?: boolean; state?: any }): void
|
|
63
|
+
|
|
64
|
+
// Navigate back in history
|
|
65
|
+
back(): void
|
|
66
|
+
|
|
67
|
+
// Navigate forward in history
|
|
68
|
+
forward(): void
|
|
69
|
+
|
|
70
|
+
// Navigate to root path
|
|
71
|
+
gotoRootPath(): void
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
##### Route Management
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Add a single route
|
|
78
|
+
addRoute(route: RouteConfig): void
|
|
79
|
+
|
|
80
|
+
// Add multiple routes
|
|
81
|
+
addRoutes(routes: RouteConfig[]): void
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
##### State Access Methods
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// Get reactive location information
|
|
88
|
+
useLocation(): LocationInfo
|
|
89
|
+
|
|
90
|
+
// Get reactive current route
|
|
91
|
+
useRoute(): RouteConfig | null
|
|
92
|
+
|
|
93
|
+
// Get reactive navigation state
|
|
94
|
+
useNavigating(): boolean
|
|
95
|
+
|
|
96
|
+
// Get reactive navigation history
|
|
97
|
+
useHistory(): HistoryEntry[]
|
|
98
|
+
|
|
99
|
+
// Check if path is active
|
|
100
|
+
isActive(path: string, exact?: boolean): boolean
|
|
101
|
+
|
|
102
|
+
// Get current route parameters
|
|
103
|
+
getParams(): RouteParams
|
|
104
|
+
|
|
105
|
+
// Get current query parameters
|
|
106
|
+
getQuery(): URLSearchParams
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
##### App Version Methods
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// Initialize app version path persistence
|
|
113
|
+
initAppVersion(appVersionPath: string): void
|
|
114
|
+
|
|
115
|
+
// Get current app version path
|
|
116
|
+
getAppVersionPath(): string
|
|
117
|
+
|
|
118
|
+
// Get full pathname including app version
|
|
119
|
+
getFullPathname(): string
|
|
120
|
+
|
|
121
|
+
// Get active path with app version
|
|
122
|
+
getActivePath(): string
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
##### Lifecycle Methods
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// Initialize the router
|
|
129
|
+
init(): void
|
|
130
|
+
|
|
131
|
+
// Clean up and destroy router
|
|
132
|
+
destroy(): void
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### Example Usage
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { createRouter } from '@finsweet/webflow-apps-utils';
|
|
139
|
+
|
|
140
|
+
// Create router with configuration
|
|
141
|
+
const router = createRouter({
|
|
142
|
+
basePath: '/app',
|
|
143
|
+
hashMode: false,
|
|
144
|
+
fallbackRoute: '/home',
|
|
145
|
+
autoInit: true
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Add routes
|
|
149
|
+
router.addRoutes([
|
|
150
|
+
{ path: '/', component: HomePage, meta: { title: 'Home' } },
|
|
151
|
+
{ path: '/users/:id', component: UserPage, meta: { title: 'User Profile' } },
|
|
152
|
+
{ path: '/about', component: AboutPage, meta: { title: 'About' } }
|
|
153
|
+
]);
|
|
154
|
+
|
|
155
|
+
// Initialize app version for persistence
|
|
156
|
+
router.initAppVersion('/v1');
|
|
157
|
+
|
|
158
|
+
// Navigate programmatically
|
|
159
|
+
router.navigate('/users/123');
|
|
160
|
+
router.navigate('/about', { replace: true, state: { from: 'home' } });
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### createRouter()
|
|
164
|
+
|
|
165
|
+
Factory function to create a new router instance.
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
function createRouter(config?: RouterConfig): Router;
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### Example
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const router = createRouter({
|
|
175
|
+
basePath: '/my-app',
|
|
176
|
+
fallbackRoute: '/dashboard'
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Components
|
|
181
|
+
|
|
182
|
+
### RouterProvider
|
|
183
|
+
|
|
184
|
+
Root component that provides router context to child components and manages router lifecycle.
|
|
185
|
+
|
|
186
|
+
#### Props
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
interface RouterProviderProps {
|
|
190
|
+
router: Router; // Router instance
|
|
191
|
+
autoInit?: boolean; // Auto-initialize router (default: true)
|
|
192
|
+
loading?: boolean; // Show loading screen
|
|
193
|
+
loadingMessage?: string; // Loading message text
|
|
194
|
+
children?: Snippet<[RouterContext]>; // Children with router context
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface RouterContext {
|
|
198
|
+
router: Router;
|
|
199
|
+
currentRoute: RouteConfig | null;
|
|
200
|
+
currentLocation: LocationInfo;
|
|
201
|
+
isNavigating: boolean;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### Example
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
<script lang="ts">
|
|
209
|
+
import { createRouter, RouterProvider } from '@finsweet/webflow-apps-utils';
|
|
210
|
+
|
|
211
|
+
const router = createRouter();
|
|
212
|
+
</script>
|
|
213
|
+
|
|
214
|
+
<RouterProvider {router} loading={false}>
|
|
215
|
+
{#snippet children({ router, currentRoute, currentLocation, isNavigating })}
|
|
216
|
+
<nav>
|
|
217
|
+
<!-- Navigation content -->
|
|
218
|
+
</nav>
|
|
219
|
+
|
|
220
|
+
<main class:navigating={isNavigating}>
|
|
221
|
+
<!-- Route content -->
|
|
222
|
+
</main>
|
|
223
|
+
{/snippet}
|
|
224
|
+
</RouterProvider>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Route
|
|
228
|
+
|
|
229
|
+
Component for defining and rendering routes based on path patterns.
|
|
230
|
+
|
|
231
|
+
#### Props
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
interface RouteProps {
|
|
235
|
+
path: string; // Path pattern (supports :params)
|
|
236
|
+
component?: any; // Component to render when active
|
|
237
|
+
meta?: Record<string, any>; // Route metadata
|
|
238
|
+
exact?: boolean; // Exact path matching (default: true)
|
|
239
|
+
children?: Snippet<[RouteContext]>; // Children with route context
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
interface RouteContext {
|
|
243
|
+
params: Record<string, string>; // Route parameters
|
|
244
|
+
location: LocationInfo; // Current location
|
|
245
|
+
router: Router; // Router instance
|
|
246
|
+
isActive: boolean; // Whether route is active
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### Example
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
<!-- Using component prop -->
|
|
254
|
+
<Route path="/users/:id" component={UserProfile} />
|
|
255
|
+
|
|
256
|
+
<!-- Using children snippet -->
|
|
257
|
+
<Route path="/dashboard">
|
|
258
|
+
{#snippet children({ params, location, router, isActive })}
|
|
259
|
+
{#if isActive}
|
|
260
|
+
<Dashboard userId={params.id} />
|
|
261
|
+
{/if}
|
|
262
|
+
{/snippet}
|
|
263
|
+
</Route>
|
|
264
|
+
|
|
265
|
+
<!-- Wildcard route for 404 -->
|
|
266
|
+
<Route path="*" exact={false}>
|
|
267
|
+
{#snippet children({ isActive })}
|
|
268
|
+
{#if isActive}
|
|
269
|
+
<NotFoundPage />
|
|
270
|
+
{/if}
|
|
271
|
+
{/snippet}
|
|
272
|
+
</Route>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Link
|
|
276
|
+
|
|
277
|
+
Navigation component that generates proper links with active state management.
|
|
278
|
+
|
|
279
|
+
#### Props
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
interface LinkProps {
|
|
283
|
+
to: string; // Target path
|
|
284
|
+
replace?: boolean; // Replace history entry (default: false)
|
|
285
|
+
activeClass?: string; // CSS class when active
|
|
286
|
+
exact?: boolean; // Exact matching for active state
|
|
287
|
+
disabled?: boolean; // Disable the link
|
|
288
|
+
class?: string; // Additional CSS classes
|
|
289
|
+
state?: any; // State to pass with navigation
|
|
290
|
+
element?: 'a' | 'button'; // HTML element type (default: 'a')
|
|
291
|
+
children?: Snippet; // Link content
|
|
292
|
+
onclick?: (event: MouseEvent) => void; // Click handler
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### Example
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
<!-- Basic link -->
|
|
300
|
+
<Link to="/about">About Us</Link>
|
|
301
|
+
|
|
302
|
+
<!-- Link with active styling -->
|
|
303
|
+
<Link to="/dashboard" activeClass="nav-active" exact>
|
|
304
|
+
Dashboard
|
|
305
|
+
</Link>
|
|
306
|
+
|
|
307
|
+
<!-- Button-style link -->
|
|
308
|
+
<Link to="/settings" element="button" class="btn btn-primary">
|
|
309
|
+
Settings
|
|
310
|
+
</Link>
|
|
311
|
+
|
|
312
|
+
<!-- Link with custom click handler -->
|
|
313
|
+
<Link
|
|
314
|
+
to="/profile"
|
|
315
|
+
onclick={(e) => console.log('Navigating to profile')}
|
|
316
|
+
>
|
|
317
|
+
My Profile
|
|
318
|
+
</Link>
|
|
319
|
+
|
|
320
|
+
<!-- Disabled link -->
|
|
321
|
+
<Link to="/admin" disabled>
|
|
322
|
+
Admin Panel
|
|
323
|
+
</Link>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Hooks
|
|
327
|
+
|
|
328
|
+
### useRouter()
|
|
329
|
+
|
|
330
|
+
Get the router instance from context.
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
function useRouter(): Router;
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
#### Example
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
<script lang="ts">
|
|
340
|
+
import { useRouter } from '@finsweet/webflow-apps-utils';
|
|
341
|
+
|
|
342
|
+
const router = useRouter();
|
|
343
|
+
|
|
344
|
+
function handleLogout() {
|
|
345
|
+
router.navigate('/login', { replace: true });
|
|
346
|
+
}
|
|
347
|
+
</script>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### useLocation()
|
|
351
|
+
|
|
352
|
+
Get reactive location information.
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
function useLocation(): LocationInfo;
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### Example
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
<script lang="ts">
|
|
362
|
+
import { useLocation } from '@finsweet/webflow-apps-utils';
|
|
363
|
+
|
|
364
|
+
const location = useLocation();
|
|
365
|
+
</script>
|
|
366
|
+
|
|
367
|
+
<div>
|
|
368
|
+
Current path: {location.pathname}
|
|
369
|
+
Query params: {location.search}
|
|
370
|
+
Route params: {JSON.stringify(location.params)}
|
|
371
|
+
</div>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### useRoute()
|
|
375
|
+
|
|
376
|
+
Get reactive current route information.
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
function useRoute(): RouteConfig | null;
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### Example
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
<script lang="ts">
|
|
386
|
+
import { useRoute } from '@finsweet/webflow-apps-utils';
|
|
387
|
+
|
|
388
|
+
const route = useRoute();
|
|
389
|
+
</script>
|
|
390
|
+
|
|
391
|
+
{#if route}
|
|
392
|
+
<title>{route.meta?.title || 'My App'}</title>
|
|
393
|
+
{/if}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### useParams()
|
|
397
|
+
|
|
398
|
+
Get reactive route parameters.
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
function useParams(): RouteParams;
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
#### Example
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
<script lang="ts">
|
|
408
|
+
import { useParams } from '@finsweet/webflow-apps-utils';
|
|
409
|
+
|
|
410
|
+
const params = useParams();
|
|
411
|
+
|
|
412
|
+
$: userId = params.id;
|
|
413
|
+
</script>
|
|
414
|
+
|
|
415
|
+
<h1>User Profile: {userId}</h1>
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### useQuery()
|
|
419
|
+
|
|
420
|
+
Get reactive query parameters.
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
function useQuery(): URLSearchParams;
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
#### Example
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
<script lang="ts">
|
|
430
|
+
import { useQuery } from '@finsweet/webflow-apps-utils';
|
|
431
|
+
|
|
432
|
+
const query = useQuery();
|
|
433
|
+
|
|
434
|
+
$: page = query.get('page') || '1';
|
|
435
|
+
$: sort = query.get('sort') || 'name';
|
|
436
|
+
</script>
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### useNavigate()
|
|
440
|
+
|
|
441
|
+
Get a navigation function.
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
function useNavigate(): (pathname: string, options?: NavigateOptions) => void;
|
|
445
|
+
|
|
446
|
+
interface NavigateOptions {
|
|
447
|
+
replace?: boolean;
|
|
448
|
+
state?: any;
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
#### Example
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
<script lang="ts">
|
|
456
|
+
import { useNavigate } from '@finsweet/webflow-apps-utils';
|
|
457
|
+
|
|
458
|
+
const navigate = useNavigate();
|
|
459
|
+
|
|
460
|
+
function goToProfile() {
|
|
461
|
+
navigate('/profile');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function goToSettings() {
|
|
465
|
+
navigate('/settings', { replace: true });
|
|
466
|
+
}
|
|
467
|
+
</script>
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### useNavigating()
|
|
471
|
+
|
|
472
|
+
Get reactive navigation state.
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
function useNavigating(): boolean;
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
#### Example
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
<script lang="ts">
|
|
482
|
+
import { useNavigating } from '@finsweet/webflow-apps-utils';
|
|
483
|
+
|
|
484
|
+
const isNavigating = useNavigating();
|
|
485
|
+
</script>
|
|
486
|
+
|
|
487
|
+
{#if isNavigating}
|
|
488
|
+
<div class="loading-spinner">Navigating...</div>
|
|
489
|
+
{/if}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### useHistory()
|
|
493
|
+
|
|
494
|
+
Get reactive navigation history.
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
function useHistory(): HistoryEntry[];
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
#### Example
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
<script lang="ts">
|
|
504
|
+
import { useHistory } from '@finsweet/webflow-apps-utils';
|
|
505
|
+
|
|
506
|
+
const history = useHistory();
|
|
507
|
+
</script>
|
|
508
|
+
|
|
509
|
+
<div>
|
|
510
|
+
<h3>Navigation History:</h3>
|
|
511
|
+
{#each history.slice(-5) as entry}
|
|
512
|
+
<div>{entry.pathname} - {new Date(entry.timestamp).toLocaleTimeString()}</div>
|
|
513
|
+
{/each}
|
|
514
|
+
</div>
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### useIsActiveRoute()
|
|
518
|
+
|
|
519
|
+
Get a function to check if routes are active.
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
function useIsActiveRoute(): (path: string, exact?: boolean) => boolean;
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
#### Example
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
<script lang="ts">
|
|
529
|
+
import { useIsActiveRoute } from '@finsweet/webflow-apps-utils';
|
|
530
|
+
|
|
531
|
+
const isActive = useIsActiveRoute();
|
|
532
|
+
</script>
|
|
533
|
+
|
|
534
|
+
<nav>
|
|
535
|
+
<a href="/home" class:active={isActive('/home')}>Home</a>
|
|
536
|
+
<a href="/about" class:active={isActive('/about')}>About</a>
|
|
537
|
+
</nav>
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### useRouteWatcher()
|
|
541
|
+
|
|
542
|
+
Watch for route changes and execute callbacks.
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
function useRouteWatcher(
|
|
546
|
+
callback: (location: LocationInfo, route: RouteConfig | null) => void,
|
|
547
|
+
immediate?: boolean
|
|
548
|
+
): void;
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
#### Example
|
|
552
|
+
|
|
553
|
+
```typescript
|
|
554
|
+
<script lang="ts">
|
|
555
|
+
import { useRouteWatcher } from '@finsweet/webflow-apps-utils';
|
|
556
|
+
|
|
557
|
+
useRouteWatcher((location, route) => {
|
|
558
|
+
console.log('Route changed:', location.pathname);
|
|
559
|
+
|
|
560
|
+
// Update page title
|
|
561
|
+
if (route?.meta?.title) {
|
|
562
|
+
document.title = route.meta.title;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Analytics tracking
|
|
566
|
+
analytics.track('page_view', { path: location.pathname });
|
|
567
|
+
});
|
|
568
|
+
</script>
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### useSearchParams()
|
|
572
|
+
|
|
573
|
+
Get search params helper with reactive updates.
|
|
574
|
+
|
|
575
|
+
```typescript
|
|
576
|
+
function useSearchParams(): SearchParamsHelper;
|
|
577
|
+
|
|
578
|
+
interface SearchParamsHelper {
|
|
579
|
+
get(key: string): string | null;
|
|
580
|
+
set(key: string, value: string): void;
|
|
581
|
+
delete(key: string): void;
|
|
582
|
+
has(key: string): boolean;
|
|
583
|
+
toString(): string;
|
|
584
|
+
getAll(): Record<string, string>;
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
#### Example
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
<script lang="ts">
|
|
592
|
+
import { useSearchParams } from '@finsweet/webflow-apps-utils';
|
|
593
|
+
|
|
594
|
+
const searchParams = useSearchParams();
|
|
595
|
+
|
|
596
|
+
function updatePage(page: number) {
|
|
597
|
+
searchParams.set('page', page.toString());
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
function clearFilters() {
|
|
601
|
+
searchParams.delete('filter');
|
|
602
|
+
searchParams.delete('sort');
|
|
603
|
+
}
|
|
604
|
+
</script>
|
|
605
|
+
|
|
606
|
+
<div>
|
|
607
|
+
Current page: {searchParams.get('page') || '1'}
|
|
608
|
+
<button onclick={() => updatePage(2)}>Go to Page 2</button>
|
|
609
|
+
<button onclick={clearFilters}>Clear Filters</button>
|
|
610
|
+
</div>
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### useAppVersion()
|
|
614
|
+
|
|
615
|
+
Get the current app version path.
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
function useAppVersion(): string;
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
#### Example
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
<script lang="ts">
|
|
625
|
+
import { useAppVersion } from '@finsweet/webflow-apps-utils';
|
|
626
|
+
|
|
627
|
+
const appVersion = useAppVersion();
|
|
628
|
+
</script>
|
|
629
|
+
|
|
630
|
+
<div>App Version: {appVersion}</div>
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### useFullPathname()
|
|
634
|
+
|
|
635
|
+
Get the full pathname including app version.
|
|
636
|
+
|
|
637
|
+
```typescript
|
|
638
|
+
function useFullPathname(): string;
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
#### Example
|
|
642
|
+
|
|
643
|
+
```typescript
|
|
644
|
+
<script lang="ts">
|
|
645
|
+
import { useFullPathname } from '@finsweet/webflow-apps-utils';
|
|
646
|
+
|
|
647
|
+
const fullPathname = useFullPathname();
|
|
648
|
+
</script>
|
|
649
|
+
|
|
650
|
+
<div>Full URL Path: {fullPathname}</div>
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
## Interfaces
|
|
654
|
+
|
|
655
|
+
### RouteConfig
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
interface RouteConfig {
|
|
659
|
+
path: string; // Path pattern ('/users/:id')
|
|
660
|
+
component?: any; // Svelte component
|
|
661
|
+
meta?: Record<string, any>; // Route metadata
|
|
662
|
+
}
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### LocationInfo
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
interface LocationInfo {
|
|
669
|
+
pathname: string; // Current pathname
|
|
670
|
+
search: string; // Query string
|
|
671
|
+
hash: string; // URL hash
|
|
672
|
+
url: URL; // Complete URL object
|
|
673
|
+
params: RouteParams; // Route parameters
|
|
674
|
+
query: URLSearchParams; // Query parameters object
|
|
675
|
+
}
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
### RouteParams
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
interface RouteParams {
|
|
682
|
+
[key: string]: string; // Parameter name to value mapping
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
### HistoryEntry
|
|
687
|
+
|
|
688
|
+
```typescript
|
|
689
|
+
interface HistoryEntry {
|
|
690
|
+
pathname: string; // Path of history entry
|
|
691
|
+
timestamp: number; // Entry creation time
|
|
692
|
+
state?: any; // Optional state data
|
|
693
|
+
}
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
## Examples
|
|
697
|
+
|
|
698
|
+
### Complete Application Setup
|
|
699
|
+
|
|
700
|
+
```typescript
|
|
701
|
+
<!-- App.svelte -->
|
|
702
|
+
<script lang="ts">
|
|
703
|
+
import { onMount } from 'svelte';
|
|
704
|
+
import { createRouter, RouterProvider, Route, Link } from '@finsweet/webflow-apps-utils';
|
|
705
|
+
|
|
706
|
+
// Import page components
|
|
707
|
+
import HomePage from './pages/HomePage.svelte';
|
|
708
|
+
import AboutPage from './pages/AboutPage.svelte';
|
|
709
|
+
import UserPage from './pages/UserPage.svelte';
|
|
710
|
+
import NotFoundPage from './pages/NotFoundPage.svelte';
|
|
711
|
+
|
|
712
|
+
// Create router with configuration
|
|
713
|
+
const router = createRouter({
|
|
714
|
+
basePath: '',
|
|
715
|
+
fallbackRoute: '/'
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// Define routes
|
|
719
|
+
router.addRoutes([
|
|
720
|
+
{ path: '/', component: HomePage, meta: { title: 'Home' } },
|
|
721
|
+
{ path: '/about', component: AboutPage, meta: { title: 'About' } },
|
|
722
|
+
{ path: '/users/:id', component: UserPage, meta: { title: 'User Profile' } },
|
|
723
|
+
{ path: '*', component: NotFoundPage, meta: { title: 'Not Found' } }
|
|
724
|
+
]);
|
|
725
|
+
|
|
726
|
+
onMount(() => {
|
|
727
|
+
// Initialize app version if needed
|
|
728
|
+
router.initAppVersion('/v1');
|
|
729
|
+
});
|
|
730
|
+
</script>
|
|
731
|
+
|
|
732
|
+
<RouterProvider {router}>
|
|
733
|
+
{#snippet children({ router, currentRoute, isNavigating })}
|
|
734
|
+
<div class="app">
|
|
735
|
+
<!-- Navigation -->
|
|
736
|
+
<nav class="navbar">
|
|
737
|
+
<div class="nav-brand">
|
|
738
|
+
<Link to="/">My App</Link>
|
|
739
|
+
</div>
|
|
740
|
+
<ul class="nav-links">
|
|
741
|
+
<li><Link to="/" exact activeClass="active">Home</Link></li>
|
|
742
|
+
<li><Link to="/about" activeClass="active">About</Link></li>
|
|
743
|
+
<li><Link to="/users/123" activeClass="active">Profile</Link></li>
|
|
744
|
+
</ul>
|
|
745
|
+
</nav>
|
|
746
|
+
|
|
747
|
+
<!-- Loading indicator -->
|
|
748
|
+
{#if isNavigating}
|
|
749
|
+
<div class="loading-bar"></div>
|
|
750
|
+
{/if}
|
|
751
|
+
|
|
752
|
+
<!-- Page title -->
|
|
753
|
+
<title>{currentRoute?.meta?.title || 'My App'}</title>
|
|
754
|
+
|
|
755
|
+
<!-- Main content -->
|
|
756
|
+
<main class="main-content">
|
|
757
|
+
<!-- Home Route -->
|
|
758
|
+
<Route path="/">
|
|
759
|
+
{#snippet children({ isActive })}
|
|
760
|
+
{#if isActive}
|
|
761
|
+
<HomePage />
|
|
762
|
+
{/if}
|
|
763
|
+
{/snippet}
|
|
764
|
+
</Route>
|
|
765
|
+
|
|
766
|
+
<!-- About Route -->
|
|
767
|
+
<Route path="/about" component={AboutPage} />
|
|
768
|
+
|
|
769
|
+
<!-- User Profile Route -->
|
|
770
|
+
<Route path="/users/:id">
|
|
771
|
+
{#snippet children({ params, isActive })}
|
|
772
|
+
{#if isActive}
|
|
773
|
+
<UserPage userId={params.id} />
|
|
774
|
+
{/if}
|
|
775
|
+
{/snippet}
|
|
776
|
+
</Route>
|
|
777
|
+
|
|
778
|
+
<!-- 404 Route -->
|
|
779
|
+
<Route path="*" exact={false} component={NotFoundPage} />
|
|
780
|
+
</main>
|
|
781
|
+
</div>
|
|
782
|
+
{/snippet}
|
|
783
|
+
</RouterProvider>
|
|
784
|
+
|
|
785
|
+
<style>
|
|
786
|
+
.app {
|
|
787
|
+
min-height: 100vh;
|
|
788
|
+
display: flex;
|
|
789
|
+
flex-direction: column;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
.navbar {
|
|
793
|
+
display: flex;
|
|
794
|
+
justify-content: space-between;
|
|
795
|
+
align-items: center;
|
|
796
|
+
padding: 1rem 2rem;
|
|
797
|
+
background: #f8f9fa;
|
|
798
|
+
border-bottom: 1px solid #dee2e6;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.nav-links {
|
|
802
|
+
display: flex;
|
|
803
|
+
list-style: none;
|
|
804
|
+
gap: 1rem;
|
|
805
|
+
margin: 0;
|
|
806
|
+
padding: 0;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.nav-links :global(a) {
|
|
810
|
+
padding: 0.5rem 1rem;
|
|
811
|
+
text-decoration: none;
|
|
812
|
+
color: #495057;
|
|
813
|
+
border-radius: 4px;
|
|
814
|
+
transition: all 0.2s;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
.nav-links :global(a:hover) {
|
|
818
|
+
background: #e9ecef;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.nav-links :global(a.active) {
|
|
822
|
+
background: #007bff;
|
|
823
|
+
color: white;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.loading-bar {
|
|
827
|
+
height: 3px;
|
|
828
|
+
background: linear-gradient(90deg, #007bff, #6610f2);
|
|
829
|
+
animation: slide 1s ease-in-out infinite;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
@keyframes slide {
|
|
833
|
+
0% { transform: translateX(-100%); }
|
|
834
|
+
100% { transform: translateX(100vw); }
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
.main-content {
|
|
838
|
+
flex: 1;
|
|
839
|
+
padding: 2rem;
|
|
840
|
+
}
|
|
841
|
+
</style>
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
### Using Hooks in Components
|
|
845
|
+
|
|
846
|
+
```typescript
|
|
847
|
+
<!-- UserProfile.svelte -->
|
|
848
|
+
<script lang="ts">
|
|
849
|
+
import { useParams, useNavigate, useSearchParams } from '@finsweet/webflow-apps-utils';
|
|
850
|
+
|
|
851
|
+
const params = useParams();
|
|
852
|
+
const navigate = useNavigate();
|
|
853
|
+
const searchParams = useSearchParams();
|
|
854
|
+
|
|
855
|
+
// Reactive values
|
|
856
|
+
$: userId = params.id;
|
|
857
|
+
$: tab = searchParams.get('tab') || 'profile';
|
|
858
|
+
|
|
859
|
+
function switchTab(newTab: string) {
|
|
860
|
+
searchParams.set('tab', newTab);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
function goBack() {
|
|
864
|
+
navigate('/users');
|
|
865
|
+
}
|
|
866
|
+
</script>
|
|
867
|
+
|
|
868
|
+
<div class="user-profile">
|
|
869
|
+
<header>
|
|
870
|
+
<button onclick={goBack}>← Back to Users</button>
|
|
871
|
+
<h1>User Profile: {userId}</h1>
|
|
872
|
+
</header>
|
|
873
|
+
|
|
874
|
+
<nav class="tabs">
|
|
875
|
+
<button
|
|
876
|
+
class:active={tab === 'profile'}
|
|
877
|
+
onclick={() => switchTab('profile')}
|
|
878
|
+
>
|
|
879
|
+
Profile
|
|
880
|
+
</button>
|
|
881
|
+
<button
|
|
882
|
+
class:active={tab === 'settings'}
|
|
883
|
+
onclick={() => switchTab('settings')}
|
|
884
|
+
>
|
|
885
|
+
Settings
|
|
886
|
+
</button>
|
|
887
|
+
</nav>
|
|
888
|
+
|
|
889
|
+
<main>
|
|
890
|
+
{#if tab === 'profile'}
|
|
891
|
+
<div>Profile content for user {userId}</div>
|
|
892
|
+
{:else if tab === 'settings'}
|
|
893
|
+
<div>Settings for user {userId}</div>
|
|
894
|
+
{/if}
|
|
895
|
+
</main>
|
|
896
|
+
</div>
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
### Programmatic Navigation
|
|
900
|
+
|
|
901
|
+
```typescript
|
|
902
|
+
<!-- NavigationExample.svelte -->
|
|
903
|
+
<script lang="ts">
|
|
904
|
+
import { useRouter, useNavigate, useLocation } from '@finsweet/webflow-apps-utils';
|
|
905
|
+
|
|
906
|
+
const router = useRouter();
|
|
907
|
+
const navigate = useNavigate();
|
|
908
|
+
const location = useLocation();
|
|
909
|
+
|
|
910
|
+
async function handleLogin(userData: any) {
|
|
911
|
+
// Simulate login
|
|
912
|
+
await loginUser(userData);
|
|
913
|
+
|
|
914
|
+
// Navigate to dashboard after login
|
|
915
|
+
navigate('/dashboard', {
|
|
916
|
+
replace: true,
|
|
917
|
+
state: { loginTime: Date.now() }
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function handleLogout() {
|
|
922
|
+
// Clear user data
|
|
923
|
+
clearUserSession();
|
|
924
|
+
|
|
925
|
+
// Navigate to home and replace history
|
|
926
|
+
router.navigate('/', { replace: true });
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
function goToUserProfile(userId: string) {
|
|
930
|
+
navigate(`/users/${userId}?tab=profile`);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function navigateWithState() {
|
|
934
|
+
navigate('/results', {
|
|
935
|
+
state: {
|
|
936
|
+
searchQuery: 'example',
|
|
937
|
+
timestamp: Date.now()
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
</script>
|
|
942
|
+
|
|
943
|
+
<div>
|
|
944
|
+
<p>Current path: {location.pathname}</p>
|
|
945
|
+
|
|
946
|
+
<button onclick={() => goToUserProfile('123')}>
|
|
947
|
+
View User 123
|
|
948
|
+
</button>
|
|
949
|
+
|
|
950
|
+
<button onclick={navigateWithState}>
|
|
951
|
+
Search with State
|
|
952
|
+
</button>
|
|
953
|
+
|
|
954
|
+
<button onclick={handleLogout}>
|
|
955
|
+
Logout
|
|
956
|
+
</button>
|
|
957
|
+
</div>
|
|
958
|
+
```
|