fusee-framework 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +145 -139
  2. package/app/benchmark/benchmark.js +2 -2
  3. package/app/main.js +24 -3
  4. package/app/main.ts +7 -1
  5. package/app/pages/_layout.js +27 -0
  6. package/app/pages/async-work.js +65 -0
  7. package/app/pages/index.js +25 -5
  8. package/app/pages/index.ts +9 -0
  9. package/app/pages/router-example.js +24 -1
  10. package/app/pages/scroll-demo.ts +102 -0
  11. package/app/providers/ChildComponent.js +8 -2
  12. package/app/providers/ChildComponent.ts +47 -47
  13. package/app/providers/GrandchildComponent.js +19 -0
  14. package/app/providers/ParentComponent.js +5 -1
  15. package/app/routes/RouterExample.js +23 -1
  16. package/app/routes/TestResource.js +47 -0
  17. package/app/services.js +15 -0
  18. package/auto-imports.d.ts +8 -0
  19. package/framework/auto-import-preset.js +13 -9
  20. package/framework/core/component.js +27 -13
  21. package/framework/core/di.js +187 -0
  22. package/framework/core/directives.js +40 -96
  23. package/framework/core/evaluator.js +1 -1
  24. package/framework/core/reconcile.js +151 -0
  25. package/framework/core/signal.js +267 -0
  26. package/framework/core/store.js +322 -81
  27. package/framework/index.js +5 -3
  28. package/framework/router/file-router.js +1 -1
  29. package/framework/router/router.js +113 -21
  30. package/framework/types/component.d.ts +89 -88
  31. package/framework/types/di.d.ts +43 -0
  32. package/framework/types/index.d.ts +32 -22
  33. package/framework/types/reconcile.d.ts +7 -0
  34. package/framework/types/router.d.ts +11 -1
  35. package/framework/types/signal.d.ts +147 -79
  36. package/framework/types/store.d.ts +66 -8
  37. package/package.json +1 -1
  38. package/vite.config.js +7 -1
@@ -1,10 +1,12 @@
1
1
  // ─── Framework Public API ─────────────────────────────────────────────────────
2
- export { signal, computed, effect, batch, untrack, inspect, watch, onCleanup } from './core/signal.js'
2
+ export { signal, computed, effect, batch, untrack, inspect, watch, onCleanup, resource, createSuspense, scheduleAsyncJob } from './core/signal.js'
3
3
  export { defineComponent, defineAsyncComponent, onMount, onUnmount, parseSlots, provide, inject, getCurrentInstance } from './core/component.js'
4
- export { createRouter, navigate, mountOutlet, currentRoute, routeParams, matchedRoutes } from './router/router.js'
4
+ export { InjectionToken, provideGlobal } from './core/di.js'
5
+ export { createRouter, navigate, mountOutlet, currentRoute, routeParams, routeQuery, matchedRoutes } from './router/router.js'
5
6
  export { generateRoutes } from './router/file-router.js'
6
7
  export { mountTemplate } from './core/compiler.js'
7
8
  export { defineComposable, assertSetupContext } from './core/composable.js'
8
- export { defineStore, resetStore, clearStores, registerStorePlugin } from './core/store.js'
9
+ export { defineStore, resetStore, clearStores, registerStorePlugin, storeToRefs, storeToState, storeToGetters, useNestedStore, MutationType } from './core/store.js'
9
10
  export { directive } from './core/directives.js'
11
+ export { reconcile } from './core/reconcile.js'
10
12
  export const emit = () => console.warn('[framework] emit() can only be used inside component setup()')
@@ -173,5 +173,5 @@ function _compareRoutes(a, b) {
173
173
  const bSegs = bPath.split('/').filter(Boolean).length;
174
174
  if (aSegs !== bSegs) return bSegs - aSegs;
175
175
 
176
- return bPath.length - aPath.length;
176
+ return aPath.localeCompare(bPath);
177
177
  }
@@ -2,6 +2,7 @@ import { signal } from '../core/signal.js'
2
2
 
3
3
  export const currentRoute = signal('/')
4
4
  export const routeParams = signal({})
5
+ export const routeQuery = signal({})
5
6
  export const matchedRoutes = signal([])
6
7
 
7
8
  let _routes = []
@@ -11,9 +12,26 @@ let _activeChain = []
11
12
  let _routeCache = new Map()
12
13
  let _cacheMaxSize = 100
13
14
  let _routerViewTimeout = 10000
15
+ let _scrollBehaviorOptions = null
16
+ let _scrollPositions = new Map()
17
+ let _currentPath = null
14
18
 
15
19
  function _getPath() {
16
- return window.location.pathname || '/'
20
+ const pathname = window.location.pathname || '/'
21
+ const search = window.location.search || ''
22
+ const hash = window.location.hash || ''
23
+ return pathname + search + hash
24
+ }
25
+
26
+ function _extractQuery(path) {
27
+ const queryStr = path.split('?')[1]?.split('#')[0]
28
+ if (!queryStr) return {}
29
+ const params = new URLSearchParams(queryStr)
30
+ const query = {}
31
+ for (const [key, value] of params.entries()) {
32
+ query[key] = value
33
+ }
34
+ return query
17
35
  }
18
36
 
19
37
  function _getRoutePaths(routePath) {
@@ -90,10 +108,9 @@ function _matchRouteTree(routes, urlSegments) {
90
108
  }
91
109
 
92
110
  function _matchSingleFlat(routePath, actualPath) {
93
- if (routePath === '*') return true
94
-
111
+ const actualPathWithoutParams = actualPath.split(/[?#]/)[0]
95
112
  const routeParts = routePath.split('/').filter(Boolean)
96
- const actualParts = actualPath.split('/').filter(Boolean)
113
+ const actualParts = actualPathWithoutParams.split('/').filter(Boolean)
97
114
 
98
115
  const hasWildcard = routeParts.length > 0 && routeParts[routeParts.length - 1] === '*'
99
116
 
@@ -121,8 +138,9 @@ function _extractParamsFromPath(singlePath, actualPath) {
121
138
  const params = {}
122
139
  if (singlePath === '*') return params
123
140
 
141
+ const actualPathWithoutParams = actualPath.split(/[?#]/)[0]
124
142
  const routeParts = singlePath.split('/').filter(Boolean)
125
- const actualParts = actualPath.split('/').filter(Boolean)
143
+ const actualParts = actualPathWithoutParams.split('/').filter(Boolean)
126
144
 
127
145
  const hasWildcard = routeParts.length > 0 && routeParts[routeParts.length - 1] === '*'
128
146
  const checkLen = hasWildcard ? routeParts.length - 1 : routeParts.length
@@ -142,14 +160,16 @@ function _extractParamsFlat(routePath, actualPath) {
142
160
  }
143
161
 
144
162
  function _findMatchingChain(path) {
145
- if (_routeCache.has(path)) {
146
- const cached = _routeCache.get(path)
147
- _routeCache.delete(path)
148
- _routeCache.set(path, cached)
163
+ const pathWithoutParams = path.split(/[?#]/)[0]
164
+
165
+ if (_routeCache.has(pathWithoutParams)) {
166
+ const cached = _routeCache.get(pathWithoutParams)
167
+ _routeCache.delete(pathWithoutParams)
168
+ _routeCache.set(pathWithoutParams, cached)
149
169
  return cached
150
170
  }
151
171
 
152
- const urlSegments = path.split('/').filter(Boolean)
172
+ const urlSegments = pathWithoutParams.split('/').filter(Boolean)
153
173
  const hasNested = _routes.some(r => r.children && r.children.length > 0)
154
174
 
155
175
  let chain = null
@@ -157,7 +177,7 @@ function _findMatchingChain(path) {
157
177
  if (hasNested) {
158
178
  chain = _matchRouteTree(_routes, urlSegments)
159
179
  if (chain) {
160
- _cacheResult(path, chain)
180
+ _cacheResult(pathWithoutParams, chain)
161
181
  return chain
162
182
  }
163
183
  }
@@ -166,11 +186,11 @@ function _findMatchingChain(path) {
166
186
  const routePaths = _getRoutePaths(r.path)
167
187
  return !routePaths.includes('*') && !routePaths.some(p => p.endsWith('/*')) && !r.children
168
188
  })
169
- const exactMatch = paths.find(r => _matchFlat(r.path, path))
189
+ const exactMatch = paths.find(r => _matchFlat(r.path, pathWithoutParams))
170
190
  if (exactMatch) {
171
- const matchedPath = _findMatchingPath(exactMatch.path, path)
172
- chain = [{ route: exactMatch, params: _extractParamsFlat(exactMatch.path, path), matchedSegments: urlSegments, matchedPath }]
173
- _cacheResult(path, chain)
191
+ const matchedPath = _findMatchingPath(exactMatch.path, pathWithoutParams)
192
+ chain = [{ route: exactMatch, params: _extractParamsFlat(exactMatch.path, pathWithoutParams), matchedSegments: urlSegments, matchedPath }]
193
+ _cacheResult(pathWithoutParams, chain)
174
194
  return chain
175
195
  }
176
196
 
@@ -178,11 +198,11 @@ function _findMatchingChain(path) {
178
198
  const routePaths = _getRoutePaths(r.path)
179
199
  return !r.children && routePaths.some(p => p.endsWith('/*'))
180
200
  })
181
- const wildcardMatch = wildcardPaths.find(r => _matchFlat(r.path, path))
201
+ const wildcardMatch = wildcardPaths.find(r => _matchFlat(r.path, pathWithoutParams))
182
202
  if (wildcardMatch) {
183
- const matchedPath = _findMatchingPath(wildcardMatch.path, path)
184
- chain = [{ route: wildcardMatch, params: _extractParamsFlat(wildcardMatch.path, path), matchedSegments: urlSegments, matchedPath }]
185
- _cacheResult(path, chain)
203
+ const matchedPath = _findMatchingPath(wildcardMatch.path, pathWithoutParams)
204
+ chain = [{ route: wildcardMatch, params: _extractParamsFlat(wildcardMatch.path, pathWithoutParams), matchedSegments: urlSegments, matchedPath }]
205
+ _cacheResult(pathWithoutParams, chain)
186
206
  return chain
187
207
  }
188
208
 
@@ -192,7 +212,7 @@ function _findMatchingChain(path) {
192
212
  })
193
213
  if (catchAll) {
194
214
  chain = [{ route: catchAll, params: {}, matchedSegments: urlSegments, matchedPath: '*' }]
195
- _cacheResult(path, chain)
215
+ _cacheResult(pathWithoutParams, chain)
196
216
  return chain
197
217
  }
198
218
 
@@ -211,6 +231,63 @@ function _clearRouteCache() {
211
231
  _routeCache.clear()
212
232
  }
213
233
 
234
+ function _saveScrollPosition(path) {
235
+ if (!_scrollBehaviorOptions?.saveScrollPosition) return
236
+ _scrollPositions.set(path, {
237
+ left: window.scrollX,
238
+ top: window.scrollY
239
+ })
240
+ }
241
+
242
+ function _getSavedScrollPosition(path) {
243
+ return _scrollPositions.get(path) || null
244
+ }
245
+
246
+ function _applyScrollBehavior(to, from) {
247
+ const options = _scrollBehaviorOptions
248
+ if (!options) return
249
+
250
+ const savedPosition = _getSavedScrollPosition(to)
251
+
252
+ if (options.custom) {
253
+ const result = options.custom(to, from, savedPosition)
254
+ if (result && typeof result.then === 'function') {
255
+ result.then(pos => _performScroll(pos))
256
+ } else {
257
+ _performScroll(result)
258
+ }
259
+ return
260
+ }
261
+
262
+ if (options.scrollToAnchor && to.includes('#')) {
263
+ const anchor = to.split('#')[1]
264
+ const element = document.getElementById(anchor)
265
+ if (element) {
266
+ element.scrollIntoView({ behavior: 'smooth' })
267
+ return
268
+ }
269
+ }
270
+
271
+ if (options.scrollToTop !== false) {
272
+ window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
273
+ } else if (savedPosition && options.saveScrollPosition) {
274
+ window.scrollTo(savedPosition.left, savedPosition.top)
275
+ }
276
+ }
277
+
278
+ function _performScroll(position) {
279
+ if (!position || position === false) return
280
+
281
+ if (typeof position === 'object' && 'selector' in position) {
282
+ const element = document.querySelector(position.selector)
283
+ if (element) {
284
+ element.scrollIntoView({ behavior: 'smooth' })
285
+ }
286
+ } else if (typeof position === 'object' && 'left' in position) {
287
+ window.scrollTo({ left: position.left, top: position.top, behavior: 'smooth' })
288
+ }
289
+ }
290
+
214
291
  function _unmountFromLevel(level) {
215
292
  for (let i = _activeChain.length - 1; i >= level; i--) {
216
293
  const entry = _activeChain[i]
@@ -362,10 +439,21 @@ function _resolveRoute() {
362
439
  }
363
440
 
364
441
  _renderChain(chain)
442
+
443
+ const from = _currentPath
444
+ _currentPath = path
445
+ _applyScrollBehavior(path, from)
446
+ routeQuery(_extractQuery(path))
365
447
  }
366
448
 
367
449
  export function navigate(path) {
368
- if (path === _getPath()) return
450
+ const currentPath = _getPath().split(/[?#]/)[0]
451
+ const targetPath = path.split(/[?#]/)[0]
452
+ if (targetPath === currentPath && path === _getPath()) {
453
+ _applyScrollBehavior(path, _getPath())
454
+ return
455
+ }
456
+ _saveScrollPosition(_getPath())
369
457
  window.history.pushState({}, '', path)
370
458
  _updateRoute()
371
459
  _resolveRoute()
@@ -440,6 +528,7 @@ export function createRouter(routes, options = {}) {
440
528
  _activeChain = []
441
529
  _cacheMaxSize = options.cacheSize || 100
442
530
  _routerViewTimeout = options.routerViewTimeout || 10000
531
+ _scrollBehaviorOptions = options.scrollBehavior || null
443
532
 
444
533
  _updateRoute()
445
534
 
@@ -457,6 +546,9 @@ export function createRouter(routes, options = {}) {
457
546
  _rootOutlet = null
458
547
  _activeChain = []
459
548
  _clearRouteCache()
549
+ _scrollPositions.clear()
550
+ _scrollBehaviorOptions = null
551
+ _currentPath = null
460
552
  }
461
553
  }
462
554
  }
@@ -1,88 +1,89 @@
1
- export type ComponentProps = Record<string, any>
2
- export type EmptyProps = Record<string, never>
3
- export type PropSchema = string[] | Record<string, PropConfig>
4
-
5
- export type PropConfig = {
6
- type?: FunctionConstructor | StringConstructor | NumberConstructor | BooleanConstructor
7
- default?: any | (() => any)
8
- required?: boolean
9
- }
10
-
11
- export type EmitFn = (eventName: string, ...args: any[]) => void
12
-
13
- export type Slots = Record<string, string>
14
-
15
- export type SetupContext = {
16
- emit: EmitFn
17
- slots: Slots
18
- }
19
-
20
- export type ComponentInstance = {
21
- props: ComponentProps
22
- _mountHooks: (() => void)[]
23
- _unmountHooks: (() => void)[]
24
- _effects: import('./signal').EffectRunner[]
25
- _element: HTMLElement | null
26
- _provides: Record<string, any>
27
- _parent: ComponentInstance | null
28
- }
29
-
30
- export type ComponentResult = {
31
- template: string
32
- [key: string]: any
33
- }
34
-
35
- export type ComponentOptions<TProps = ComponentProps, P = PropSchema> = {
36
- props?: P
37
- components?: Record<string, ComponentFactory<any>>
38
- setup: (props: TProps, ctx: SetupContext) => ComponentResult
39
- }
40
-
41
- export type ComponentFactory<TProps = ComponentProps> = (
42
- props?: TProps,
43
- options?: { listeners?: Record<string, Function>, slots?: Slots, parent?: ComponentInstance }
44
- ) => ComponentApi
45
-
46
- export type ComponentApi = {
47
- render: (container: HTMLElement) => ComponentInstance
48
- unmount: () => void
49
- instance: ComponentInstance
50
- }
51
-
52
- export declare function onMount(fn: () => void): void
53
- export declare function onUnmount(fn: () => void): void
54
- export declare function parseSlots(slotHTML: string): Slots
55
- export declare function getCurrentInstance(): ComponentInstance | null
56
-
57
- export declare function provide<T>(key: string, value: T): void
58
- export declare function inject<T>(key: string): T | null
59
-
60
- type InferPropType<T> = T extends StringConstructor ? string :
61
- T extends NumberConstructor ? number :
62
- T extends BooleanConstructor ? boolean :
63
- any;
64
-
65
- type InferProps<P> = P extends string[]
66
- ? Record<P[number], any>
67
- : P extends Record<string, PropConfig>
68
- ? {
69
- [K in keyof P]: P[K]['required'] extends true
70
- ? InferPropType<P[K]['type']>
71
- : InferPropType<P[K]['type']> | (P[K] extends { default: any } ? never : undefined)
72
- }
73
- : Record<string, any>;
74
-
75
- export declare function defineComponent<P extends PropSchema = any, TProps = InferProps<P>>(
76
- options: ComponentOptions<TProps, P>
77
- ): ComponentFactory<TProps>
78
-
79
- export type AsyncComponentLoader<TProps = ComponentProps> = () => Promise<ComponentFactory<TProps> | { default: ComponentFactory<TProps> } | Record<string, any>>
80
-
81
- export type AsyncComponentOptions<TProps = ComponentProps> = {
82
- loader: AsyncComponentLoader<TProps>
83
- loadingComponent?: ComponentFactory<any>
84
- }
85
-
86
- export declare function defineAsyncComponent<TProps = ComponentProps>(
87
- loaderOrOptions: AsyncComponentLoader<TProps> | AsyncComponentOptions<TProps>
88
- ): ComponentFactory<TProps>
1
+ export type ComponentProps = Record<string, any>
2
+ export type EmptyProps = Record<string, never>
3
+ export type PropSchema = string[] | Record<string, PropConfig>
4
+
5
+ export type PropConfig = {
6
+ type?: FunctionConstructor | StringConstructor | NumberConstructor | BooleanConstructor
7
+ default?: any | (() => any)
8
+ required?: boolean
9
+ }
10
+
11
+ export type EmitFn = (eventName: string, ...args: any[]) => void
12
+
13
+ export type Slots = Record<string, string>
14
+
15
+ export type SetupContext = {
16
+ emit: EmitFn
17
+ slots: Slots
18
+ }
19
+
20
+ export type ComponentInstance = {
21
+ props: ComponentProps
22
+ _mountHooks: (() => void)[]
23
+ _unmountHooks: (() => void)[]
24
+ _effects: import('./signal').EffectRunner[]
25
+ _element: HTMLElement | null
26
+ _parent: ComponentInstance | null
27
+ _injector: import('./di').Injector
28
+ _ownsInjector: boolean
29
+ }
30
+
31
+ export type ComponentResult = {
32
+ template: string
33
+ [key: string]: any
34
+ }
35
+
36
+ export type ComponentOptions<TProps = ComponentProps, P = PropSchema> = {
37
+ props?: P
38
+ components?: Record<string, ComponentFactory<any>>
39
+ setup: (props: TProps, ctx: SetupContext) => ComponentResult
40
+ }
41
+
42
+ export type ComponentFactory<TProps = ComponentProps> = (
43
+ props?: TProps,
44
+ options?: { listeners?: Record<string, Function>, slots?: Slots, parent?: ComponentInstance }
45
+ ) => ComponentApi
46
+
47
+ export type ComponentApi = {
48
+ render: (container: HTMLElement) => ComponentInstance
49
+ unmount: () => void
50
+ instance: ComponentInstance
51
+ }
52
+
53
+ export declare function onMount(fn: () => void): void
54
+ export declare function onUnmount(fn: () => void): void
55
+ export declare function parseSlots(slotHTML: string): Slots
56
+ export declare function getCurrentInstance(): ComponentInstance | null
57
+
58
+ export declare function provide(keyOrProvider: any, value?: any): void
59
+ export { inject } from './di'
60
+
61
+ type InferPropType<T> = T extends StringConstructor ? string :
62
+ T extends NumberConstructor ? number :
63
+ T extends BooleanConstructor ? boolean :
64
+ any;
65
+
66
+ type InferProps<P> = P extends string[]
67
+ ? Record<P[number], any>
68
+ : P extends Record<string, PropConfig>
69
+ ? {
70
+ [K in keyof P]: P[K]['required'] extends true
71
+ ? InferPropType<P[K]['type']>
72
+ : InferPropType<P[K]['type']> | (P[K] extends { default: any } ? never : undefined)
73
+ }
74
+ : Record<string, any>;
75
+
76
+ export declare function defineComponent<P extends PropSchema = any, TProps = InferProps<P>>(
77
+ options: ComponentOptions<TProps, P>
78
+ ): ComponentFactory<TProps>
79
+
80
+ export type AsyncComponentLoader<TProps = ComponentProps> = () => Promise<ComponentFactory<TProps> | { default: ComponentFactory<TProps> } | Record<string, any>>
81
+
82
+ export type AsyncComponentOptions<TProps = ComponentProps> = {
83
+ loader: AsyncComponentLoader<TProps>
84
+ loadingComponent?: ComponentFactory<any>
85
+ }
86
+
87
+ export declare function defineAsyncComponent<TProps = ComponentProps>(
88
+ loaderOrOptions: AsyncComponentLoader<TProps> | AsyncComponentOptions<TProps>
89
+ ): ComponentFactory<TProps>
@@ -0,0 +1,43 @@
1
+ export declare class InjectionToken<T = any> {
2
+ constructor(description: string);
3
+ description: string;
4
+ toString(): string;
5
+ }
6
+
7
+ export declare function isClass(fn: any): boolean;
8
+
9
+ export interface InjectOptions {
10
+ optional?: boolean;
11
+ skipSelf?: boolean;
12
+ self?: boolean;
13
+ }
14
+
15
+ export declare abstract class Injector {
16
+ get<T>(token: any, options?: InjectOptions): T;
17
+ }
18
+
19
+ export declare class NullInjector extends Injector {
20
+ get<T>(token: any, options?: InjectOptions): T | null;
21
+ }
22
+
23
+ export declare type Provider =
24
+ | any // class (shorthand)
25
+ | { provide: any, useClass: any }
26
+ | { provide: any, useValue: any }
27
+ | { provide: any, useFactory: () => any }
28
+ | { provide: any, useExisting: any };
29
+
30
+ export declare class EnvironmentInjector extends Injector {
31
+ constructor(providers?: Provider[], parent?: Injector);
32
+ parent: Injector;
33
+ provide(provider: Provider): void;
34
+ get<T>(token: any, options?: InjectOptions): T;
35
+ createChild(providers?: Provider[]): EnvironmentInjector;
36
+ destroy(): void;
37
+ }
38
+
39
+ export declare function runInContext<T>(injector: Injector, fn: () => T): T;
40
+ export declare function replaceActiveInjector(injector: Injector): void;
41
+ export declare function inject<T>(token: any, options: InjectOptions & { optional: true }): T | null;
42
+ export declare function inject<T>(token: any, options?: InjectOptions): T;
43
+
@@ -1,22 +1,32 @@
1
- export * from './signal'
2
- export * from './component'
3
- export * from './composable'
4
- export * from './router'
5
- export * from './compiler'
6
- export * from './directives'
7
- export * from './store'
8
- export * from './event-delegation'
9
-
10
- declare global {
11
- type Signal<T = any> = import('./signal').Signal<T>
12
- type Computed<T = any> = import('./signal').Computed<T>
13
- type SignalAccessor<T> = import('./signal').SignalAccessor<T>
14
- type Composable<T extends (...args: any[]) => any> = import('./composable').Composable<T>
15
- type DirectiveBinding<V = any> = import('./directives').DirectiveBinding<V>
16
- type DirectiveHooks<V = any> = import('./directives').DirectiveHooks<V>
17
- type DelegatedEventOptions = import('./event-delegation').DelegatedEventOptions
18
- const defineStore: typeof import('./store').defineStore
19
- const isDelegatedEvent: typeof import('./event-delegation').isDelegatedEvent
20
- }
21
-
22
- export as namespace Fusee
1
+ export * from './signal'
2
+ export * from './component'
3
+ export * from './composable'
4
+ export * from './router'
5
+ export * from './compiler'
6
+ export * from './directives'
7
+ export * from './store'
8
+ export * from './event-delegation'
9
+ export * from './di'
10
+ export * from './reconcile'
11
+
12
+ declare global {
13
+ type Signal<T = any> = import('./signal').Signal<T>
14
+ type Computed<T = any> = import('./signal').Computed<T>
15
+ type SignalAccessor<T> = import('./signal').SignalAccessor<T>
16
+ type Composable<T extends (...args: any[]) => any> = import('./composable').Composable<T>
17
+ type DirectiveBinding<V = any> = import('./directives').DirectiveBinding<V>
18
+ type DirectiveHooks<V = any> = import('./directives').DirectiveHooks<V>
19
+ type DelegatedEventOptions = import('./event-delegation').DelegatedEventOptions
20
+ const defineStore: typeof import('./store').defineStore
21
+ const storeToRefs: typeof import('./store').storeToRefs
22
+ const storeToState: typeof import('./store').storeToState
23
+ const storeToGetters: typeof import('./store').storeToGetters
24
+ const useNestedStore: typeof import('./store').useNestedStore
25
+ type StoreHook<T> = import('./store').StoreHook<T>
26
+ const isDelegatedEvent: typeof import('./event-delegation').isDelegatedEvent
27
+ const InjectionToken: typeof import('./di').InjectionToken
28
+ const provideGlobal: typeof import('./di').provideGlobal
29
+ const reconcile: typeof import('./reconcile').reconcile
30
+ }
31
+
32
+ export as namespace Fusee
@@ -0,0 +1,7 @@
1
+ export function reconcile<T = any>(
2
+ container: Element,
3
+ oldList: T[],
4
+ newList: T[],
5
+ keyFn: (item: T) => any,
6
+ createFn: (item: T) => Element
7
+ ): void;
@@ -7,6 +7,15 @@ export type Route = {
7
7
  children?: Route[]
8
8
  }
9
9
 
10
+ export type ScrollPosition = { left: number; top: number } | { selector: string } | false
11
+
12
+ export type ScrollBehaviorOptions = {
13
+ scrollToTop?: boolean
14
+ scrollToAnchor?: boolean
15
+ saveScrollPosition?: boolean
16
+ custom?: (to: string, from: string, savedPosition: ScrollPosition | null) => ScrollPosition | Promise<ScrollPosition>
17
+ }
18
+
10
19
  export type Router = {
11
20
  navigate: (path: string) => void
12
21
  destroy: () => void
@@ -16,9 +25,10 @@ export type RouteParams = Record<string, string>
16
25
 
17
26
  export declare const currentRoute: Signal<string>
18
27
  export declare const routeParams: Signal<RouteParams>
28
+ export declare const routeQuery: Signal<Record<string, string>>
19
29
  export declare const matchedRoutes: Signal<Route[]>
20
30
 
21
- export declare function createRouter(routes: Route[], options?: { cacheSize?: number; routerViewTimeout?: number }): Router
31
+ export declare function createRouter(routes: Route[], options?: { cacheSize?: number; routerViewTimeout?: number; scrollBehavior?: ScrollBehaviorOptions }): Router
22
32
  export declare function navigate(path: string): void
23
33
  export declare function mountOutlet(el: HTMLElement): void
24
34