@dotvoid/stacked-router 1.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 (62) hide show
  1. package/README.md +594 -0
  2. package/dist/components/DefaultLayout.d.ts +4 -0
  3. package/dist/components/DefaultLayout.d.ts.map +1 -0
  4. package/dist/components/ErrorBoundary.d.ts +22 -0
  5. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  6. package/dist/components/ErrorResolver.d.ts +9 -0
  7. package/dist/components/ErrorResolver.d.ts.map +1 -0
  8. package/dist/components/Link.d.ts +29 -0
  9. package/dist/components/Link.d.ts.map +1 -0
  10. package/dist/components/Slots.d.ts +14 -0
  11. package/dist/components/Slots.d.ts.map +1 -0
  12. package/dist/components/StackedView.d.ts +6 -0
  13. package/dist/components/StackedView.d.ts.map +1 -0
  14. package/dist/components/StackedViewGroup.d.ts +6 -0
  15. package/dist/components/StackedViewGroup.d.ts.map +1 -0
  16. package/dist/components/VoidViews.d.ts +6 -0
  17. package/dist/components/VoidViews.d.ts.map +1 -0
  18. package/dist/contexts/RouterContext.d.ts +27 -0
  19. package/dist/contexts/RouterContext.d.ts.map +1 -0
  20. package/dist/contexts/RouterProvider.d.ts +11 -0
  21. package/dist/contexts/RouterProvider.d.ts.map +1 -0
  22. package/dist/contexts/SlotContext.d.ts +6 -0
  23. package/dist/contexts/SlotContext.d.ts.map +1 -0
  24. package/dist/contexts/SlotProvider.d.ts +4 -0
  25. package/dist/contexts/SlotProvider.d.ts.map +1 -0
  26. package/dist/contexts/ViewContext.d.ts +17 -0
  27. package/dist/contexts/ViewContext.d.ts.map +1 -0
  28. package/dist/contexts/ViewProvider.d.ts +10 -0
  29. package/dist/contexts/ViewProvider.d.ts.map +1 -0
  30. package/dist/hooks/useHref.d.ts +14 -0
  31. package/dist/hooks/useHref.d.ts.map +1 -0
  32. package/dist/hooks/useNavigate.d.ts +19 -0
  33. package/dist/hooks/useNavigate.d.ts.map +1 -0
  34. package/dist/hooks/useOpenViews.d.ts +25 -0
  35. package/dist/hooks/useOpenViews.d.ts.map +1 -0
  36. package/dist/hooks/usePrevious.d.ts +2 -0
  37. package/dist/hooks/usePrevious.d.ts.map +1 -0
  38. package/dist/hooks/useRouter.d.ts +2 -0
  39. package/dist/hooks/useRouter.d.ts.map +1 -0
  40. package/dist/hooks/useView.d.ts +2 -0
  41. package/dist/hooks/useView.d.ts.map +1 -0
  42. package/dist/hooks/useViewStack.d.ts +18 -0
  43. package/dist/hooks/useViewStack.d.ts.map +1 -0
  44. package/dist/index.es.js +1112 -0
  45. package/dist/index.umd.js +22 -0
  46. package/dist/lib/RouterRegistry.d.ts +57 -0
  47. package/dist/lib/RouterRegistry.d.ts.map +1 -0
  48. package/dist/lib/allocation.d.ts +23 -0
  49. package/dist/lib/allocation.d.ts.map +1 -0
  50. package/dist/lib/events.d.ts +4 -0
  51. package/dist/lib/events.d.ts.map +1 -0
  52. package/dist/lib/history.d.ts +34 -0
  53. package/dist/lib/history.d.ts.map +1 -0
  54. package/dist/lib/href.d.ts +23 -0
  55. package/dist/lib/href.d.ts.map +1 -0
  56. package/dist/lib/mapRoutes.d.ts +6 -0
  57. package/dist/lib/mapRoutes.d.ts.map +1 -0
  58. package/dist/lib/viewsAreEqual.d.ts +8 -0
  59. package/dist/lib/viewsAreEqual.d.ts.map +1 -0
  60. package/dist/main.d.ts +13 -0
  61. package/dist/main.d.ts.map +1 -0
  62. package/package.json +63 -0
package/README.md ADDED
@@ -0,0 +1,594 @@
1
+ # stacked-router
2
+
3
+ A client side only, file based, router with path mapping to _"view component_ props. Treats opened views as a stack of cards. When a new view (route) is opened this view is added to the top of the stack. As long as enough screen estate is available for all open views they can be displayed side by side. If not the leftmost is hidden until on smaller screens only one view is visible.
4
+
5
+ The router maintains the browser history and navigation and include utilities to integrate with modern UI libraries navigation. The browser location always matches the focused view which allows links to individual views to be copied and shared.
6
+
7
+ ## Basic concepts
8
+
9
+ ### Routing
10
+ Routing is the process of mapping a URL to a view component (file) and its props. The router provides a `RouterProvider` component that takes a `config` prop which is an array of route definitions, preferrably mapped from the file structure. Each route definition is an object with a `path` and `component` property. The `path` property is a string that defines the URL path for the route. The `component` property is a React component that will be rendered when the route is matched.
11
+
12
+ Supports a `basePath` property that can be used to automatically prefix all paths in the router navigation.
13
+
14
+ Supports external routes that are loaded from remote urls. These routes are loaded asynchronously and can be used to load content from external sources. External routes can be defined using the `external` property in the route definition. The `external` property is a string that defines the URL for the external route.
15
+
16
+ ### Stacked views
17
+ Allow placing multiple views side by side on large screens but still degrade gracefully on smaller screens (mobile). Mobile friendly should also be large desktop screen friendly.
18
+
19
+ Smaller screens/viewports stacks views on top of each other, hiding views that don't receive as much space as they want..
20
+
21
+ ```text
22
+ ..........
23
+ . ..........
24
+ . . ..........
25
+ . . . __________
26
+ . . . | |
27
+ ... . | |
28
+ ... | |
29
+ ..| |
30
+ ----------
31
+ ```
32
+
33
+ Based on the minimum screen estate each view require, a larger screen/viewport could display more views if possible. Open views that do not receive enough screen estate will be hidden.
34
+
35
+ ```text
36
+ ..........
37
+ . ---------- ---------- ----------
38
+ . | | | | | |
39
+ . | | | | | |
40
+ . | | | | | |
41
+ ..| | | | | |
42
+ ---------- ---------- ----------
43
+ ```
44
+
45
+ ### Void views
46
+
47
+ Void views are rendered outside the stack. These views do not take up any space in the stack. This is useful for displaying a view in a modal, sheet or popup.
48
+
49
+ ### Layouts
50
+
51
+ Layouts are used to define the layout of the views in the stack. Layouts can be nested to create more complex layouts. This means that a layout further down the tree is rendered inside a layout further up in the tree.
52
+
53
+ Default layouts are named `_layout.tsx`.
54
+
55
+ It is also possible to define named, or keyed, layouts. When navigating to a view, the layouts with the matching name will be used. If no layout with the matching name is found, any default layouts will be used.
56
+
57
+ Named layouts are named `_layout.name.tsx`.
58
+
59
+ ### Slots
60
+
61
+ Layouts support defining named slots. This allows view components to render content which is automatically rendered inside the layout instead. This allow for styling of for example headers and footers in the layout while still allowing the views to have the logic and decide what should be rendered these slots.
62
+
63
+ ### Error Boundaries
64
+
65
+ Stacked router includes automatic error boundaries around each view that catch rendering errors and display contextual error components.
66
+
67
+ ## Usage
68
+
69
+ ### Basic setup
70
+
71
+ **main.tsx**
72
+
73
+ ```tsx
74
+ import { mapRoutes } from 'stacked-router'
75
+ import { RouterProvider } from 'stacked-router'
76
+
77
+ const modules = import.meta.glob('./views/**/*.tsx', { eager: true })
78
+ const config = mapRoutes(modules, './views')
79
+
80
+ createRoot(document.getElementById('root')!).render(
81
+ <StrictMode>
82
+ <RouterProvider config={ config }>
83
+ <App />
84
+ </RouterProvider>
85
+ </StrictMode>,
86
+ )
87
+
88
+ ```
89
+
90
+ **App.tsx**
91
+
92
+ ```tsx
93
+ import { StackedViewGroup } from 'stacked-router'
94
+
95
+ export function App() {
96
+ return (
97
+ <div ref={grid} className='w-screen h-screen relative'>
98
+ {/* Stacked views rendered here */}
99
+ <StackedViewGroup className={`flex content-stretch h-screen overflow-hidden`} />
100
+
101
+ {/* Standalone views rendered here */}
102
+ <VoidViews />
103
+ </div>
104
+ )
105
+ }
106
+ ```
107
+
108
+ **_layout.tsx**
109
+
110
+ Layouts are optional and are automatically wrapped around all views at the same level or below it in the file tree. This layout handles active state and width css using tailwind.
111
+
112
+ ```tsx
113
+ import { type PropsWithChildren } from 'react'
114
+ import { StackedView } from 'stacked-router'
115
+ import { useView } from 'stacked-router'
116
+ import { cva } from 'class-variance-authority'
117
+ import { cn } from '@/lib/cn'
118
+ import View from '@/components/View'
119
+
120
+ export default function Layout({ children }: PropsWithChildren) {
121
+ const { width, isActive } = useView()
122
+ const stackedView = cva('h-full grow transition-all group/view', {
123
+ variants: {
124
+ isActive: {
125
+ true: 'is-active',
126
+ false: 'border-s-1 border-s-foreground-300 [.is-active+&]:border-s-background'
127
+ }
128
+ }
129
+ })
130
+
131
+ return (
132
+ <StackedView className={cn(stackedView({ isActive }))} style={{ flexBasis: `${width}vw` }}>
133
+ <View.Root>
134
+ {children}
135
+ </View.Root>
136
+ </StackedView>
137
+ )
138
+ }
139
+ ```
140
+
141
+ **users/[id].tsx**
142
+
143
+ File names with the structure `[param].tsx` automatically receives `param` in the url as props. As so the url `/users/10104` can be mapped to the below view component.
144
+
145
+ ```tsx
146
+ function PlanningItem({ id }: { id: string }) {
147
+ const user = useUser(id)
148
+
149
+ return (
150
+ <div>
151
+ {user?.name ?? ''}
152
+ </div>
153
+ )
154
+ }
155
+ ```
156
+
157
+ ### Mapping file structure
158
+
159
+ Use RouterProvider to store all client side routes. Either through a config or by mapping a directory structure.
160
+
161
+ ```tsx
162
+ import { mapRoutes } from 'stacked-router'
163
+ import { RouterProvider } from 'stacked-router'
164
+
165
+ const modules = import.meta.glob('./views/**/*.tsx', { eager: true })
166
+ const config = mapRoutes(modules, './views')
167
+
168
+ createRoot(document.getElementById('root')!).render(
169
+ <StrictMode>
170
+ <RouterProvider config={ config }>
171
+ <App />
172
+ </RouterProvider>
173
+ </StrictMode>,
174
+ )
175
+ ```
176
+
177
+ **Example view file structure**
178
+
179
+ A simple file structure with one default view (`views/index.tsx`) and one global layout (`_layout.tsx`) file used for all views. The `plannings/` have one default view that lists plannings and one specific view that opens one planning.
180
+
181
+ All directories prefixed with underscore (`_`) are ignored. So view specific components are placed in `_component/` directories.
182
+
183
+ ```
184
+ views/
185
+ plannings/
186
+ _components/
187
+ Assignment.tsx
188
+ AssigmentAction.tsx
189
+ [id].tsx
190
+ index.tsx
191
+ _layout.tsx
192
+ _layout.dialog.tsx
193
+ index.tsx
194
+ ```
195
+
196
+ **Example view - `views/plannings/[id].tsx`**
197
+
198
+ ```tsx
199
+ const meta = {
200
+ breakpoints: [
201
+ {
202
+ breakpoint: 720,
203
+ minVw: 50
204
+ },
205
+ {
206
+ breakpoint: 1024,
207
+ minVw: 30
208
+ },
209
+ {
210
+ breakpoint: 1280,
211
+ minVw: 20
212
+ }
213
+ ]
214
+ }
215
+
216
+ function PlanningItem({ id }: { id: string }) {
217
+ return (
218
+ <div>
219
+ Planning item
220
+ </div>
221
+ )
222
+ }
223
+
224
+ PlanningItem.meta = meta
225
+ export default PlanningItem
226
+ ```
227
+
228
+ The `mapRoutes()` creates a route configuration including minimum view width requirements for each breakpoint based on the meta data in each view file.
229
+
230
+ _The configuration includes the actual components which is not visible below, which is why the layout seems empty._
231
+
232
+ ```json
233
+ {
234
+ "routes": [
235
+ {
236
+ "path": "/",
237
+ "meta": {
238
+ "breakpoints": [
239
+ {
240
+ "breakpoint": 1024,
241
+ "minVw": 50
242
+ },
243
+ {
244
+ "breakpoint": 1280,
245
+ "minVw": 33
246
+ }
247
+ ]
248
+ }
249
+ },
250
+ {
251
+ "path": "/plannings/[id]",
252
+ "meta": {
253
+ "breakpoints": [
254
+ {
255
+ "breakpoint": 720,
256
+ "minVw": 50
257
+ },
258
+ {
259
+ "breakpoint": 1024,
260
+ "minVw": 30
261
+ },
262
+ {
263
+ "breakpoint": 1280,
264
+ "minVw": 20
265
+ }
266
+ ]
267
+ }
268
+ },
269
+ {
270
+ "path": "/plannings",
271
+ "meta": {
272
+ "breakpoints": [
273
+ {
274
+ "breakpoint": 1024,
275
+ "minVw": 50
276
+ },
277
+ {
278
+ "breakpoint": 1280,
279
+ "minVw": 33
280
+ }
281
+ ]
282
+ }
283
+ }
284
+ ],
285
+ "layouts": {}
286
+ }
287
+ ```
288
+
289
+ ### Integrating with UI libraries
290
+
291
+ Stacked router, as most router libraries, expose hooks to allow better integration with (some) UI libraries that can be configured to use the router mechanism inside its UI components like tabs, listboxes, buttons etc. The hook `useNavigate()` handles client-side navigation and `useHref()` can translate router hrefs to native HTML hrefs. Example below is based on HeroUI.
292
+
293
+ ```jsx
294
+ import { StackedViewGroup } from 'stacked-router'
295
+ import { useHref, useNavigate } from 'stacked-router/hooks'
296
+ import { HeroUIProvider } from '@heroui/react'
297
+
298
+ export function App() {
299
+ const navigate = useNavigate()
300
+
301
+ return (
302
+ <HeroUIProvider navigate={navigate} useHref={useHref}>
303
+ <div ref={grid} className='w-screen h-screen relative'>
304
+ <StackedViewGroup className={`flex content-stretch h-screen overflow-hidden`} />
305
+ </div>
306
+ </HeroUIProvider>
307
+ )
308
+ }
309
+ ```
310
+
311
+ Then it is a simple matter of using the UI libraries components for navigation.
312
+
313
+ **Link component example**
314
+
315
+ ```jsx
316
+ import { Link } from '@heroui/react'
317
+
318
+ <Link href='/plannings/234'>Planning item nr 234</Link>
319
+ ```
320
+
321
+ **Dropdown menu example**
322
+
323
+ ```jsx
324
+ import { Button, Dropdown, DropdownItem, DropdownMenu, DropdownSection, DropdownTrigger } from "@heroui/react";
325
+ import { Ellipsis } from 'lucide-react'
326
+
327
+ <Dropdown>
328
+ <DropdownTrigger>
329
+ <Button isIconOnly size="sm" variant="light">
330
+ <Ellipsis size={18} />
331
+ </Button>
332
+ </DropdownTrigger>
333
+ <DropdownMenu>
334
+ <DropdownSection showDivider>
335
+ <DropdownItem key='open' href={`/plannings/234`}>
336
+ Planning item nr 234
337
+ </DropdownItem>
338
+ </DropdownSection>
339
+ </DropdownMenu>
340
+ </Dropdown>
341
+ }
342
+ ```
343
+
344
+ **shadcn example**
345
+
346
+ Integration with shadcn is different as it does not provide the same convenience context. Most shadcn components that need navigation (like Button, NavigationMenu) accept an `asChild` prop which makes it easy to wrap the stacked router `Link` component.
347
+
348
+ ```jsx
349
+ import { Button } from '@/components/ui/button'
350
+ import { Link } from 'stacked-router'
351
+
352
+ <Button asChild>
353
+ <Link to="/planning/234">Planning item nr 234</Link>
354
+ </Button>
355
+ ```
356
+
357
+ ### Custom navigation
358
+
359
+ For more custom ways of navigating to another view, the hook `useNavigate()`, can be used. It allows sending _invisible_ props (params not visible in URL), specifying a specific layout or that the view should be rendered as a void view (outside of the stack).
360
+
361
+ The same can be achieved by using the `<Link />` component included in the `stacked-router` package.
362
+
363
+ ```jsx
364
+ import { useNavigate } from 'stacked-router'
365
+
366
+ const navigate = useNavigate()
367
+
368
+ <button onPress={() => {
369
+ navigate('/planning/234', {
370
+ options: {
371
+ fromEvent: '3433'
372
+ }
373
+ })
374
+ }}>
375
+ Navigate to planning item nr 234
376
+ </button>
377
+
378
+ <button onPress={() => {
379
+ navigate('/planning/' + crypto.randomUUID(), {
380
+ options: {
381
+ fromEvent: '3433',
382
+ layout: 'dialog',
383
+ target: '_void'
384
+ }
385
+ })
386
+ }}>
387
+ Create new planning item
388
+ </button>
389
+ ```
390
+
391
+ ### useView()
392
+
393
+ Used to get query parameter, props, layout or update query parameters or props or if a named layout is used.
394
+
395
+ ```jsx
396
+ import { useView } from 'stacked-router'
397
+
398
+ const { props, setProps, queryParams, setQueryParams, layout } = useView()
399
+
400
+ <p>
401
+ {layout
402
+ ? layout
403
+ : 'No layout or default layout'
404
+ }
405
+ </p>
406
+
407
+ <button onPress={() => {
408
+ // Add one prop
409
+ setProps({ created: true})
410
+ }}>
411
+ Is created
412
+ </button>
413
+
414
+ <button onPress={() => {
415
+ // Set all (clear all) query parameters
416
+ setQueryParams({}, true)
417
+ }}>
418
+ Is created
419
+ </button>
420
+ ```
421
+
422
+ ### useOpenViews()
423
+
424
+ Can be used to get information on a subset of open views that match a given criteria. It is only possible to find views that have set the type in the view meta information. Useful to be able to mark rows that match an open view in a table or listing.
425
+
426
+ Example view:
427
+
428
+ ```jsx
429
+ const meta: ViewMetadata = {
430
+ type: 'customer'
431
+ }
432
+
433
+ function Customer({ id }: { id: string }) {
434
+ return <div>Example component</div>
435
+ }
436
+
437
+ Customer.meta = meta
438
+ export default Customer
439
+ ```
440
+
441
+ Usage in other views:
442
+
443
+ ```jsx
444
+ import { useOpenViews } from 'stacked-router'
445
+
446
+ export function CustomerList() {
447
+ // Get all customers
448
+ const customers = useCustomers()
449
+
450
+ // Get all open customer views
451
+ const customerViews = useOpenViews('customer')
452
+
453
+ return (
454
+ <div>
455
+ {customers.map(c => (
456
+ <div
457
+ key={c.id}
458
+ className={customerViews.includes(c.id) ? 'active' : ''}
459
+ >
460
+ {c.id}: {c.name}
461
+ </div>
462
+ ))}
463
+ </div>
464
+ )
465
+ }
466
+ ```
467
+
468
+ It is also possible to match against params (url path params).
469
+ ```jsx
470
+ const specificView = useOpenViews('article', {
471
+ categoryId: 'news',
472
+ articleId: '456'
473
+ })
474
+ ```
475
+
476
+ ### Using layout slots
477
+
478
+ A slot is defined in the layout using the component `<Outlet/>` and filled with content in the view using the component `<Fill/>`. The prop `name` is used to identify the slot.
479
+
480
+ The example below is a basic HeroUI Modal displayed in a void view (not in the normal stack). Note how the enabled state of the button can be maintained in the view but still rendered in the footer slot styled by the layout.
481
+
482
+ The layout could be used by many view components but keep all styling of the header and footer in the layout. The order of the slots in the view component is not important.
483
+
484
+ _Also shows how to close a void view, in this case when when the modal closes._
485
+
486
+ **View component**
487
+
488
+ ```jsx
489
+ import { Fill } from 'stacked-router'
490
+
491
+ export default function User() {
492
+ const [disabled, setDisabled] = useState(false)
493
+ const userName = 'John Doe'
494
+
495
+ return (
496
+ <>
497
+ <Fill slot='header'>
498
+ {userName}
499
+ </Fill>
500
+
501
+ <p>User content here</p>
502
+
503
+ <Fill slot='footer'>
504
+ <button disabled={disabled}>Save</button>
505
+ </Fill>
506
+ </>
507
+ )
508
+ }
509
+ ```
510
+
511
+ **Dialog layout**
512
+
513
+ ```jsx
514
+ import {
515
+ Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure,
516
+ } from '@heroui/react'
517
+ import { useEffect } from 'react'
518
+ import { useView, Outlet } from 'stacked-router'
519
+
520
+ export default function DialogLayout({ children }: {
521
+ children: React.ReactNode
522
+ }) {
523
+ const {isOpen, onOpen, onClose} = useDisclosure()
524
+ const { close } = useView()
525
+
526
+ useEffect(() => {
527
+ onOpen()
528
+ }, [onOpen])
529
+
530
+
531
+ return (
532
+ <>
533
+ <Modal
534
+ isOpen={isOpen} size='2xl' className='max-h-4/5' onClose={onClose}
535
+ onOpenChange={(isOpen) => {
536
+ if (!isOpen) {
537
+ close()
538
+ }
539
+ }}
540
+ hideCloseButton={true}
541
+ >
542
+ <ModalContent>
543
+ <ModalHeader className='flex flex-row gap-4 border-b border-gray-200'>
544
+ <Outlet slot='header' />{/* Header content from the view */}
545
+ </ModalHeader>
546
+
547
+ <ModalBody className='overflow-y-scroll p-0'>
548
+ {/* All and any User view content is displayed here */}
549
+ {children}
550
+ </ModalBody>
551
+
552
+ <ModalFooter className='border-t border-gray-200 flex justify-end gap-4'>
553
+ <Outlet slot='footer' />{/* Footer content from the view */}
554
+ </ModalFooter>
555
+ </ModalContent>
556
+ </Modal>
557
+ </>
558
+ )
559
+ }
560
+ ```
561
+
562
+ ### Error components
563
+
564
+ Create `_error.tsx` files to handle errors at different levels of your application. The router finds the closest error component up the directory tree.
565
+
566
+ **_error.tsx**
567
+
568
+ ```tsx
569
+ import type { ErrorComponentProps } from 'stacked-router'
570
+
571
+ export default function MyError({ error, reset }: ErrorComponentProps) {
572
+ return (
573
+ <div>
574
+ <h2>Something went wrong</h2>
575
+ <p>{error.message}</p>
576
+ <button onClick={reset}>Try again</button>
577
+ </div>
578
+ )
579
+ }
580
+ ```
581
+
582
+ **File structure example**
583
+
584
+ ```
585
+ views/
586
+ _error.tsx # Root fallback for all views
587
+ users/
588
+ _error.tsx # Specific to user section
589
+ index.tsx # Uses users/_error.tsx
590
+ plannings/
591
+ index.tsx # Uses root _error.tsx
592
+ ```
593
+
594
+ The `reset` function clears the error and re-renders the component. Error boundaries only catch rendering errors, not errors in event handlers or async code.
@@ -0,0 +1,4 @@
1
+ export declare function DefaultLayout({ children }: {
2
+ children: React.ReactNode;
3
+ }): import("react/jsx-runtime").JSX.Element;
4
+ //# sourceMappingURL=DefaultLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultLayout.d.ts","sourceRoot":"","sources":["../../lib/components/DefaultLayout.tsx"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE;IAC1C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,2CAMA"}
@@ -0,0 +1,22 @@
1
+ import { Component, ErrorInfo, ReactNode } from 'react';
2
+ interface Props {
3
+ children?: ReactNode;
4
+ viewUrl: string;
5
+ error?: Error;
6
+ errorCode?: number;
7
+ }
8
+ interface State {
9
+ hasError: boolean;
10
+ errorCode?: number;
11
+ error?: Error;
12
+ errorInfo?: ErrorInfo;
13
+ }
14
+ export declare class ErrorBoundary extends Component<Props, State> {
15
+ constructor(props: Props);
16
+ static getDerivedStateFromError(error: Error): State;
17
+ componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
18
+ reset: () => void;
19
+ render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
20
+ }
21
+ export {};
22
+ //# sourceMappingURL=ErrorBoundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../lib/components/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGvD,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,UAAU,KAAK;IACb,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB;AAED,qBAAa,aAAc,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;gBAC5C,KAAK,EAAE,KAAK;IASxB,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK;IAIpD,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;IAMpD,KAAK,aAEJ;IAED,MAAM;CAaP"}
@@ -0,0 +1,9 @@
1
+ import { ErrorInfo } from 'react';
2
+ export declare function ErrorResolver({ viewUrl, error, errorCode, errorInfo, reset }: {
3
+ viewUrl: string;
4
+ error: Error;
5
+ errorCode?: number;
6
+ errorInfo?: ErrorInfo;
7
+ reset: () => void;
8
+ }): import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=ErrorResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorResolver.d.ts","sourceRoot":"","sources":["../../lib/components/ErrorResolver.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAIjC,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,KAAK,EACL,SAAS,EACT,SAAS,EACT,KAAK,EACN,EAAE;IACD,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB,2CAiFA"}
@@ -0,0 +1,29 @@
1
+ import { PropsWithChildren } from 'react';
2
+ interface LinkProps {
3
+ href?: string;
4
+ query?: Record<string, string | number | boolean>;
5
+ props?: Record<string, string | number | boolean>;
6
+ layout?: string;
7
+ className?: string;
8
+ target?: '_self' | '_top' | '_blank' | '_void';
9
+ onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;
10
+ }
11
+ /**
12
+ * Link component allows giving parameters in two ways, as part of the query string
13
+ * in the href or as a query key/value object. They will always be combined to a url.
14
+ *
15
+ * Automatically adds rel="noopener noreferrer" to all external links.
16
+ * Props can be used to send arbitrary data to a view.
17
+ *
18
+ * ATTENTION:
19
+ *
20
+ * If using HeroUI, prefer using HeroUI Link component. Utilise the hooks useHref()
21
+ * and useNavigate() to provide HeroUIProvider the necessary components.
22
+ *
23
+ * CAVEAT: Props is not persisted in any way and thus only used in first load of a view.
24
+ * When using target _blank or CMD/CTRL to open a view in a new window props will
25
+ * not be passed to the view.
26
+ */
27
+ export declare function Link({ href, query, children, className, target, onClick, props, layout }: PropsWithChildren & LinkProps): import("react/jsx-runtime").JSX.Element;
28
+ export {};
29
+ //# sourceMappingURL=Link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../lib/components/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAKzC,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;IACjD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;IAC9C,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;CAC3D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,IAAI,CAAC,EACnB,IAAI,EACJ,KAAU,EACV,QAAQ,EACR,SAAS,EACT,MAAgB,EAChB,OAAO,EACP,KAAK,EACL,MAAM,EACP,EAAE,iBAAiB,GAAG,SAAS,2CAuC/B"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Use in layout to render slot content
3
+ */
4
+ export declare function Outlet({ slot }: {
5
+ slot: string;
6
+ }): import("react/jsx-runtime").JSX.Element;
7
+ /**
8
+ * Use in view component to define content for a slot
9
+ */
10
+ export declare function Fill({ slot, children }: {
11
+ slot: string;
12
+ children: React.ReactNode;
13
+ }): null;
14
+ //# sourceMappingURL=Slots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Slots.d.ts","sourceRoot":"","sources":["../../lib/components/Slots.tsx"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,2CAKhD;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,QAUA"}