@furystack/shades 13.2.2 → 15.0.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 (146) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/esm/component-factory.spec.d.ts.map +1 -1
  3. package/esm/component-factory.spec.js +2 -2
  4. package/esm/component-factory.spec.js.map +1 -1
  5. package/esm/components/define-nested-routes.d.ts +27 -0
  6. package/esm/components/define-nested-routes.d.ts.map +1 -0
  7. package/esm/components/define-nested-routes.js +26 -0
  8. package/esm/components/define-nested-routes.js.map +1 -0
  9. package/esm/components/define-nested-routes.spec.d.ts +2 -0
  10. package/esm/components/define-nested-routes.spec.d.ts.map +1 -0
  11. package/esm/components/define-nested-routes.spec.js +81 -0
  12. package/esm/components/define-nested-routes.spec.js.map +1 -0
  13. package/esm/components/index.d.ts +3 -3
  14. package/esm/components/index.d.ts.map +1 -1
  15. package/esm/components/index.js +3 -3
  16. package/esm/components/index.js.map +1 -1
  17. package/esm/components/nested-hooks.d.ts +62 -0
  18. package/esm/components/nested-hooks.d.ts.map +1 -0
  19. package/esm/components/nested-hooks.js +73 -0
  20. package/esm/components/nested-hooks.js.map +1 -0
  21. package/esm/components/nested-hooks.spec.d.ts +2 -0
  22. package/esm/components/nested-hooks.spec.d.ts.map +1 -0
  23. package/esm/components/nested-hooks.spec.js +211 -0
  24. package/esm/components/nested-hooks.spec.js.map +1 -0
  25. package/esm/components/nested-navigate.d.ts +52 -21
  26. package/esm/components/nested-navigate.d.ts.map +1 -1
  27. package/esm/components/nested-navigate.js +32 -17
  28. package/esm/components/nested-navigate.js.map +1 -1
  29. package/esm/components/nested-navigate.spec.js +109 -19
  30. package/esm/components/nested-navigate.spec.js.map +1 -1
  31. package/esm/components/nested-replace.d.ts +36 -0
  32. package/esm/components/nested-replace.d.ts.map +1 -0
  33. package/esm/components/nested-replace.js +38 -0
  34. package/esm/components/nested-replace.js.map +1 -0
  35. package/esm/components/nested-replace.spec.d.ts +2 -0
  36. package/esm/components/nested-replace.spec.d.ts.map +1 -0
  37. package/esm/components/nested-replace.spec.js +59 -0
  38. package/esm/components/nested-replace.spec.js.map +1 -0
  39. package/esm/components/nested-route-link.d.ts +36 -26
  40. package/esm/components/nested-route-link.d.ts.map +1 -1
  41. package/esm/components/nested-route-link.js +18 -20
  42. package/esm/components/nested-route-link.js.map +1 -1
  43. package/esm/components/nested-route-link.spec.js +67 -17
  44. package/esm/components/nested-route-link.spec.js.map +1 -1
  45. package/esm/components/nested-route-types.d.ts +79 -2
  46. package/esm/components/nested-route-types.d.ts.map +1 -1
  47. package/esm/components/nested-router.d.ts +77 -7
  48. package/esm/components/nested-router.d.ts.map +1 -1
  49. package/esm/components/nested-router.js +139 -13
  50. package/esm/components/nested-router.js.map +1 -1
  51. package/esm/components/nested-router.spec.js +283 -52
  52. package/esm/components/nested-router.spec.js.map +1 -1
  53. package/esm/services/location-service.d.ts +39 -42
  54. package/esm/services/location-service.d.ts.map +1 -1
  55. package/esm/services/location-service.js +115 -134
  56. package/esm/services/location-service.js.map +1 -1
  57. package/esm/services/location-service.spec.js +59 -24
  58. package/esm/services/location-service.spec.js.map +1 -1
  59. package/esm/services/route-match-service.d.ts +3 -2
  60. package/esm/services/route-match-service.d.ts.map +1 -1
  61. package/esm/services/route-match-service.js +13 -22
  62. package/esm/services/route-match-service.js.map +1 -1
  63. package/esm/services/route-match-service.spec.js +42 -49
  64. package/esm/services/route-match-service.spec.js.map +1 -1
  65. package/esm/services/route-meta-utils.d.ts +28 -6
  66. package/esm/services/route-meta-utils.d.ts.map +1 -1
  67. package/esm/services/route-meta-utils.js +18 -4
  68. package/esm/services/route-meta-utils.js.map +1 -1
  69. package/esm/services/route-meta-utils.spec.js +60 -5
  70. package/esm/services/route-meta-utils.spec.js.map +1 -1
  71. package/esm/services/screen-service.d.ts +13 -72
  72. package/esm/services/screen-service.d.ts.map +1 -1
  73. package/esm/services/screen-service.js +45 -137
  74. package/esm/services/screen-service.js.map +1 -1
  75. package/esm/services/screen-service.spec.js +19 -18
  76. package/esm/services/screen-service.spec.js.map +1 -1
  77. package/esm/services/spatial-navigation-service.d.ts +17 -39
  78. package/esm/services/spatial-navigation-service.d.ts.map +1 -1
  79. package/esm/services/spatial-navigation-service.js +280 -313
  80. package/esm/services/spatial-navigation-service.js.map +1 -1
  81. package/esm/services/spatial-navigation-service.spec.js +163 -158
  82. package/esm/services/spatial-navigation-service.spec.js.map +1 -1
  83. package/esm/shade.d.ts +1 -1
  84. package/esm/shade.d.ts.map +1 -1
  85. package/esm/shade.js +10 -7
  86. package/esm/shade.js.map +1 -1
  87. package/esm/vnode.d.ts +1 -1
  88. package/esm/vnode.js +1 -1
  89. package/package.json +5 -4
  90. package/src/component-factory.spec.tsx +3 -2
  91. package/src/components/define-nested-routes.spec.ts +91 -0
  92. package/src/components/define-nested-routes.ts +27 -0
  93. package/src/components/index.ts +3 -3
  94. package/src/components/nested-hooks.spec.ts +254 -0
  95. package/src/components/nested-hooks.ts +109 -0
  96. package/src/components/nested-navigate.spec.ts +136 -32
  97. package/src/components/nested-navigate.ts +75 -26
  98. package/src/components/nested-replace.spec.ts +89 -0
  99. package/src/components/nested-replace.ts +46 -0
  100. package/src/components/nested-route-link.spec.tsx +90 -22
  101. package/src/components/nested-route-link.tsx +54 -29
  102. package/src/components/nested-route-types.ts +82 -2
  103. package/src/components/nested-router.spec.tsx +334 -51
  104. package/src/components/nested-router.tsx +184 -24
  105. package/src/services/location-service.spec.ts +68 -25
  106. package/src/services/location-service.tsx +156 -122
  107. package/src/services/route-match-service.spec.ts +41 -28
  108. package/src/services/route-match-service.ts +17 -8
  109. package/src/services/route-meta-utils.spec.ts +78 -10
  110. package/src/services/route-meta-utils.ts +44 -15
  111. package/src/services/screen-service.spec.ts +19 -18
  112. package/src/services/screen-service.ts +65 -110
  113. package/src/services/spatial-navigation-service.spec.ts +165 -160
  114. package/src/services/spatial-navigation-service.ts +299 -287
  115. package/src/shade.ts +11 -8
  116. package/src/vnode.ts +1 -1
  117. package/esm/components/link-to-route.d.ts +0 -10
  118. package/esm/components/link-to-route.d.ts.map +0 -1
  119. package/esm/components/link-to-route.js +0 -16
  120. package/esm/components/link-to-route.js.map +0 -1
  121. package/esm/components/link-to-route.spec.d.ts +0 -2
  122. package/esm/components/link-to-route.spec.d.ts.map +0 -1
  123. package/esm/components/link-to-route.spec.js +0 -30
  124. package/esm/components/link-to-route.spec.js.map +0 -1
  125. package/esm/components/route-link.d.ts +0 -10
  126. package/esm/components/route-link.d.ts.map +0 -1
  127. package/esm/components/route-link.js +0 -25
  128. package/esm/components/route-link.js.map +0 -1
  129. package/esm/components/route-link.spec.d.ts +0 -2
  130. package/esm/components/route-link.spec.d.ts.map +0 -1
  131. package/esm/components/route-link.spec.js +0 -34
  132. package/esm/components/route-link.spec.js.map +0 -1
  133. package/esm/components/router.d.ts +0 -44
  134. package/esm/components/router.d.ts.map +0 -1
  135. package/esm/components/router.js +0 -66
  136. package/esm/components/router.js.map +0 -1
  137. package/esm/components/router.spec.d.ts +0 -2
  138. package/esm/components/router.spec.d.ts.map +0 -1
  139. package/esm/components/router.spec.js +0 -161
  140. package/esm/components/router.spec.js.map +0 -1
  141. package/src/components/link-to-route.spec.tsx +0 -45
  142. package/src/components/link-to-route.tsx +0 -26
  143. package/src/components/route-link.spec.tsx +0 -44
  144. package/src/components/route-link.tsx +0 -29
  145. package/src/components/router.spec.tsx +0 -217
  146. package/src/components/router.tsx +0 -103
package/src/shade.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { Constructable } from '@furystack/inject'
2
- import { hasInjectorReference, Injector } from '@furystack/inject'
1
+ import type { Constructable } from '@furystack/core'
2
+ import { Injector } from '@furystack/inject'
3
3
  import { ObservableValue } from '@furystack/utils'
4
4
  import type { ChildrenList, CSSObject, PartialElement, RenderOptions } from './models/index.js'
5
5
  import type { RefObject } from './models/render-options.js'
@@ -166,16 +166,16 @@ export const Shade = <TProps, TElementBase extends HTMLElement = HTMLElement>(
166
166
  this._refs.set(key, refObject as unknown as RefObject<Element>)
167
167
  return refObject as RefObject<T>
168
168
  },
169
- useObservable: (key, obesrvable, options) => {
169
+ useObservable: (key, observable, options) => {
170
170
  const onChange = options?.onChange || (() => this.updateComponent())
171
- return this.resourceManager.useObservable(key, obesrvable, onChange, options)
171
+ return this.resourceManager.useObservable(key, observable, onChange, options)
172
172
  },
173
173
  useState: (key, initialValue) =>
174
174
  this.resourceManager.useState(key, initialValue, this.updateComponent.bind(this)),
175
175
  useSearchState: (key, initialValue) =>
176
176
  this.resourceManager.useObservable(
177
177
  `useSearchState-${key}`,
178
- this.injector.getInstance(LocationService).useSearchParam(key, initialValue),
178
+ this.injector.get(LocationService).useSearchParam(key, initialValue),
179
179
  () => this.updateComponent(),
180
180
  ),
181
181
 
@@ -416,8 +416,8 @@ export const Shade = <TProps, TElementBase extends HTMLElement = HTMLElement>(
416
416
  return this._injector
417
417
  }
418
418
 
419
- const fromProps = hasInjectorReference(this.props) && this.props.injector
420
- if (fromProps && fromProps instanceof Injector) {
419
+ const fromProps = (this.props as { injector?: unknown } | undefined)?.injector
420
+ if (fromProps instanceof Injector) {
421
421
  return fromProps
422
422
  }
423
423
 
@@ -426,7 +426,10 @@ export const Shade = <TProps, TElementBase extends HTMLElement = HTMLElement>(
426
426
  this._injector = fromParent
427
427
  return fromParent
428
428
  }
429
- // Injector not set explicitly and not found on parents!
429
+ // Fallback for isolated components (tests and non-DI use cases) that
430
+ // never reach for any services. Components that do resolve tokens
431
+ // will fail loudly at resolution time, since this throwaway injector
432
+ // has no bindings.
430
433
  return new Injector()
431
434
  }
432
435
 
package/src/vnode.ts CHANGED
@@ -183,7 +183,7 @@ export const shallowEqual = (a: Record<string, unknown>, b: Record<string, unkno
183
183
  * VChild array suitable for `patchChildren`.
184
184
  *
185
185
  * Real DOM elements can appear here when component state stores elements created
186
- * outside renderMode (e.g. in async callbacks like Router's `updateUrl`).
186
+ * outside renderMode (e.g. in async callbacks like NestedRouter's `updateUrl`).
187
187
  */
188
188
  export const toVChildArray = (renderResult: unknown): VChild[] => {
189
189
  if (renderResult === null || renderResult === undefined) return []
@@ -1,10 +0,0 @@
1
- import type { ChildrenList } from '../models/children-list.js';
2
- import type { Route } from './router.js';
3
- /** @deprecated Use `NestedRouteLinkProps` from `nested-route-link` instead */
4
- export type LinkToRouteProps<T extends object> = {
5
- route: Route<T>;
6
- params: T;
7
- } & Omit<JSX.IntrinsicElements['a'], 'href'>;
8
- /** @deprecated Use `NestedRouteLink` from `nested-route-link` instead */
9
- export declare const LinkToRoute: <T extends object>(props: LinkToRouteProps<T>, children?: ChildrenList) => JSX.Element;
10
- //# sourceMappingURL=link-to-route.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"link-to-route.d.ts","sourceRoot":"","sources":["../../src/components/link-to-route.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAG9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAExC,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,IAAI;IAC/C,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;IACf,MAAM,EAAE,CAAC,CAAA;CACV,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAA;AAE5C,yEAAyE;AACzE,eAAO,MAAM,WAAW,EAAE,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,YAAY,KAAK,GAAG,CAAC,OAYrG,CAAA"}
@@ -1,16 +0,0 @@
1
- import { compileRoute } from '../compile-route.js';
2
- import { createComponent } from '../shade-component.js';
3
- import { Shade } from '../shade.js';
4
- /** @deprecated Use `NestedRouteLink` from `nested-route-link` instead */
5
- export const LinkToRoute = Shade({
6
- customElementName: 'link-to-route',
7
- elementBase: HTMLAnchorElement,
8
- elementBaseName: 'a',
9
- render: ({ props, useHostProps, children }) => {
10
- const { route, params } = props;
11
- const url = compileRoute(route.url, params);
12
- useHostProps({ href: url });
13
- return createComponent(createComponent, null, children);
14
- },
15
- });
16
- //# sourceMappingURL=link-to-route.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"link-to-route.js","sourceRoot":"","sources":["../../src/components/link-to-route.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AASnC,yEAAyE;AACzE,MAAM,CAAC,MAAM,WAAW,GACtB,KAAK,CAAC;IACJ,iBAAiB,EAAE,eAAe;IAClC,WAAW,EAAE,iBAAiB;IAC9B,eAAe,EAAE,GAAG;IACpB,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC5C,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;QAE/B,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QAC3C,YAAY,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;QAC3B,OAAO,uCAAG,QAAQ,CAAI,CAAA;IACxB,CAAC;CACF,CAAC,CAAA"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=link-to-route.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"link-to-route.spec.d.ts","sourceRoot":"","sources":["../../src/components/link-to-route.spec.tsx"],"names":[],"mappings":""}
@@ -1,30 +0,0 @@
1
- import { Injector } from '@furystack/inject';
2
- import { usingAsync } from '@furystack/utils';
3
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
4
- import { initializeShadeRoot } from '../initialize.js';
5
- import { createComponent } from '../shade-component.js';
6
- import { flushUpdates } from '../shade.js';
7
- import { LinkToRoute } from './link-to-route.js';
8
- describe('LinkToRoute', () => {
9
- beforeEach(() => {
10
- document.body.innerHTML = '<div id="root"></div>';
11
- });
12
- afterEach(() => {
13
- document.body.innerHTML = '';
14
- });
15
- it('Shuld display the loader and completed state', async () => {
16
- await usingAsync(new Injector(), async (injector) => {
17
- const rootElement = document.getElementById('root');
18
- initializeShadeRoot({
19
- injector,
20
- rootElement,
21
- jsxElement: (createComponent(LinkToRoute, { route: {
22
- url: '/subroute/:id',
23
- }, params: { id: 123 }, id: "route" }, "Link")),
24
- });
25
- await flushUpdates();
26
- expect(document.body.innerHTML).toBe('<div id="root"><a is="link-to-route" id="route" href="/subroute/123">Link</a></div>');
27
- });
28
- });
29
- });
30
- //# sourceMappingURL=link-to-route.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"link-to-route.spec.js","sourceRoot":"","sources":["../../src/components/link-to-route.spec.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGhD,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,uBAAuB,CAAA;IACnD,CAAC,CAAC,CAAA;IACF,SAAS,CAAC,GAAG,EAAE;QACb,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IAC9B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,UAAU,CAAC,IAAI,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YAClD,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAmB,CAAA;YAErE,mBAAmB,CAAC;gBAClB,QAAQ;gBACR,WAAW;gBACX,UAAU,EAAE,CACV,gBAAC,WAAW,IACV,KAAK,EACH;wBACE,GAAG,EAAE,eAAe;qBACI,EAE5B,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EACnB,EAAE,EAAC,OAAO,WAGE,CACf;aACF,CAAC,CAAA;YACF,MAAM,YAAY,EAAE,CAAA;YACpB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAClC,qFAAqF,CACtF,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,10 +0,0 @@
1
- import type { PartialElement } from '../models/partial-element.js';
2
- /** @deprecated Use `NestedRouteLinkProps` from `nested-route-link` instead */
3
- export type RouteLinkProps = PartialElement<Omit<HTMLAnchorElement, 'onclick'>>;
4
- /** @deprecated Use `NestedRouteLink` from `nested-route-link` instead */
5
- export declare const RouteLink: (props: Omit<Partial<Omit<HTMLAnchorElement, "onclick">>, "style"> & {
6
- style?: Partial<CSSStyleDeclaration>;
7
- } & {
8
- ref?: import("../index.js").RefObject<Element>;
9
- } & Omit<Partial<HTMLElement>, "style">, children?: import("../index.js").ChildrenList) => JSX.Element;
10
- //# sourceMappingURL=route-link.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-link.d.ts","sourceRoot":"","sources":["../../src/components/route-link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAKlE,8EAA8E;AAC9E,MAAM,MAAM,cAAc,GAAG,cAAc,CAAC,IAAI,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC,CAAA;AAE/E,yEAAyE;AACzE,eAAO,MAAM,SAAS;;;;sGAmBpB,CAAA"}
@@ -1,25 +0,0 @@
1
- import { LocationService } from '../services/location-service.js';
2
- import { createComponent } from '../shade-component.js';
3
- import { Shade } from '../shade.js';
4
- /** @deprecated Use `NestedRouteLink` from `nested-route-link` instead */
5
- export const RouteLink = Shade({
6
- customElementName: 'route-link',
7
- elementBase: HTMLAnchorElement,
8
- elementBaseName: 'a',
9
- css: {
10
- color: 'inherit',
11
- textDecoration: 'inherit',
12
- },
13
- render: ({ children, props, injector, useHostProps }) => {
14
- useHostProps({
15
- onclick: (ev) => {
16
- ev.preventDefault();
17
- // eslint-disable-next-line furystack/prefer-location-service -- Deprecated framework component; must call pushState directly.
18
- history.pushState('', props.title || '', props.href);
19
- injector.getInstance(LocationService).updateState();
20
- },
21
- });
22
- return createComponent(createComponent, null, children);
23
- },
24
- });
25
- //# sourceMappingURL=route-link.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-link.js","sourceRoot":"","sources":["../../src/components/route-link.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAKnC,yEAAyE;AACzE,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAiB;IAC7C,iBAAiB,EAAE,YAAY;IAC/B,WAAW,EAAE,iBAAiB;IAC9B,eAAe,EAAE,GAAG;IACpB,GAAG,EAAE;QACH,KAAK,EAAE,SAAS;QAChB,cAAc,EAAE,SAAS;KAC1B;IACD,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE;QACtD,YAAY,CAAC;YACX,OAAO,EAAE,CAAC,EAAc,EAAE,EAAE;gBAC1B,EAAE,CAAC,cAAc,EAAE,CAAA;gBACnB,8HAA8H;gBAC9H,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;gBACpD,QAAQ,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,WAAW,EAAE,CAAA;YACrD,CAAC;SACF,CAAC,CAAA;QACF,OAAO,uCAAG,QAAQ,CAAI,CAAA;IACxB,CAAC;CACF,CAAC,CAAA"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=route-link.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-link.spec.d.ts","sourceRoot":"","sources":["../../src/components/route-link.spec.tsx"],"names":[],"mappings":""}
@@ -1,34 +0,0 @@
1
- import { Injector } from '@furystack/inject';
2
- import { usingAsync } from '@furystack/utils';
3
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { initializeShadeRoot } from '../initialize.js';
5
- import { LocationService } from '../services/location-service.js';
6
- import { createComponent } from '../shade-component.js';
7
- import { flushUpdates } from '../shade.js';
8
- import { RouteLink } from './route-link.js';
9
- describe('RouteLink', () => {
10
- beforeEach(() => {
11
- document.body.innerHTML = '<div id="root"></div>';
12
- });
13
- afterEach(() => {
14
- document.body.innerHTML = '';
15
- });
16
- it('Shuld display the loader and completed state', async () => {
17
- await usingAsync(new Injector(), async (injector) => {
18
- const rootElement = document.getElementById('root');
19
- const onRouteChange = vi.fn();
20
- injector.getInstance(LocationService).onLocationPathChanged.subscribe(onRouteChange);
21
- initializeShadeRoot({
22
- injector,
23
- rootElement,
24
- jsxElement: (createComponent(RouteLink, { id: "route", href: "/subroute" }, "Link")),
25
- });
26
- await flushUpdates();
27
- expect(document.body.innerHTML).toMatchInlineSnapshot(`"<div id="root"><a is="route-link" id="route" href="/subroute">Link</a></div>"`);
28
- expect(onRouteChange).not.toBeCalled();
29
- document.getElementById('route')?.click();
30
- expect(onRouteChange).toBeCalledTimes(1);
31
- });
32
- });
33
- });
34
- //# sourceMappingURL=route-link.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-link.spec.js","sourceRoot":"","sources":["../../src/components/route-link.spec.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,uBAAuB,CAAA;IACnD,CAAC,CAAC,CAAA;IACF,SAAS,CAAC,GAAG,EAAE;QACb,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IAC9B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,UAAU,CAAC,IAAI,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YAClD,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAmB,CAAA;YAErE,MAAM,aAAa,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;YAE7B,QAAQ,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,qBAAqB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;YAEpF,mBAAmB,CAAC;gBAClB,QAAQ;gBACR,WAAW;gBACX,UAAU,EAAE,CACV,gBAAC,SAAS,IAAC,EAAE,EAAC,OAAO,EAAC,IAAI,EAAC,WAAW,WAE1B,CACb;aACF,CAAC,CAAA;YACF,MAAM,YAAY,EAAE,CAAA;YACpB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,qBAAqB,CACnD,gFAAgF,CACjF,CAAA;YACD,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,CAAA;YACtC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAA;YACzC,MAAM,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,44 +0,0 @@
1
- import type { MatchOptions, MatchResult } from 'path-to-regexp';
2
- import type { RenderOptions } from '../models/render-options.js';
3
- /**
4
- * @deprecated Use NestedRouter instead
5
- */
6
- export interface Route<TMatchResult = unknown> {
7
- url: string;
8
- component: (options: {
9
- currentUrl: string;
10
- match: MatchResult<TMatchResult extends object ? TMatchResult : object>;
11
- }) => JSX.Element;
12
- routingOptions?: MatchOptions;
13
- onVisit?: (options: RenderOptions<unknown> & {
14
- element: JSX.Element;
15
- }) => Promise<void>;
16
- onLeave?: (options: RenderOptions<unknown> & {
17
- element: JSX.Element;
18
- }) => Promise<void>;
19
- }
20
- /**
21
- * @deprecated Use NestedRouterProps instead
22
- */
23
- export interface RouterProps {
24
- style?: CSSStyleDeclaration;
25
- routes: Array<Route<any>>;
26
- notFound?: JSX.Element;
27
- }
28
- /**
29
- * @deprecated Use NestedRouterState instead
30
- */
31
- export interface RouterState {
32
- activeRoute?: Route<unknown> | null;
33
- activeRouteParams?: unknown;
34
- jsx: JSX.Element;
35
- }
36
- /**
37
- * @deprecated Use NestedRouter instead
38
- */
39
- export declare const Router: (props: RouterProps & Omit<Partial<HTMLElement>, "style"> & {
40
- style?: Partial<CSSStyleDeclaration>;
41
- } & {
42
- ref?: import("../models/render-options.js").RefObject<Element>;
43
- }, children?: import("../index.js").ChildrenList) => JSX.Element;
44
- //# sourceMappingURL=router.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/components/router.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAKhE;;GAEG;AACH,MAAM,WAAW,KAAK,CAAC,YAAY,GAAG,OAAO;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,CAAC,OAAO,EAAE;QACnB,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,EAAE,WAAW,CAAC,YAAY,SAAS,MAAM,GAAG,YAAY,GAAG,MAAM,CAAC,CAAA;KACxE,KAAK,GAAG,CAAC,OAAO,CAAA;IACjB,cAAc,CAAC,EAAE,YAAY,CAAA;IAC7B,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG;QAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG;QAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACxF;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,mBAAmB,CAAA;IAC3B,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;IACzB,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;IACnC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,GAAG,EAAE,GAAG,CAAC,OAAO,CAAA;CACjB;AAED;;GAEG;AACH,eAAO,MAAM,MAAM;;;;gEA2DjB,CAAA"}
@@ -1,66 +0,0 @@
1
- import { ObservableAlreadyDisposedError } from '@furystack/utils';
2
- import { match } from 'path-to-regexp';
3
- import { LocationService } from '../services/location-service.js';
4
- import { createComponent } from '../shade-component.js';
5
- import { Shade } from '../shade.js';
6
- /**
7
- * @deprecated Use NestedRouter instead
8
- */
9
- export const Router = Shade({
10
- customElementName: 'shade-router',
11
- render: (options) => {
12
- const { useState, useObservable, injector } = options;
13
- const [versionRef] = useState('navVersion', { current: 0 });
14
- const [state, setState] = useState('routerState', {
15
- jsx: createComponent("div", null),
16
- });
17
- const updateUrl = async (currentUrl) => {
18
- const [lastState] = useState('routerState', state);
19
- const { activeRoute: lastRoute, activeRouteParams: lastRouteParams, jsx: lastJsx } = lastState;
20
- try {
21
- for (const route of options.props.routes) {
22
- const matchFn = match(route.url, route.routingOptions);
23
- const matchResult = matchFn(currentUrl);
24
- if (matchResult) {
25
- if (route !== lastRoute || JSON.stringify(lastRouteParams) !== JSON.stringify(matchResult.params)) {
26
- const version = ++versionRef.current;
27
- await lastRoute?.onLeave?.({ ...options, element: lastState.jsx });
28
- if (version !== versionRef.current)
29
- return;
30
- const newJsx = route.component({ currentUrl, match: matchResult });
31
- setState({ jsx: newJsx, activeRoute: route, activeRouteParams: matchResult.params });
32
- await route.onVisit?.({ ...options, element: newJsx });
33
- if (version !== versionRef.current)
34
- return;
35
- }
36
- return;
37
- }
38
- }
39
- if (lastRoute !== null) {
40
- const version = ++versionRef.current;
41
- await lastRoute?.onLeave?.({ ...options, element: lastJsx });
42
- if (version !== versionRef.current)
43
- return;
44
- setState({
45
- jsx: options.props.notFound || createComponent("div", null),
46
- activeRoute: null,
47
- activeRouteParams: null,
48
- });
49
- }
50
- }
51
- catch (e) {
52
- if (!(e instanceof ObservableAlreadyDisposedError)) {
53
- throw e;
54
- }
55
- }
56
- };
57
- const [locationPath] = useObservable('locationPathChanged', injector.getInstance(LocationService).onLocationPathChanged, {
58
- onChange: (newValue) => {
59
- void updateUrl(newValue);
60
- },
61
- });
62
- void updateUrl(locationPath);
63
- return state.jsx;
64
- },
65
- });
66
- //# sourceMappingURL=router.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/components/router.tsx"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=router.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.spec.d.ts","sourceRoot":"","sources":["../../src/components/router.spec.tsx"],"names":[],"mappings":""}
@@ -1,161 +0,0 @@
1
- import { Injector } from '@furystack/inject';
2
- import { sleepAsync, usingAsync } from '@furystack/utils';
3
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { initializeShadeRoot } from '../initialize.js';
5
- import { LocationService } from '../services/location-service.js';
6
- import { createComponent } from '../shade-component.js';
7
- import { flushUpdates } from '../shade.js';
8
- import { RouteLink } from './route-link.js';
9
- import { Router } from './router.js';
10
- describe('Router', () => {
11
- beforeEach(() => {
12
- document.body.innerHTML = '<div id="root"></div>';
13
- });
14
- afterEach(() => {
15
- document.body.innerHTML = '';
16
- });
17
- it('should skip intermediate route when navigating rapidly (latest wins)', async () => {
18
- await usingAsync(new Injector(), async (injector) => {
19
- history.pushState(null, '', '/route-a');
20
- const callOrder = [];
21
- const onVisitA = vi.fn(async () => {
22
- callOrder.push('visit-a');
23
- });
24
- const onLeaveA = vi.fn(async () => {
25
- callOrder.push('leave-a');
26
- });
27
- const onVisitB = vi.fn(async () => {
28
- await sleepAsync(200);
29
- callOrder.push('visit-b');
30
- });
31
- const onLeaveB = vi.fn(async () => {
32
- callOrder.push('leave-b');
33
- });
34
- const onVisitC = vi.fn(async () => {
35
- callOrder.push('visit-c');
36
- });
37
- const routeA = {
38
- url: '/route-a',
39
- component: () => createComponent("div", { id: "content" }, "route-a"),
40
- onVisit: onVisitA,
41
- onLeave: onLeaveA,
42
- };
43
- const routeB = {
44
- url: '/route-b',
45
- component: () => createComponent("div", { id: "content" }, "route-b"),
46
- onVisit: onVisitB,
47
- onLeave: onLeaveB,
48
- };
49
- const routeC = {
50
- url: '/route-c',
51
- component: () => createComponent("div", { id: "content" }, "route-c"),
52
- onVisit: onVisitC,
53
- };
54
- const rootElement = document.getElementById('root');
55
- initializeShadeRoot({
56
- injector,
57
- rootElement,
58
- jsxElement: (createComponent("div", null,
59
- createComponent(RouteLink, { id: "go-a", href: "/route-a" }, "a"),
60
- createComponent(RouteLink, { id: "go-b", href: "/route-b" }, "b"),
61
- createComponent(RouteLink, { id: "go-c", href: "/route-c" }, "c"),
62
- createComponent(Router, { routes: [routeA, routeB, routeC] }))),
63
- });
64
- const getContent = () => document.getElementById('content')?.innerHTML;
65
- const clickOn = (name) => document.getElementById(name)?.click();
66
- // --- Initial load at /route-a ---
67
- await flushUpdates();
68
- expect(getContent()).toBe('route-a');
69
- expect(onVisitA).toHaveBeenCalledTimes(1);
70
- // --- Rapid navigation: click B then immediately C ---
71
- callOrder.length = 0;
72
- clickOn('go-b');
73
- clickOn('go-c');
74
- // Wait long enough for both transitions to settle (onVisitB has 200ms delay)
75
- await sleepAsync(500);
76
- // The final destination should be route-c
77
- expect(getContent()).toBe('route-c');
78
- expect(onVisitC).toHaveBeenCalledTimes(1);
79
- // route-b's onVisit should have been abandoned
80
- expect(callOrder).not.toContain('visit-b');
81
- });
82
- });
83
- it('Shuld display the loader and completed state', async () => {
84
- await usingAsync(new Injector(), async (injector) => {
85
- history.pushState(null, '', '/');
86
- const onVisit = vi.fn();
87
- const onLeave = vi.fn();
88
- const onLastLeave = vi.fn();
89
- const rootElement = document.getElementById('root');
90
- const onRouteChange = vi.fn();
91
- injector.getInstance(LocationService).onLocationPathChanged.subscribe(onRouteChange);
92
- const route1 = {
93
- url: '/route-a',
94
- component: () => createComponent("div", { id: "content" }, "route-a"),
95
- onVisit,
96
- onLeave,
97
- };
98
- const route2 = {
99
- url: '/route-b{/:id}',
100
- component: ({ match }) => createComponent("div", { id: "content" },
101
- "route-b",
102
- match.params.id),
103
- };
104
- const route3 = {
105
- url: '/route-c',
106
- component: () => createComponent("div", { id: "content" }, "route-c"),
107
- onLeave: onLastLeave,
108
- };
109
- const route4 = { url: '/', component: () => createComponent("div", { id: "content" }, "home") };
110
- initializeShadeRoot({
111
- injector,
112
- rootElement,
113
- jsxElement: (createComponent("div", null,
114
- createComponent(RouteLink, { id: "home", href: "/" }, "home"),
115
- createComponent(RouteLink, { id: "a", href: "/route-a" }, "a"),
116
- createComponent(RouteLink, { id: "b", href: "/route-b" }, "b"),
117
- createComponent(RouteLink, { id: "b-with-id", href: "/route-b/123" }, "b-with-id"),
118
- createComponent(RouteLink, { id: "c", href: "/route-c" }, "c"),
119
- createComponent(RouteLink, { id: "x", href: "/route-x" }, "x"),
120
- createComponent(Router, { routes: [route1, route2, route3, route4], notFound: createComponent("div", { id: "content" }, "not found") }))),
121
- });
122
- const getContent = () => document.getElementById('content')?.innerHTML;
123
- const getLocation = () => location.pathname;
124
- const clickOn = (name) => document.getElementById(name)?.click();
125
- await flushUpdates();
126
- expect(getLocation()).toBe('/');
127
- expect(getContent()).toBe('home');
128
- expect(onVisit).not.toBeCalled();
129
- clickOn('a');
130
- await flushUpdates();
131
- expect(getContent()).toBe('route-a');
132
- expect(getLocation()).toBe('/route-a');
133
- expect(onRouteChange).toBeCalledTimes(1);
134
- expect(onVisit).toBeCalledTimes(1);
135
- clickOn('a');
136
- await flushUpdates();
137
- expect(onVisit).toBeCalledTimes(1);
138
- expect(onLeave).not.toBeCalled();
139
- clickOn('b');
140
- await flushUpdates();
141
- expect(onLeave).toBeCalledTimes(1);
142
- expect(getContent()).toBe('route-b');
143
- expect(getLocation()).toBe('/route-b');
144
- clickOn('b-with-id');
145
- await flushUpdates();
146
- expect(getContent()).toBe('route-b123');
147
- expect(getLocation()).toBe('/route-b/123');
148
- clickOn('c');
149
- await flushUpdates();
150
- expect(getContent()).toBe('route-c');
151
- expect(getLocation()).toBe('/route-c');
152
- expect(onLastLeave).not.toBeCalled();
153
- clickOn('x');
154
- await flushUpdates();
155
- expect(getContent()).toBe('not found');
156
- expect(getLocation()).toBe('/route-x');
157
- expect(onLastLeave).toBeCalledTimes(1);
158
- });
159
- });
160
- });
161
- //# sourceMappingURL=router.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.spec.js","sourceRoot":"","sources":["../../src/components/router.spec.tsx"],"names":[],"mappings":"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"}
@@ -1,45 +0,0 @@
1
- import { Injector } from '@furystack/inject'
2
- import { usingAsync } from '@furystack/utils'
3
- import { afterEach, beforeEach, describe, expect, it } from 'vitest'
4
- import { initializeShadeRoot } from '../initialize.js'
5
- import { createComponent } from '../shade-component.js'
6
- import { flushUpdates } from '../shade.js'
7
- import { LinkToRoute } from './link-to-route.js'
8
- import type { Route } from './router.js'
9
-
10
- describe('LinkToRoute', () => {
11
- beforeEach(() => {
12
- document.body.innerHTML = '<div id="root"></div>'
13
- })
14
- afterEach(() => {
15
- document.body.innerHTML = ''
16
- })
17
-
18
- it('Shuld display the loader and completed state', async () => {
19
- await usingAsync(new Injector(), async (injector) => {
20
- const rootElement = document.getElementById('root') as HTMLDivElement
21
-
22
- initializeShadeRoot({
23
- injector,
24
- rootElement,
25
- jsxElement: (
26
- <LinkToRoute
27
- route={
28
- {
29
- url: '/subroute/:id',
30
- } as Route<{ id: number }>
31
- }
32
- params={{ id: 123 }}
33
- id="route"
34
- >
35
- Link
36
- </LinkToRoute>
37
- ),
38
- })
39
- await flushUpdates()
40
- expect(document.body.innerHTML).toBe(
41
- '<div id="root"><a is="link-to-route" id="route" href="/subroute/123">Link</a></div>',
42
- )
43
- })
44
- })
45
- })
@@ -1,26 +0,0 @@
1
- import { compileRoute } from '../compile-route.js'
2
- import type { ChildrenList } from '../models/children-list.js'
3
- import { createComponent } from '../shade-component.js'
4
- import { Shade } from '../shade.js'
5
- import type { Route } from './router.js'
6
-
7
- /** @deprecated Use `NestedRouteLinkProps` from `nested-route-link` instead */
8
- export type LinkToRouteProps<T extends object> = {
9
- route: Route<T>
10
- params: T
11
- } & Omit<JSX.IntrinsicElements['a'], 'href'>
12
-
13
- /** @deprecated Use `NestedRouteLink` from `nested-route-link` instead */
14
- export const LinkToRoute: <T extends object>(props: LinkToRouteProps<T>, children?: ChildrenList) => JSX.Element =
15
- Shade({
16
- customElementName: 'link-to-route',
17
- elementBase: HTMLAnchorElement,
18
- elementBaseName: 'a',
19
- render: ({ props, useHostProps, children }) => {
20
- const { route, params } = props
21
-
22
- const url = compileRoute(route.url, params)
23
- useHostProps({ href: url })
24
- return <>{children}</>
25
- },
26
- })