@astrale-os/shell-react 0.2.10-beta.2 → 0.3.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 (131) hide show
  1. package/dist/application/apps/app-host.d.ts +5 -5
  2. package/dist/application/apps/app-host.d.ts.map +1 -1
  3. package/dist/application/apps/app-host.js +18 -39
  4. package/dist/application/apps/apps.hook.d.ts +4 -11
  5. package/dist/application/apps/apps.hook.d.ts.map +1 -1
  6. package/dist/application/apps/apps.hook.js +9 -49
  7. package/dist/application/apps/open-app.hook.d.ts +4 -7
  8. package/dist/application/apps/open-app.hook.d.ts.map +1 -1
  9. package/dist/application/apps/open-app.hook.js +2 -2
  10. package/dist/application/index.d.ts +1 -3
  11. package/dist/application/index.d.ts.map +1 -1
  12. package/dist/application/index.js +1 -2
  13. package/dist/application/spaces/space.hook.d.ts.map +1 -1
  14. package/dist/application/spaces/space.hook.js +4 -1
  15. package/dist/auth/act-as.context.d.ts +1 -1
  16. package/dist/auth/act-as.context.d.ts.map +1 -1
  17. package/dist/auth/auth.hook.d.ts +1 -1
  18. package/dist/auth/auth.hook.d.ts.map +1 -1
  19. package/dist/auth/can.hook.d.ts +2 -2
  20. package/dist/auth/can.hook.d.ts.map +1 -1
  21. package/dist/auth/self.hook.d.ts +1 -1
  22. package/dist/auth/self.hook.d.ts.map +1 -1
  23. package/dist/components/astrale.d.ts +14 -0
  24. package/dist/components/astrale.d.ts.map +1 -0
  25. package/dist/components/astrale.js +12 -0
  26. package/dist/components/can.d.ts +2 -2
  27. package/dist/components/can.d.ts.map +1 -1
  28. package/dist/components/index.d.ts +2 -3
  29. package/dist/components/index.d.ts.map +1 -1
  30. package/dist/components/index.js +1 -2
  31. package/dist/graph/call/call.hook.d.ts +2 -2
  32. package/dist/graph/call/call.hook.d.ts.map +1 -1
  33. package/dist/graph/call/stream.hook.d.ts +2 -2
  34. package/dist/graph/call/stream.hook.d.ts.map +1 -1
  35. package/dist/graph/graph.context.d.ts +1 -1
  36. package/dist/graph/graph.context.d.ts.map +1 -1
  37. package/dist/graph/guards.error.d.ts +4 -4
  38. package/dist/graph/guards.error.d.ts.map +1 -1
  39. package/dist/graph/guards.error.js +4 -4
  40. package/dist/graph/query-definition.hook.d.ts +1 -2
  41. package/dist/graph/query-definition.hook.d.ts.map +1 -1
  42. package/dist/graph/query-definition.hook.js +4 -10
  43. package/dist/graph/resource.d.ts +1 -1
  44. package/dist/graph/resource.d.ts.map +1 -1
  45. package/dist/graph/store.d.ts +2 -2
  46. package/dist/graph/store.d.ts.map +1 -1
  47. package/dist/graph/store.js +1 -1
  48. package/dist/index.d.ts +7 -7
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +2 -2
  51. package/dist/navigation/adapters/url.adapter.d.ts.map +1 -1
  52. package/dist/navigation/adapters/url.adapter.js +2 -5
  53. package/dist/navigation/codec.d.ts.map +1 -1
  54. package/dist/navigation/codec.js +1 -7
  55. package/dist/navigation/link.js +1 -1
  56. package/dist/navigation/scope.context.d.ts +1 -1
  57. package/dist/navigation/scope.context.d.ts.map +1 -1
  58. package/dist/navigation/scope.context.js +3 -6
  59. package/dist/navigation/snapshot.d.ts +1 -1
  60. package/dist/navigation/snapshot.d.ts.map +1 -1
  61. package/dist/navigation/snapshot.js +2 -8
  62. package/dist/navigation/view-key.d.ts +3 -0
  63. package/dist/navigation/view-key.d.ts.map +1 -0
  64. package/dist/navigation/view-key.js +8 -0
  65. package/dist/schema/action.hook.d.ts +11 -7
  66. package/dist/schema/action.hook.d.ts.map +1 -1
  67. package/dist/schema/action.hook.js +11 -6
  68. package/dist/schema/domain.hook.js +12 -13
  69. package/dist/schema/kernel.hook.d.ts +1 -1
  70. package/dist/schema/kernel.hook.d.ts.map +1 -1
  71. package/dist/schema/kernel.hook.js +1 -1
  72. package/dist/schema/mutation.hook.d.ts +2 -2
  73. package/dist/schema/mutation.hook.d.ts.map +1 -1
  74. package/dist/schema/mutation.hook.js +6 -5
  75. package/dist/schema/object.hook.d.ts +3 -6
  76. package/dist/schema/object.hook.d.ts.map +1 -1
  77. package/dist/schema/object.hook.js +4 -5
  78. package/dist/schema/relation.hook.d.ts +29 -19
  79. package/dist/schema/relation.hook.d.ts.map +1 -1
  80. package/dist/schema/relation.hook.js +45 -63
  81. package/dist/selection/live.d.ts.map +1 -1
  82. package/dist/selection/live.js +1 -2
  83. package/dist/session/session.context.d.ts +3 -4
  84. package/dist/session/session.context.d.ts.map +1 -1
  85. package/package.json +6 -5
  86. package/src/application/apps/app-host.tsx +22 -52
  87. package/src/application/apps/apps.hook.ts +14 -64
  88. package/src/application/apps/open-app.hook.ts +5 -10
  89. package/src/application/index.ts +2 -12
  90. package/src/application/spaces/space.hook.ts +6 -1
  91. package/src/auth/act-as.context.tsx +1 -1
  92. package/src/auth/auth.hook.ts +1 -1
  93. package/src/auth/can.hook.ts +3 -3
  94. package/src/auth/self.hook.ts +1 -1
  95. package/src/components/astrale.tsx +40 -0
  96. package/src/components/can.tsx +2 -2
  97. package/src/components/index.ts +2 -3
  98. package/src/graph/call/call.hook.ts +2 -2
  99. package/src/graph/call/stream.hook.ts +2 -2
  100. package/src/graph/graph.context.ts +1 -1
  101. package/src/graph/guards.error.ts +4 -4
  102. package/src/graph/query-definition.hook.ts +13 -23
  103. package/src/graph/resource.ts +1 -1
  104. package/src/graph/store.ts +3 -3
  105. package/src/index.ts +5 -14
  106. package/src/navigation/adapters/url.adapter.ts +3 -4
  107. package/src/navigation/codec.ts +1 -7
  108. package/src/navigation/link.tsx +1 -1
  109. package/src/navigation/scope.context.tsx +5 -6
  110. package/src/navigation/snapshot.ts +4 -9
  111. package/src/navigation/view-key.ts +11 -0
  112. package/src/schema/action.hook.ts +45 -28
  113. package/src/schema/domain.hook.ts +9 -10
  114. package/src/schema/kernel.hook.ts +1 -1
  115. package/src/schema/mutation.hook.ts +13 -9
  116. package/src/schema/object.hook.ts +10 -18
  117. package/src/schema/relation.hook.ts +127 -145
  118. package/src/selection/live.ts +1 -2
  119. package/src/session/session.context.ts +3 -4
  120. package/dist/application/apps/domains.hook.d.ts +0 -7
  121. package/dist/application/apps/domains.hook.d.ts.map +0 -1
  122. package/dist/application/apps/domains.hook.js +0 -18
  123. package/dist/components/mount-domain-frontend.d.ts +0 -22
  124. package/dist/components/mount-domain-frontend.d.ts.map +0 -1
  125. package/dist/components/mount-domain-frontend.js +0 -85
  126. package/dist/components/view-app.d.ts +0 -16
  127. package/dist/components/view-app.d.ts.map +0 -1
  128. package/dist/components/view-app.js +0 -16
  129. package/src/application/apps/domains.hook.ts +0 -37
  130. package/src/components/mount-domain-frontend.tsx +0 -158
  131. package/src/components/view-app.tsx +0 -49
@@ -1,85 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { createElement, lazy, Suspense } from 'react';
3
- import { createRoot } from 'react-dom/client';
4
- import { useHistoryVersion, useOptionalNavCtx } from '../navigation/scope.context.js';
5
- import { useDomain } from '../schema/domain.hook.js';
6
- import { useTargetPath } from '../window/hooks/target-node.hook.js';
7
- import { defaultViewError, defaultViewLoading, ViewErrorBoundary } from './boundaries.js';
8
- import { ViewApp } from './view-app.js';
9
- /** Browser bootstrap used by SDK-generated route entries and custom full React apps alike. */
10
- export function mountDomainFrontend(options) {
11
- const rootElement = typeof options.root === 'string' ? document.querySelector(options.root) : options.root;
12
- if (rootElement === null)
13
- throw new Error(`React frontend root '${options.root}' was not found.`);
14
- const route = options.module.routes[options.view];
15
- if (route === undefined)
16
- throw new Error(`React View '${options.view}' is not implemented.`);
17
- const loading = options.fallback ?? defaultViewLoading();
18
- const errorFallback = options.errorFallback ?? defaultViewError;
19
- const routeRuntime = createRouteRuntime();
20
- const root = createRoot(rootElement);
21
- root.render(_jsx(ViewApp, { config: options.config ?? { mode: 'sandboxed' }, fallback: loading, errorFallback: errorFallback, onError: ({ error }) => options.onError?.(error), children: _jsx(ViewErrorBoundary, { fallback: errorFallback, onError: options.onError, children: (generation) => (_jsx(Suspense, { fallback: loading, children: _jsx(DomainRoute, { module: options.module, name: options.view, generation: generation, runtime: routeRuntime }) })) }) }));
22
- return Object.freeze({ unmount: () => root.unmount() });
23
- }
24
- function DomainRoute(props) {
25
- const domain = useDomain(props.module.schema);
26
- const navigation = useOptionalNavCtx();
27
- useHistoryVersion(navigation?.history ?? null);
28
- const view = domain[props.name];
29
- // Domain's schema-indexed conditional retains the exact authored View type,
30
- // while the runtime member has Core's common rich Definition shape.
31
- const runtimeView = view;
32
- const targetPath = useTargetPath();
33
- const implementation = props.module.routes[props.name];
34
- const Component = props.runtime.component(props.generation, implementation);
35
- const declaration = runtimeView.definition;
36
- const target = declaration.target.kind === 'domain'
37
- ? Object.freeze({ kind: 'domain', origin: runtimeView.origin })
38
- : targetPath === null
39
- ? missingTarget(runtimeView.name)
40
- : targetPath;
41
- const current = new URL(window.location.href);
42
- const routeParams = navigation?.history.current?.params ?? directRouteParams(current);
43
- const route = Object.freeze({
44
- name: props.name,
45
- href: current.href,
46
- params: Object.freeze({ ...routeParams }),
47
- });
48
- return createElement(Component, { view, target, route });
49
- }
50
- function directRouteParams(url) {
51
- const params = {};
52
- const prefix = 'astrale.param.';
53
- for (const key of new Set(url.searchParams.keys())) {
54
- if (!key.startsWith(prefix))
55
- continue;
56
- const name = key.slice(prefix.length);
57
- if (name.length === 0 || /token|credential|authorization|secret/i.test(name)) {
58
- throw new TypeError(`React View route param '${name}' is invalid.`);
59
- }
60
- const values = url.searchParams.getAll(key);
61
- if (values.length !== 1)
62
- throw new TypeError(`React View route param '${name}' is duplicated.`);
63
- params[name] = values[0];
64
- }
65
- return Object.freeze(params);
66
- }
67
- function createRouteRuntime() {
68
- const generations = new Map();
69
- return {
70
- component(generation, implementation) {
71
- let Component = generations.get(generation);
72
- if (Component === undefined) {
73
- Component = lazy(async () => {
74
- const loaded = await implementation.component();
75
- return { default: loaded.default };
76
- });
77
- generations.set(generation, Component);
78
- }
79
- return Component;
80
- },
81
- };
82
- }
83
- function missingTarget(name) {
84
- throw new Error(`React View '${name}' requires a resource target from the Shell handshake.`);
85
- }
@@ -1,16 +0,0 @@
1
- import type { Shell, ShellConfig } from '@astrale-os/shell';
2
- import type { ReactElement, ReactNode } from 'react';
3
- import type { NavAdapter } from '../navigation/adapters/adapter.js';
4
- import type { NavTarget } from '../navigation/snapshot.js';
5
- import type { ShellProviderProps } from '../session/provider.js';
6
- /** One generated/default root; custom React apps may compose the lower-level providers directly. */
7
- export declare function ViewApp(props: {
8
- readonly config: ShellConfig | Shell;
9
- readonly navigation?: NavAdapter;
10
- readonly initial?: NavTarget;
11
- readonly fallback?: ReactNode;
12
- readonly errorFallback?: ShellProviderProps['errorFallback'];
13
- readonly onError?: ShellProviderProps['onError'];
14
- readonly children: ReactNode;
15
- }): ReactElement;
16
- //# sourceMappingURL=view-app.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"view-app.d.ts","sourceRoot":"","sources":["../../src/components/view-app.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAShE,oGAAoG;AACpG,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAC7B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAA;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAA;IAC5D,QAAQ,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAA;IAChD,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,GAAG,YAAY,CAWf"}
@@ -1,16 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { memoryAdapter } from '../navigation/adapters/memory.adapter.js';
3
- import { urlAdapter } from '../navigation/adapters/url.adapter.js';
4
- import { NavScope } from '../navigation/scope.context.js';
5
- import { ShellProvider } from '../session/provider.js';
6
- import { useShell } from '../session/shell.hook.js';
7
- import { ViewStage } from '../window/stage.js';
8
- /** One generated/default root; custom React apps may compose the lower-level providers directly. */
9
- export function ViewApp(props) {
10
- return (_jsx(ShellProvider, { config: props.config, fallback: props.fallback, errorFallback: props.errorFallback, onError: props.onError, children: _jsx(ViewAppRuntime, { ...props }) }));
11
- }
12
- function ViewAppRuntime(props) {
13
- const shell = useShell();
14
- const defaultAdapter = shell.hostCapabilities.navigation.history === 'browser' ? urlAdapter() : memoryAdapter();
15
- return (_jsxs(NavScope, { adapter: props.navigation ?? defaultAdapter, initial: props.initial, children: [props.children, _jsx(ViewStage, {})] }));
16
- }
@@ -1,37 +0,0 @@
1
- import type { DomainSearchResult } from '@astrale-os/shell'
2
-
3
- import { useMemo } from 'react'
4
-
5
- import type { ReadState } from '../../graph/memory/read/envelope.js'
6
-
7
- import { useAsyncResource } from '../../graph/async.js'
8
- import { useShell } from '../../session/shell.hook.js'
9
- import { isOsPlaneAvailable } from '../user/user.store.js'
10
-
11
- const NO_DOMAINS: readonly DomainSearchResult[] = []
12
-
13
- export interface DomainsResult extends ReadState {
14
- readonly domains: readonly DomainSearchResult[]
15
- }
16
-
17
- export function useInstalledDomains(): DomainsResult {
18
- const shell = useShell()
19
- const available = isOsPlaneAvailable(shell)
20
- const result = useAsyncResource<readonly DomainSearchResult[]>(
21
- available ? () => shell.apps.searchDomains() : null,
22
- NO_DOMAINS,
23
- [shell, available],
24
- )
25
-
26
- return useMemo(
27
- () => ({
28
- domains: result.data,
29
- pending: result.pending,
30
- error: result.error,
31
- live: false,
32
- seq: 0,
33
- refetch: result.refetch,
34
- }),
35
- [result],
36
- )
37
- }
@@ -1,158 +0,0 @@
1
- import type { Domain, Definition } from '@astrale-os/sdk/domain'
2
- import type { ReactRouteModule, ReactViewModule, ReactViewProps } from '@astrale-os/sdk/react'
3
- import type { schema } from '@astrale-os/sdk/schema'
4
- import type { Shell, ShellConfig } from '@astrale-os/shell'
5
- import type { ComponentType, LazyExoticComponent, ReactElement, ReactNode } from 'react'
6
-
7
- import { createElement, lazy, Suspense } from 'react'
8
- import { createRoot } from 'react-dom/client'
9
-
10
- import { useHistoryVersion, useOptionalNavCtx } from '../navigation/scope.context.js'
11
- import { useDomain } from '../schema/domain.hook.js'
12
- import { useTargetPath } from '../window/hooks/target-node.hook.js'
13
- import { defaultViewError, defaultViewLoading, ViewErrorBoundary } from './boundaries.js'
14
- import { ViewApp } from './view-app.js'
15
-
16
- type ViewName<S extends schema.DomainSchema> = Extract<keyof ReactRouteModule<S>['routes'], string>
17
- type ViewOf<S extends schema.DomainSchema, Name extends ViewName<S>> = Extract<
18
- Domain<S>[Name],
19
- Definition<'view'>
20
- >
21
-
22
- export interface MountDomainFrontendOptions<
23
- S extends schema.DomainSchema,
24
- Name extends ViewName<S>,
25
- > {
26
- readonly root: Element | string
27
- readonly module: ReactRouteModule<S>
28
- readonly view: Name
29
- /** Defaults to the child-side sandbox handshake. A prebuilt Shell is the full-app escape hatch. */
30
- readonly config?: ShellConfig | Shell
31
- readonly fallback?: ReactNode
32
- readonly errorFallback?: (error: unknown, retry: () => void) => ReactNode
33
- readonly onError?: (error: unknown) => void
34
- }
35
-
36
- export interface MountedDomainFrontend {
37
- unmount(): void
38
- }
39
-
40
- /** Browser bootstrap used by SDK-generated route entries and custom full React apps alike. */
41
- export function mountDomainFrontend<
42
- const S extends schema.DomainSchema,
43
- const Name extends ViewName<S>,
44
- >(options: MountDomainFrontendOptions<S, Name>): MountedDomainFrontend {
45
- const rootElement =
46
- typeof options.root === 'string' ? document.querySelector(options.root) : options.root
47
- if (rootElement === null) throw new Error(`React frontend root '${options.root}' was not found.`)
48
- const route = options.module.routes[options.view]
49
- if (route === undefined) throw new Error(`React View '${options.view}' is not implemented.`)
50
- const loading = options.fallback ?? defaultViewLoading()
51
- const errorFallback = options.errorFallback ?? defaultViewError
52
- const routeRuntime = createRouteRuntime()
53
- const root = createRoot(rootElement)
54
- root.render(
55
- <ViewApp
56
- config={options.config ?? { mode: 'sandboxed' }}
57
- fallback={loading}
58
- errorFallback={errorFallback}
59
- onError={({ error }) => options.onError?.(error)}
60
- >
61
- <ViewErrorBoundary fallback={errorFallback} onError={options.onError}>
62
- {(generation) => (
63
- <Suspense fallback={loading}>
64
- <DomainRoute
65
- module={options.module}
66
- name={options.view}
67
- generation={generation}
68
- runtime={routeRuntime}
69
- />
70
- </Suspense>
71
- )}
72
- </ViewErrorBoundary>
73
- </ViewApp>,
74
- )
75
- return Object.freeze({ unmount: () => root.unmount() })
76
- }
77
-
78
- function DomainRoute<S extends schema.DomainSchema, Name extends ViewName<S>>(props: {
79
- readonly module: ReactRouteModule<S>
80
- readonly name: Name
81
- readonly generation: number
82
- readonly runtime: RouteRuntime
83
- }): ReactElement {
84
- const domain = useDomain(props.module.schema)
85
- const navigation = useOptionalNavCtx()
86
- useHistoryVersion(navigation?.history ?? null)
87
- const view = domain[props.name] as ViewOf<S, Name>
88
- // Domain's schema-indexed conditional retains the exact authored View type,
89
- // while the runtime member has Core's common rich Definition shape.
90
- const runtimeView = view as unknown as Definition<'view'>
91
- const targetPath = useTargetPath()
92
- const implementation = props.module.routes[props.name]!
93
- const Component = props.runtime.component<ViewOf<S, Name>>(props.generation, implementation)
94
- const declaration = runtimeView.definition as { readonly target: { readonly kind: string } }
95
- const target =
96
- declaration.target.kind === 'domain'
97
- ? Object.freeze({ kind: 'domain' as const, origin: runtimeView.origin })
98
- : targetPath === null
99
- ? missingTarget(runtimeView.name)
100
- : targetPath
101
- const current = new URL(window.location.href)
102
- const routeParams = navigation?.history.current?.params ?? directRouteParams(current)
103
- const route = Object.freeze({
104
- name: props.name,
105
- href: current.href,
106
- params: Object.freeze({ ...routeParams }),
107
- })
108
- return createElement(Component, { view, target, route } as unknown as ReactViewProps<
109
- ViewOf<S, Name>
110
- >)
111
- }
112
-
113
- function directRouteParams(url: URL): Readonly<Record<string, string>> {
114
- const params: Record<string, string> = {}
115
- const prefix = 'astrale.param.'
116
- for (const key of new Set(url.searchParams.keys())) {
117
- if (!key.startsWith(prefix)) continue
118
- const name = key.slice(prefix.length)
119
- if (name.length === 0 || /token|credential|authorization|secret/i.test(name)) {
120
- throw new TypeError(`React View route param '${name}' is invalid.`)
121
- }
122
- const values = url.searchParams.getAll(key)
123
- if (values.length !== 1) throw new TypeError(`React View route param '${name}' is duplicated.`)
124
- params[name] = values[0]!
125
- }
126
- return Object.freeze(params)
127
- }
128
-
129
- interface RouteRuntime {
130
- component<View extends Definition<'view'>>(
131
- generation: number,
132
- implementation: { readonly component: () => Promise<ReactViewModule<View>> },
133
- ): ComponentType<ReactViewProps<View>>
134
- }
135
-
136
- function createRouteRuntime(): RouteRuntime {
137
- const generations = new Map<number, LazyExoticComponent<ComponentType<ReactViewProps<never>>>>()
138
- return {
139
- component<View extends Definition<'view'>>(
140
- generation: number,
141
- implementation: { readonly component: () => Promise<ReactViewModule<View>> },
142
- ): ComponentType<ReactViewProps<View>> {
143
- let Component = generations.get(generation)
144
- if (Component === undefined) {
145
- Component = lazy(async () => {
146
- const loaded = await implementation.component()
147
- return { default: loaded.default as ComponentType<ReactViewProps<never>> }
148
- })
149
- generations.set(generation, Component)
150
- }
151
- return Component as unknown as ComponentType<ReactViewProps<View>>
152
- },
153
- }
154
- }
155
-
156
- function missingTarget(name: string): never {
157
- throw new Error(`React View '${name}' requires a resource target from the Shell handshake.`)
158
- }
@@ -1,49 +0,0 @@
1
- import type { Shell, ShellConfig } from '@astrale-os/shell'
2
- import type { ReactElement, ReactNode } from 'react'
3
-
4
- import type { NavAdapter } from '../navigation/adapters/adapter.js'
5
- import type { NavTarget } from '../navigation/snapshot.js'
6
- import type { ShellProviderProps } from '../session/provider.js'
7
-
8
- import { memoryAdapter } from '../navigation/adapters/memory.adapter.js'
9
- import { urlAdapter } from '../navigation/adapters/url.adapter.js'
10
- import { NavScope } from '../navigation/scope.context.js'
11
- import { ShellProvider } from '../session/provider.js'
12
- import { useShell } from '../session/shell.hook.js'
13
- import { ViewStage } from '../window/stage.js'
14
-
15
- /** One generated/default root; custom React apps may compose the lower-level providers directly. */
16
- export function ViewApp(props: {
17
- readonly config: ShellConfig | Shell
18
- readonly navigation?: NavAdapter
19
- readonly initial?: NavTarget
20
- readonly fallback?: ReactNode
21
- readonly errorFallback?: ShellProviderProps['errorFallback']
22
- readonly onError?: ShellProviderProps['onError']
23
- readonly children: ReactNode
24
- }): ReactElement {
25
- return (
26
- <ShellProvider
27
- config={props.config}
28
- fallback={props.fallback}
29
- errorFallback={props.errorFallback}
30
- onError={props.onError}
31
- >
32
- <ViewAppRuntime {...props} />
33
- </ShellProvider>
34
- )
35
- }
36
-
37
- function ViewAppRuntime(
38
- props: Omit<Parameters<typeof ViewApp>[0], 'config' | 'fallback'>,
39
- ): ReactElement {
40
- const shell = useShell()
41
- const defaultAdapter =
42
- shell.hostCapabilities.navigation.history === 'browser' ? urlAdapter() : memoryAdapter()
43
- return (
44
- <NavScope adapter={props.navigation ?? defaultAdapter} initial={props.initial}>
45
- {props.children}
46
- <ViewStage />
47
- </NavScope>
48
- )
49
- }