@furystack/shades 11.1.0 → 12.0.1

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 (166) hide show
  1. package/CHANGELOG.md +312 -0
  2. package/README.md +13 -13
  3. package/esm/component-factory.spec.js +13 -5
  4. package/esm/component-factory.spec.js.map +1 -1
  5. package/esm/components/index.d.ts +4 -1
  6. package/esm/components/index.d.ts.map +1 -1
  7. package/esm/components/index.js +4 -1
  8. package/esm/components/index.js.map +1 -1
  9. package/esm/components/lazy-load.d.ts +2 -4
  10. package/esm/components/lazy-load.d.ts.map +1 -1
  11. package/esm/components/lazy-load.js +40 -24
  12. package/esm/components/lazy-load.js.map +1 -1
  13. package/esm/components/lazy-load.spec.js +57 -50
  14. package/esm/components/lazy-load.spec.js.map +1 -1
  15. package/esm/components/link-to-route.d.ts +2 -0
  16. package/esm/components/link-to-route.d.ts.map +1 -1
  17. package/esm/components/link-to-route.js +3 -2
  18. package/esm/components/link-to-route.js.map +1 -1
  19. package/esm/components/link-to-route.spec.js +13 -9
  20. package/esm/components/link-to-route.spec.js.map +1 -1
  21. package/esm/components/nested-route-link.d.ts +62 -0
  22. package/esm/components/nested-route-link.d.ts.map +1 -0
  23. package/esm/components/nested-route-link.js +66 -0
  24. package/esm/components/nested-route-link.js.map +1 -0
  25. package/esm/components/nested-route-link.spec.d.ts +2 -0
  26. package/esm/components/nested-route-link.spec.d.ts.map +1 -0
  27. package/esm/components/nested-route-link.spec.js +179 -0
  28. package/esm/components/nested-route-link.spec.js.map +1 -0
  29. package/esm/components/nested-route-types.d.ts +37 -0
  30. package/esm/components/nested-route-types.d.ts.map +1 -0
  31. package/esm/components/nested-route-types.js +2 -0
  32. package/esm/components/nested-route-types.js.map +1 -0
  33. package/esm/components/nested-router.d.ts +103 -0
  34. package/esm/components/nested-router.d.ts.map +1 -0
  35. package/esm/components/nested-router.js +183 -0
  36. package/esm/components/nested-router.js.map +1 -0
  37. package/esm/components/nested-router.spec.d.ts +2 -0
  38. package/esm/components/nested-router.spec.d.ts.map +1 -0
  39. package/esm/components/nested-router.spec.js +737 -0
  40. package/esm/components/nested-router.spec.js.map +1 -0
  41. package/esm/components/route-link.d.ts +4 -0
  42. package/esm/components/route-link.d.ts.map +1 -1
  43. package/esm/components/route-link.js +5 -5
  44. package/esm/components/route-link.js.map +1 -1
  45. package/esm/components/route-link.spec.js +16 -12
  46. package/esm/components/route-link.spec.js.map +1 -1
  47. package/esm/components/router.d.ts +20 -2
  48. package/esm/components/router.d.ts.map +1 -1
  49. package/esm/components/router.js +12 -7
  50. package/esm/components/router.js.map +1 -1
  51. package/esm/components/router.spec.js +141 -74
  52. package/esm/components/router.spec.js.map +1 -1
  53. package/esm/initialize.d.ts +11 -0
  54. package/esm/initialize.d.ts.map +1 -1
  55. package/esm/initialize.js +5 -0
  56. package/esm/initialize.js.map +1 -1
  57. package/esm/jsx.d.ts +83 -2
  58. package/esm/jsx.d.ts.map +1 -1
  59. package/esm/models/children-list.d.ts +5 -1
  60. package/esm/models/children-list.d.ts.map +1 -1
  61. package/esm/models/partial-element.d.ts +12 -2
  62. package/esm/models/partial-element.d.ts.map +1 -1
  63. package/esm/models/render-options.d.ts +89 -3
  64. package/esm/models/render-options.d.ts.map +1 -1
  65. package/esm/models/selection-state.d.ts +4 -0
  66. package/esm/models/selection-state.d.ts.map +1 -1
  67. package/esm/services/location-service.d.ts +11 -0
  68. package/esm/services/location-service.d.ts.map +1 -1
  69. package/esm/services/location-service.js +11 -0
  70. package/esm/services/location-service.js.map +1 -1
  71. package/esm/services/resource-manager.d.ts +24 -0
  72. package/esm/services/resource-manager.d.ts.map +1 -1
  73. package/esm/services/resource-manager.js +36 -1
  74. package/esm/services/resource-manager.js.map +1 -1
  75. package/esm/services/resource-manager.spec.js +102 -0
  76. package/esm/services/resource-manager.spec.js.map +1 -1
  77. package/esm/services/screen-service.d.ts +81 -4
  78. package/esm/services/screen-service.d.ts.map +1 -1
  79. package/esm/services/screen-service.js +75 -4
  80. package/esm/services/screen-service.js.map +1 -1
  81. package/esm/services/screen-service.spec.js +91 -7
  82. package/esm/services/screen-service.spec.js.map +1 -1
  83. package/esm/shade-component.d.ts +17 -4
  84. package/esm/shade-component.d.ts.map +1 -1
  85. package/esm/shade-component.js +67 -5
  86. package/esm/shade-component.js.map +1 -1
  87. package/esm/shade-host-props-ref.integration.spec.d.ts +2 -0
  88. package/esm/shade-host-props-ref.integration.spec.d.ts.map +1 -0
  89. package/esm/shade-host-props-ref.integration.spec.js +381 -0
  90. package/esm/shade-host-props-ref.integration.spec.js.map +1 -0
  91. package/esm/shade-resources.integration.spec.js +208 -39
  92. package/esm/shade-resources.integration.spec.js.map +1 -1
  93. package/esm/shade.d.ts +20 -17
  94. package/esm/shade.d.ts.map +1 -1
  95. package/esm/shade.js +172 -33
  96. package/esm/shade.js.map +1 -1
  97. package/esm/shade.spec.js +31 -30
  98. package/esm/shade.spec.js.map +1 -1
  99. package/esm/shades.integration.spec.js +135 -72
  100. package/esm/shades.integration.spec.js.map +1 -1
  101. package/esm/style-manager.d.ts +2 -2
  102. package/esm/style-manager.js +2 -2
  103. package/esm/svg-types.d.ts +389 -0
  104. package/esm/svg-types.d.ts.map +1 -0
  105. package/esm/svg-types.js +9 -0
  106. package/esm/svg-types.js.map +1 -0
  107. package/esm/svg.d.ts +15 -0
  108. package/esm/svg.d.ts.map +1 -0
  109. package/esm/svg.js +76 -0
  110. package/esm/svg.js.map +1 -0
  111. package/esm/svg.spec.d.ts +2 -0
  112. package/esm/svg.spec.d.ts.map +1 -0
  113. package/esm/svg.spec.js +80 -0
  114. package/esm/svg.spec.js.map +1 -0
  115. package/esm/vnode.d.ts +103 -0
  116. package/esm/vnode.d.ts.map +1 -0
  117. package/esm/vnode.integration.spec.d.ts +2 -0
  118. package/esm/vnode.integration.spec.d.ts.map +1 -0
  119. package/esm/vnode.integration.spec.js +494 -0
  120. package/esm/vnode.integration.spec.js.map +1 -0
  121. package/esm/vnode.js +453 -0
  122. package/esm/vnode.js.map +1 -0
  123. package/esm/vnode.spec.d.ts +2 -0
  124. package/esm/vnode.spec.d.ts.map +1 -0
  125. package/esm/vnode.spec.js +473 -0
  126. package/esm/vnode.spec.js.map +1 -0
  127. package/package.json +8 -9
  128. package/src/component-factory.spec.tsx +18 -5
  129. package/src/components/index.ts +4 -1
  130. package/src/components/lazy-load.spec.tsx +82 -75
  131. package/src/components/lazy-load.tsx +49 -27
  132. package/src/components/link-to-route.spec.tsx +25 -21
  133. package/src/components/link-to-route.tsx +4 -2
  134. package/src/components/nested-route-link.spec.tsx +303 -0
  135. package/src/components/nested-route-link.tsx +100 -0
  136. package/src/components/nested-route-types.ts +42 -0
  137. package/src/components/nested-router.spec.tsx +918 -0
  138. package/src/components/nested-router.tsx +260 -0
  139. package/src/components/route-link.spec.tsx +22 -18
  140. package/src/components/route-link.tsx +6 -5
  141. package/src/components/router.spec.tsx +196 -108
  142. package/src/components/router.tsx +21 -8
  143. package/src/initialize.ts +12 -0
  144. package/src/jsx.ts +129 -2
  145. package/src/models/children-list.ts +7 -1
  146. package/src/models/partial-element.ts +13 -2
  147. package/src/models/render-options.ts +90 -3
  148. package/src/models/selection-state.ts +4 -0
  149. package/src/services/location-service.tsx +11 -0
  150. package/src/services/resource-manager.spec.ts +128 -0
  151. package/src/services/resource-manager.ts +36 -1
  152. package/src/services/screen-service.spec.ts +109 -7
  153. package/src/services/screen-service.ts +81 -4
  154. package/src/shade-component.ts +72 -6
  155. package/src/shade-host-props-ref.integration.spec.tsx +460 -0
  156. package/src/shade-resources.integration.spec.tsx +276 -52
  157. package/src/shade.spec.tsx +40 -39
  158. package/src/shade.ts +186 -58
  159. package/src/shades.integration.spec.tsx +154 -80
  160. package/src/style-manager.ts +2 -2
  161. package/src/svg-types.ts +437 -0
  162. package/src/svg.spec.ts +89 -0
  163. package/src/svg.ts +78 -0
  164. package/src/vnode.integration.spec.tsx +657 -0
  165. package/src/vnode.spec.ts +579 -0
  166. package/src/vnode.ts +508 -0
@@ -0,0 +1,100 @@
1
+ import { compileRoute } from '../compile-route.js'
2
+ import type { ChildrenList } from '../models/children-list.js'
3
+ import type { PartialElement } from '../models/partial-element.js'
4
+ import { LocationService } from '../services/location-service.js'
5
+ import { createComponent } from '../shade-component.js'
6
+ import { Shade } from '../shade.js'
7
+ import type { ExtractRouteParams, ExtractRoutePaths } from './nested-route-types.js'
8
+ import type { NestedRoute } from './nested-router.js'
9
+
10
+ /**
11
+ * Props for the NestedRouteLink component.
12
+ * Combines SPA navigation from RouteLink with parameter compilation from LinkToRoute.
13
+ */
14
+ export type NestedRouteLinkProps = {
15
+ href: string
16
+ params?: Record<string, string>
17
+ } & PartialElement<Omit<HTMLAnchorElement, 'onclick' | 'href'>>
18
+
19
+ /**
20
+ * Props for a type-safe nested route link.
21
+ * When the path contains parameters (e.g. `:id`), the `params` prop becomes required.
22
+ * @typeParam TPath - A specific route path string
23
+ */
24
+ export type TypedNestedRouteLinkProps<TPath extends string> = {
25
+ href: TPath
26
+ } & (string extends keyof ExtractRouteParams<TPath>
27
+ ? { params?: Record<string, string> }
28
+ : { params: ExtractRouteParams<TPath> }) &
29
+ PartialElement<Omit<HTMLAnchorElement, 'onclick' | 'href'>>
30
+
31
+ const _NestedRouteLink = Shade<NestedRouteLinkProps>({
32
+ shadowDomName: 'nested-route-link',
33
+ elementBase: HTMLAnchorElement,
34
+ elementBaseName: 'a',
35
+ css: {
36
+ color: 'inherit',
37
+ textDecoration: 'inherit',
38
+ },
39
+ render: ({ children, props, injector, useHostProps }) => {
40
+ const { href, params } = props
41
+ const resolvedUrl = params ? compileRoute(href, params) : href
42
+
43
+ useHostProps({
44
+ href: resolvedUrl,
45
+ onclick: (ev: MouseEvent) => {
46
+ ev.preventDefault()
47
+ history.pushState('', props.title || '', resolvedUrl)
48
+ injector.getInstance(LocationService).updateState()
49
+ },
50
+ })
51
+ return <>{children}</>
52
+ },
53
+ })
54
+
55
+ /**
56
+ * A link component for NestedRouter that supports SPA navigation with
57
+ * type-safe route parameter compilation.
58
+ *
59
+ * Intercepts click events to use `history.pushState` for client-side navigation,
60
+ * and compiles parameterized routes (e.g. `/users/:id`) when `params` is provided.
61
+ *
62
+ * Route parameters are automatically inferred from the `href` pattern:
63
+ * - `href="/buttons"` — `params` is optional
64
+ * - `href="/users/:id"` — `params: { id: string }` is required
65
+ *
66
+ * For additional URL validation against a route tree, use {@link createNestedRouteLink}.
67
+ */
68
+ export const NestedRouteLink = _NestedRouteLink as unknown as <TPath extends string = string>(
69
+ props: TypedNestedRouteLinkProps<TPath>,
70
+ children?: ChildrenList,
71
+ ) => JSX.Element
72
+
73
+ /**
74
+ * Creates a type-safe wrapper around NestedRouteLink constrained to a specific route tree.
75
+ * The returned component has the same runtime behavior but narrows `href` to only accept
76
+ * valid route paths, and requires `params` when the route has parameters.
77
+ *
78
+ * @typeParam TRoutes - The route tree type (use `typeof yourRoutes`)
79
+ * @returns A narrowed NestedRouteLink component
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const AppLink = createNestedRouteLink<typeof appRoutes>()
84
+ *
85
+ * // Type-safe: only valid paths accepted
86
+ * <AppLink href="/buttons">Buttons</AppLink>
87
+ *
88
+ * // TypeScript error: invalid path
89
+ * <AppLink href="/nonexistent">Error!</AppLink>
90
+ *
91
+ * // Params required for parameterized routes
92
+ * <AppLink href="/users/:id" params={{ id: '123' }}>User</AppLink>
93
+ * ```
94
+ */
95
+ export const createNestedRouteLink = <TRoutes extends Record<string, NestedRoute<unknown>>>() => {
96
+ return _NestedRouteLink as unknown as <TPath extends ExtractRoutePaths<TRoutes>>(
97
+ props: TypedNestedRouteLinkProps<TPath>,
98
+ children?: ChildrenList,
99
+ ) => JSX.Element
100
+ }
@@ -0,0 +1,42 @@
1
+ import type { NestedRoute } from './nested-router.js'
2
+
3
+ /**
4
+ * Concatenates parent and child route paths, handling the '/' root specially
5
+ * to avoid double slashes.
6
+ * @typeParam Parent - The parent route path
7
+ * @typeParam Child - The child route path
8
+ */
9
+ export type ConcatPaths<Parent extends string, Child extends string> = Parent extends '/' ? Child : `${Parent}${Child}`
10
+
11
+ /**
12
+ * Recursively extracts all valid full URL paths from a nested route tree.
13
+ * @typeParam T - A record of route patterns to NestedRoute definitions
14
+ */
15
+ export type ExtractRoutePaths<T extends Record<string, NestedRoute<unknown>>> = {
16
+ [K in keyof T & string]:
17
+ | K
18
+ | (T[K] extends { children: infer C extends Record<string, NestedRoute<unknown>> }
19
+ ? ConcatPaths<K, ExtractRoutePaths<C> & string>
20
+ : never)
21
+ }[keyof T & string]
22
+
23
+ /**
24
+ * Extracts route parameter names from a URL pattern and creates a record type
25
+ * mapping each parameter name to `string`.
26
+ * Returns `Record<string, never>` when no parameters are present.
27
+ * @typeParam T - A URL pattern string potentially containing `:param` segments
28
+ */
29
+ export type ExtractRouteParams<T extends string> = T extends `${string}:${infer Param}/${infer Rest}`
30
+ ? { [K in Param | keyof ExtractRouteParams<`/${Rest}`>]: string }
31
+ : T extends `${string}:${infer Param}`
32
+ ? { [K in Param]: string }
33
+ : Record<string, never>
34
+
35
+ /**
36
+ * A recursive type for validating URL constant objects against a set of valid paths.
37
+ * Leaf values must be valid route paths, and intermediate values can be nested UrlTree objects.
38
+ * @typeParam TPaths - Union of valid route path strings
39
+ */
40
+ export type UrlTree<TPaths extends string> = {
41
+ [key: string]: TPaths | UrlTree<TPaths>
42
+ }