@tempots/ui 5.2.2 → 6.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tempots/ui",
3
- "version": "5.2.2",
3
+ "version": "6.0.1",
4
4
  "type": "module",
5
5
  "main": "./index.cjs",
6
6
  "module": "./index.js",
@@ -0,0 +1,96 @@
1
+ import { Provider, Prop } from '@tempots/dom';
2
+ /**
3
+ * Represents the context information for a router level in nested routing.
4
+ *
5
+ * Each router level (AppRouter or SubRouter) creates a RouterContext that contains
6
+ * information about the matched path, remaining path for child routers, and accumulated
7
+ * parameters from all parent router levels.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // For URL "/admin/users/123" with routes:
12
+ * // RootRouter: { '/admin/*': () => AdminRoutes() }
13
+ * // ChildRouter: { '/users/:id': (info) => UserDetail(info) }
14
+ *
15
+ * // RootRouter context:
16
+ * {
17
+ * matchedPath: '/admin',
18
+ * remainingPath: '/users/123',
19
+ * fullPath: '/admin/users/123',
20
+ * params: {}
21
+ * }
22
+ *
23
+ * // ChildRouter context:
24
+ * {
25
+ * matchedPath: '/users/123',
26
+ * remainingPath: '',
27
+ * fullPath: '/admin/users/123',
28
+ * params: { id: '123' }
29
+ * }
30
+ * ```
31
+ *
32
+ * @public
33
+ */
34
+ export interface RouterContext {
35
+ /**
36
+ * The portion of the path that was matched by this router level.
37
+ * For RootRouter, this is the matched portion of the full pathname.
38
+ * For ChildRouter, this is the matched portion of the remaining path from parent.
39
+ */
40
+ readonly matchedPath: string;
41
+ /**
42
+ * The remaining path that should be processed by child routers.
43
+ * Empty string if no remaining path.
44
+ */
45
+ readonly remainingPath: string;
46
+ /**
47
+ * The full original pathname from the browser location.
48
+ * This remains the same across all router levels.
49
+ */
50
+ readonly fullPath: string;
51
+ /**
52
+ * Route parameters extracted at this router level.
53
+ * These are accumulated with parameters from parent router levels.
54
+ */
55
+ readonly params: Record<string, string>;
56
+ }
57
+ /**
58
+ * Provider for router context stack in nested routing scenarios.
59
+ *
60
+ * The RouterContextProvider maintains a stack of RouterContext objects,
61
+ * where each level represents a router in the nested hierarchy. Child
62
+ * routers can access the context stack to determine what path remains
63
+ * to be processed and what parameters have been accumulated from parent
64
+ * router levels.
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * // RootRouter creates the initial context
69
+ * const RootRouter = <T extends Routes>(routes: T) =>
70
+ * Provide(
71
+ * RouterContextProvider,
72
+ * {},
73
+ * () => {
74
+ * // Router implementation that creates initial context
75
+ * return Use(Location, location => {
76
+ * // Match routes and create context...
77
+ * })
78
+ * }
79
+ * )
80
+ * ```
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * // ChildRouter reads parent context and adds its own
85
+ * const ChildRouter = <T extends Routes>(routes: T) =>
86
+ * Use(RouterContextProvider, contextStack => {
87
+ * const parentContext = contextStack.value[contextStack.value.length - 1]
88
+ * const remainingPath = parentContext?.remainingPath || ''
89
+ *
90
+ * // Match against remaining path and create new context...
91
+ * })
92
+ * ```
93
+ *
94
+ * @public
95
+ */
96
+ export declare const RouterContextProvider: Provider<Prop<RouterContext[]>>;
@@ -1,100 +1,92 @@
1
1
  import { TNode, Renderable, Signal } from '@tempots/dom';
2
2
  import { ExtractParams, MakeParams, RouteInfo } from './route-info';
3
3
  /**
4
- * Creates a client-side router that maps URL patterns to renderable components.
4
+ * Creates the root router for an application that provides routing context to child components.
5
5
  *
6
- * The Router component provides declarative routing for single-page applications.
7
- * It automatically extracts route parameters from URLs and passes them to the
8
- * corresponding route handlers. The router integrates with the browser's history
9
- * API and updates the UI when the URL changes.
6
+ * RootRouter is the top-level router that matches against the full browser pathname
7
+ * and creates the initial routing context. It provides the RouterContextProvider
8
+ * that child ChildRouter components can use for nested routing scenarios.
10
9
  *
11
10
  * @example
12
11
  * ```typescript
13
- * // Basic routing setup
14
- * const AppRouter = Router({
12
+ * // Basic app routing
13
+ * const App = RootRouter({
15
14
  * '/': () => html.div('Home Page'),
16
15
  * '/about': () => html.div('About Page'),
17
- * '/contact': () => html.div('Contact Page'),
16
+ * '/admin/*': () => AdminSection(), // Passes remaining path to AdminSection
18
17
  * '*': () => html.div('404 - Page Not Found')
19
18
  * })
20
19
  *
21
- * render(AppRouter, document.body)
20
+ * render(App, document.body)
22
21
  * ```
23
22
  *
24
23
  * @example
25
24
  * ```typescript
26
- * // Routes with parameters
27
- * const BlogRouter = Router({
28
- * '/': () => html.div('Blog Home'),
29
- * '/posts/:id': (info) => {
30
- * const postId = info.$.params.$.id
31
- * return html.div(
32
- * html.h1('Post ID: ', postId),
33
- * html.p('Loading post...')
34
- * )
35
- * },
36
- * '/users/:userId/posts/:postId': (info) => {
37
- * const userId = info.$.params.$.userId
38
- * const postId = info.$.params.$.postId
39
- * return html.div(
40
- * html.h1('User ', userId, ' - Post ', postId),
41
- * UserPost({ userId, postId })
42
- * )
43
- * },
44
- * '*': () => html.div('Page not found')
25
+ * // Nested routing with RootRouter and ChildRouter
26
+ * const App = RootRouter({
27
+ * '/': () => html.div('Home'),
28
+ * '/admin/*': () => AdminRoutes(),
29
+ * '/blog/*': () => BlogRoutes()
30
+ * })
31
+ *
32
+ * const AdminRoutes = ChildRouter({
33
+ * '/users': () => html.div('User List'),
34
+ * '/users/:id': (info) => html.div('User: ', info.$.params.$.id),
35
+ * '/settings': () => html.div('Admin Settings')
45
36
  * })
46
37
  * ```
47
38
  *
39
+ * @template T - The type of the routes configuration object
40
+ * @param routes - Object mapping route patterns to handler functions
41
+ * @returns A renderable router component that handles URL routing and provides context
42
+ * @throws {Error} When no matching route is found for the current URL
43
+ * @public
44
+ */
45
+ export declare const RootRouter: <T extends { [K in keyof T]: (info: K extends string ? Signal<RouteInfo<MakeParams<ExtractParams<K>>, K>> : never) => TNode; }>(routes: T) => Renderable;
46
+ /**
47
+ * Creates a nested router that matches against the remaining path from parent routers.
48
+ *
49
+ * ChildRouter is used for nested routing scenarios where a parent router (RootRouter or
50
+ * another ChildRouter) has matched a portion of the path and passed the remaining path
51
+ * to child components. ChildRouter reads the parent routing context and matches its
52
+ * routes against the remaining path.
53
+ *
48
54
  * @example
49
55
  * ```typescript
50
- * // Using route info for navigation and data
51
- * const ProductRouter = Router({
52
- * '/products': () => ProductList(),
53
- * '/products/:id': (info) => {
54
- * const productId = info.$.params.$.id
55
- * const searchParams = info.$.search
56
+ * // Parent RootRouter passes remaining path to AdminRoutes
57
+ * const App = RootRouter({
58
+ * '/admin/*': () => AdminRoutes(),
59
+ * '/blog/*': () => BlogRoutes()
60
+ * })
56
61
  *
57
- * return html.div(
58
- * html.h1('Product ', productId),
59
- * html.p('Search params: ', searchParams),
60
- * ProductDetail({
61
- * id: productId,
62
- * variant: new URLSearchParams(searchParams.value).get('variant')
63
- * })
64
- * )
65
- * },
66
- * '/products/:id/reviews': (info) => {
67
- * const productId = info.$.params.$.id
68
- * return ProductReviews({ productId })
69
- * }
62
+ * // ChildRouter matches against remaining path
63
+ * const AdminRoutes = ChildRouter({
64
+ * '/users': () => html.div('User List'),
65
+ * '/users/:id': (info) => html.div('User: ', info.$.params.$.id),
66
+ * '/settings': () => html.div('Admin Settings'),
67
+ * '*': () => html.div('Admin 404')
70
68
  * })
71
69
  * ```
72
70
  *
73
71
  * @example
74
72
  * ```typescript
75
- * // Programmatic navigation
76
- * import { Location } from '@tempots/ui'
73
+ * // Multiple levels of nesting
74
+ * const BlogRoutes = ChildRouter({
75
+ * '/posts/*': () => PostRoutes(),
76
+ * '/categories': () => html.div('Categories')
77
+ * })
77
78
  *
78
- * const Navigation = () => html.nav(
79
- * html.button(
80
- * on.click(() => Location.navigate('/')),
81
- * 'Home'
82
- * ),
83
- * html.button(
84
- * on.click(() => Location.navigate('/about')),
85
- * 'About'
86
- * ),
87
- * html.button(
88
- * on.click(() => Location.navigate('/products/123')),
89
- * 'Product 123'
90
- * )
91
- * )
79
+ * const PostRoutes = ChildRouter({
80
+ * '/': () => html.div('All Posts'),
81
+ * '/:id': (info) => html.div('Post: ', info.$.params.$.id),
82
+ * '/:id/comments': (info) => html.div('Comments for: ', info.$.params.$.id)
83
+ * })
92
84
  * ```
93
85
  *
94
86
  * @template T - The type of the routes configuration object
95
87
  * @param routes - Object mapping route patterns to handler functions
96
- * @returns A renderable router component that handles URL routing
97
- * @throws {Error} When no matching route is found for the current URL
88
+ * @returns A renderable router component that handles nested URL routing
89
+ * @throws {Error} When no matching route is found for the remaining path
98
90
  * @public
99
91
  */
100
- export declare const Router: <T extends { [K in keyof T]: (info: K extends string ? Signal<RouteInfo<MakeParams<ExtractParams<K>>, K>> : never) => TNode; }>(routes: T) => Renderable;
92
+ export declare const ChildRouter: <T extends { [K in keyof T]: (info: K extends string ? Signal<RouteInfo<MakeParams<ExtractParams<K>>, K>> : never) => TNode; }>(routes: T) => Renderable;
@@ -204,15 +204,6 @@ export declare function getAbsoluteRect(el: Element): Rect;
204
204
  * @public
205
205
  */
206
206
  export declare const ElementRect: (fn: (rect: Signal<Rect>) => TNode) => import('@tempots/dom').Renderable;
207
- /**
208
- * Creates a renderable function that monitors the size of an element and provides it as a signal.
209
- *
210
- * @param fn - The renderable function that receives the size signal and returns a TNode.
211
- * @returns A function that takes a DOMContext and returns a renderable function.
212
- * @deprecated use ElementRect instead
213
- * @public
214
- */
215
- export declare const ElementSize: (fn: (size: Signal<Rect>) => TNode) => import('@tempots/dom').Renderable;
216
207
  /**
217
208
  * Creates a renderable function that monitors the window size and invokes the provided function with the current size.
218
209
  * @param fn - The function to be invoked with the current window size.