@cohesivesystems/presentation-react 0.1.0-alpha.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/LICENSE +55 -0
- package/dist/collection-chrome-slot-renderer-registry.d.ts +12 -0
- package/dist/collection-chrome-slot-renderer-registry.d.ts.map +1 -0
- package/dist/collection-chrome-slot-renderer-registry.js +12 -0
- package/dist/collection-chrome-slot-renderer-registry.js.map +1 -0
- package/dist/collection-selection-state-context.d.ts +6 -0
- package/dist/collection-selection-state-context.d.ts.map +1 -0
- package/dist/collection-selection-state-context.js +25 -0
- package/dist/collection-selection-state-context.js.map +1 -0
- package/dist/collection-selection-state.d.ts +3 -0
- package/dist/collection-selection-state.d.ts.map +1 -0
- package/dist/collection-selection-state.js +52 -0
- package/dist/collection-selection-state.js.map +1 -0
- package/dist/document-workspace-runtime.d.ts +262 -0
- package/dist/document-workspace-runtime.d.ts.map +1 -0
- package/dist/document-workspace-runtime.js +699 -0
- package/dist/document-workspace-runtime.js.map +1 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/input-form-endpoint-runtime.d.ts +140 -0
- package/dist/input-form-endpoint-runtime.d.ts.map +1 -0
- package/dist/input-form-endpoint-runtime.js +280 -0
- package/dist/input-form-endpoint-runtime.js.map +1 -0
- package/dist/local-flow-state-data-source-projection.d.ts +21 -0
- package/dist/local-flow-state-data-source-projection.d.ts.map +1 -0
- package/dist/local-flow-state-data-source-projection.js +65 -0
- package/dist/local-flow-state-data-source-projection.js.map +1 -0
- package/dist/navigation-runtime-context.d.ts +22 -0
- package/dist/navigation-runtime-context.d.ts.map +1 -0
- package/dist/navigation-runtime-context.js +23 -0
- package/dist/navigation-runtime-context.js.map +1 -0
- package/dist/navigation-shell-frame-renderer-registry.d.ts +20 -0
- package/dist/navigation-shell-frame-renderer-registry.d.ts.map +1 -0
- package/dist/navigation-shell-frame-renderer-registry.js +9 -0
- package/dist/navigation-shell-frame-renderer-registry.js.map +1 -0
- package/dist/navigation-shell-region-component-registry.d.ts +50 -0
- package/dist/navigation-shell-region-component-registry.d.ts.map +1 -0
- package/dist/navigation-shell-region-component-registry.js +44 -0
- package/dist/navigation-shell-region-component-registry.js.map +1 -0
- package/dist/navigation-shell-slot-renderer-registry.d.ts +22 -0
- package/dist/navigation-shell-slot-renderer-registry.d.ts.map +1 -0
- package/dist/navigation-shell-slot-renderer-registry.js +9 -0
- package/dist/navigation-shell-slot-renderer-registry.js.map +1 -0
- package/dist/page-host-projection.d.ts +127 -0
- package/dist/page-host-projection.d.ts.map +1 -0
- package/dist/page-host-projection.js +59 -0
- package/dist/page-host-projection.js.map +1 -0
- package/dist/page-host-renderer-registry.d.ts +72 -0
- package/dist/page-host-renderer-registry.d.ts.map +1 -0
- package/dist/page-host-renderer-registry.js +63 -0
- package/dist/page-host-renderer-registry.js.map +1 -0
- package/dist/presentation-action-group-runtime-options.d.ts +36 -0
- package/dist/presentation-action-group-runtime-options.d.ts.map +1 -0
- package/dist/presentation-action-group-runtime-options.js +50 -0
- package/dist/presentation-action-group-runtime-options.js.map +1 -0
- package/dist/presentation-action-runtime.d.ts +52 -0
- package/dist/presentation-action-runtime.d.ts.map +1 -0
- package/dist/presentation-action-runtime.js +78 -0
- package/dist/presentation-action-runtime.js.map +1 -0
- package/dist/presentation-data-source-binding-runtime.d.ts +3 -0
- package/dist/presentation-data-source-binding-runtime.d.ts.map +1 -0
- package/dist/presentation-data-source-binding-runtime.js +65 -0
- package/dist/presentation-data-source-binding-runtime.js.map +1 -0
- package/dist/presentation-data-source-binding.d.ts +12 -0
- package/dist/presentation-data-source-binding.d.ts.map +1 -0
- package/dist/presentation-data-source-binding.js +13 -0
- package/dist/presentation-data-source-binding.js.map +1 -0
- package/dist/presentation-flow-runtime.d.ts +139 -0
- package/dist/presentation-flow-runtime.d.ts.map +1 -0
- package/dist/presentation-flow-runtime.js +514 -0
- package/dist/presentation-flow-runtime.js.map +1 -0
- package/dist/presentation-module-context.d.ts +4 -0
- package/dist/presentation-module-context.d.ts.map +1 -0
- package/dist/presentation-module-context.js +6 -0
- package/dist/presentation-module-context.js.map +1 -0
- package/dist/presentation-module-provider.d.ts +7 -0
- package/dist/presentation-module-provider.d.ts.map +1 -0
- package/dist/presentation-module-provider.js +7 -0
- package/dist/presentation-module-provider.js.map +1 -0
- package/dist/presentation-projection-diagnostics-context.d.ts +8 -0
- package/dist/presentation-projection-diagnostics-context.d.ts.map +1 -0
- package/dist/presentation-projection-diagnostics-context.js +3 -0
- package/dist/presentation-projection-diagnostics-context.js.map +1 -0
- package/dist/presentation-projection-diagnostics-hooks.d.ts +4 -0
- package/dist/presentation-projection-diagnostics-hooks.d.ts.map +1 -0
- package/dist/presentation-projection-diagnostics-hooks.js +17 -0
- package/dist/presentation-projection-diagnostics-hooks.js.map +1 -0
- package/dist/presentation-projection-diagnostics-runtime.d.ts +12 -0
- package/dist/presentation-projection-diagnostics-runtime.d.ts.map +1 -0
- package/dist/presentation-projection-diagnostics-runtime.js +54 -0
- package/dist/presentation-projection-diagnostics-runtime.js.map +1 -0
- package/dist/presentation-projection-trace.d.ts +27 -0
- package/dist/presentation-projection-trace.d.ts.map +1 -0
- package/dist/presentation-projection-trace.js +54 -0
- package/dist/presentation-projection-trace.js.map +1 -0
- package/dist/presentation-query-form-runtime.d.ts +30 -0
- package/dist/presentation-query-form-runtime.d.ts.map +1 -0
- package/dist/presentation-query-form-runtime.js +75 -0
- package/dist/presentation-query-form-runtime.js.map +1 -0
- package/dist/presentation-query-form-state-adapter-registry.d.ts +4 -0
- package/dist/presentation-query-form-state-adapter-registry.d.ts.map +1 -0
- package/dist/presentation-query-form-state-adapter-registry.js +13 -0
- package/dist/presentation-query-form-state-adapter-registry.js.map +1 -0
- package/dist/presentation-query-form-state-context.d.ts +20 -0
- package/dist/presentation-query-form-state-context.d.ts.map +1 -0
- package/dist/presentation-query-form-state-context.js +20 -0
- package/dist/presentation-query-form-state-context.js.map +1 -0
- package/dist/presentation-query-form-state.d.ts +29 -0
- package/dist/presentation-query-form-state.d.ts.map +1 -0
- package/dist/presentation-query-form-state.js +99 -0
- package/dist/presentation-query-form-state.js.map +1 -0
- package/dist/presentation-renderer-registry.d.ts +109 -0
- package/dist/presentation-renderer-registry.d.ts.map +1 -0
- package/dist/presentation-renderer-registry.js +25 -0
- package/dist/presentation-renderer-registry.js.map +1 -0
- package/dist/presentation-standards-context.d.ts +4 -0
- package/dist/presentation-standards-context.d.ts.map +1 -0
- package/dist/presentation-standards-context.js +12 -0
- package/dist/presentation-standards-context.js.map +1 -0
- package/dist/presentation-standards-provider.d.ts +14 -0
- package/dist/presentation-standards-provider.d.ts.map +1 -0
- package/dist/presentation-standards-provider.js +16 -0
- package/dist/presentation-standards-provider.js.map +1 -0
- package/dist/projected-document-action-runtime-bindings.d.ts +20 -0
- package/dist/projected-document-action-runtime-bindings.d.ts.map +1 -0
- package/dist/projected-document-action-runtime-bindings.js +88 -0
- package/dist/projected-document-action-runtime-bindings.js.map +1 -0
- package/dist/projected-document-action-runtime.d.ts +76 -0
- package/dist/projected-document-action-runtime.d.ts.map +1 -0
- package/dist/projected-document-action-runtime.js +224 -0
- package/dist/projected-document-action-runtime.js.map +1 -0
- package/dist/projected-document-process-preview-action-runtime-bindings.d.ts +26 -0
- package/dist/projected-document-process-preview-action-runtime-bindings.d.ts.map +1 -0
- package/dist/projected-document-process-preview-action-runtime-bindings.js +106 -0
- package/dist/projected-document-process-preview-action-runtime-bindings.js.map +1 -0
- package/dist/projected-document-process-preview-action-runtime.d.ts +321 -0
- package/dist/projected-document-process-preview-action-runtime.d.ts.map +1 -0
- package/dist/projected-document-process-preview-action-runtime.js +729 -0
- package/dist/projected-document-process-preview-action-runtime.js.map +1 -0
- package/dist/projected-document-process-preview-capability-runtime.d.ts +47 -0
- package/dist/projected-document-process-preview-capability-runtime.d.ts.map +1 -0
- package/dist/projected-document-process-preview-capability-runtime.js +49 -0
- package/dist/projected-document-process-preview-capability-runtime.js.map +1 -0
- package/dist/projected-document-workspace-action-runtime.d.ts +87 -0
- package/dist/projected-document-workspace-action-runtime.d.ts.map +1 -0
- package/dist/projected-document-workspace-action-runtime.js +150 -0
- package/dist/projected-document-workspace-action-runtime.js.map +1 -0
- package/dist/projected-document-workspace-projection-renderer-diagnostics.d.ts +18 -0
- package/dist/projected-document-workspace-projection-renderer-diagnostics.d.ts.map +1 -0
- package/dist/projected-document-workspace-projection-renderer-diagnostics.js +207 -0
- package/dist/projected-document-workspace-projection-renderer-diagnostics.js.map +1 -0
- package/dist/projected-document-workspace-runtime-binding-diagnostics.d.ts +19 -0
- package/dist/projected-document-workspace-runtime-binding-diagnostics.d.ts.map +1 -0
- package/dist/projected-document-workspace-runtime-binding-diagnostics.js +124 -0
- package/dist/projected-document-workspace-runtime-binding-diagnostics.js.map +1 -0
- package/dist/projected-navigation-provider.d.ts +16 -0
- package/dist/projected-navigation-provider.d.ts.map +1 -0
- package/dist/projected-navigation-provider.js +51 -0
- package/dist/projected-navigation-provider.js.map +1 -0
- package/dist/projected-presentation-flow-host.d.ts +16 -0
- package/dist/projected-presentation-flow-host.d.ts.map +1 -0
- package/dist/projected-presentation-flow-host.js +14 -0
- package/dist/projected-presentation-flow-host.js.map +1 -0
- package/dist/projected-query-form-state-adapter.d.ts +12 -0
- package/dist/projected-query-form-state-adapter.d.ts.map +1 -0
- package/dist/projected-query-form-state-adapter.js +361 -0
- package/dist/projected-query-form-state-adapter.js.map +1 -0
- package/dist/react-router-binding.d.ts +133 -0
- package/dist/react-router-binding.d.ts.map +1 -0
- package/dist/react-router-binding.js +76 -0
- package/dist/react-router-binding.js.map +1 -0
- package/dist/react-router-path.d.ts +4 -0
- package/dist/react-router-path.d.ts.map +1 -0
- package/dist/react-router-path.js +11 -0
- package/dist/react-router-path.js.map +1 -0
- package/dist/scope-selection-context.d.ts +28 -0
- package/dist/scope-selection-context.d.ts.map +1 -0
- package/dist/scope-selection-context.js +13 -0
- package/dist/scope-selection-context.js.map +1 -0
- package/dist/scope-selection-provider.d.ts +33 -0
- package/dist/scope-selection-provider.d.ts.map +1 -0
- package/dist/scope-selection-provider.js +162 -0
- package/dist/scope-selection-provider.js.map +1 -0
- package/dist/scope-selection-request.d.ts +6 -0
- package/dist/scope-selection-request.d.ts.map +1 -0
- package/dist/scope-selection-request.js +12 -0
- package/dist/scope-selection-request.js.map +1 -0
- package/dist/standard-navigation-shell-frame-renderers.d.ts +15 -0
- package/dist/standard-navigation-shell-frame-renderers.d.ts.map +1 -0
- package/dist/standard-navigation-shell-frame-renderers.js +22 -0
- package/dist/standard-navigation-shell-frame-renderers.js.map +1 -0
- package/dist/standard-navigation-shell-slot-renderers.d.ts +59 -0
- package/dist/standard-navigation-shell-slot-renderers.d.ts.map +1 -0
- package/dist/standard-navigation-shell-slot-renderers.js +67 -0
- package/dist/standard-navigation-shell-slot-renderers.js.map +1 -0
- package/dist/view-chrome-slot-renderer-registry.d.ts +12 -0
- package/dist/view-chrome-slot-renderer-registry.d.ts.map +1 -0
- package/dist/view-chrome-slot-renderer-registry.js +12 -0
- package/dist/view-chrome-slot-renderer-registry.js.map +1 -0
- package/package.json +60 -0
- package/src/collection-chrome-slot-renderer-registry.ts +66 -0
- package/src/collection-selection-state-context.ts +51 -0
- package/src/collection-selection-state.tsx +101 -0
- package/src/document-workspace-runtime.tsx +1505 -0
- package/src/index.ts +50 -0
- package/src/input-form-endpoint-runtime.ts +632 -0
- package/src/local-flow-state-data-source-projection.ts +133 -0
- package/src/navigation-runtime-context.ts +40 -0
- package/src/navigation-shell-frame-renderer-registry.ts +54 -0
- package/src/navigation-shell-region-component-registry.tsx +127 -0
- package/src/navigation-shell-slot-renderer-registry.ts +88 -0
- package/src/page-host-projection.ts +356 -0
- package/src/page-host-renderer-registry.tsx +353 -0
- package/src/presentation-action-group-runtime-options.ts +121 -0
- package/src/presentation-action-runtime.ts +190 -0
- package/src/presentation-data-source-binding-runtime.ts +109 -0
- package/src/presentation-data-source-binding.tsx +24 -0
- package/src/presentation-flow-runtime.tsx +835 -0
- package/src/presentation-module-context.ts +10 -0
- package/src/presentation-module-provider.tsx +19 -0
- package/src/presentation-projection-diagnostics-context.ts +17 -0
- package/src/presentation-projection-diagnostics-hooks.ts +29 -0
- package/src/presentation-projection-diagnostics-runtime.tsx +95 -0
- package/src/presentation-projection-trace.ts +117 -0
- package/src/presentation-query-form-runtime.ts +148 -0
- package/src/presentation-query-form-state-adapter-registry.ts +25 -0
- package/src/presentation-query-form-state-context.ts +56 -0
- package/src/presentation-query-form-state.tsx +250 -0
- package/src/presentation-renderer-registry.ts +214 -0
- package/src/presentation-standards-context.ts +21 -0
- package/src/presentation-standards-provider.tsx +44 -0
- package/src/projected-document-action-runtime-bindings.ts +132 -0
- package/src/projected-document-action-runtime.ts +414 -0
- package/src/projected-document-process-preview-action-runtime-bindings.ts +231 -0
- package/src/projected-document-process-preview-action-runtime.ts +1725 -0
- package/src/projected-document-process-preview-capability-runtime.ts +216 -0
- package/src/projected-document-workspace-action-runtime.ts +402 -0
- package/src/projected-document-workspace-projection-renderer-diagnostics.ts +342 -0
- package/src/projected-document-workspace-runtime-binding-diagnostics.ts +208 -0
- package/src/projected-navigation-provider.tsx +104 -0
- package/src/projected-presentation-flow-host.tsx +46 -0
- package/src/projected-query-form-state-adapter.ts +578 -0
- package/src/react-router-binding.tsx +417 -0
- package/src/react-router-path.ts +16 -0
- package/src/scope-selection-context.ts +58 -0
- package/src/scope-selection-provider.tsx +324 -0
- package/src/scope-selection-request.ts +21 -0
- package/src/standard-navigation-shell-frame-renderers.tsx +106 -0
- package/src/standard-navigation-shell-slot-renderers.tsx +289 -0
- package/src/view-chrome-slot-renderer-registry.ts +66 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { useQuery, type QueryKey } from '@tanstack/react-query'
|
|
2
|
+
import {
|
|
3
|
+
useCallback,
|
|
4
|
+
useLayoutEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useState,
|
|
7
|
+
type PropsWithChildren,
|
|
8
|
+
} from 'react'
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
formatPresentationScopeSelectionQuerySuffix,
|
|
12
|
+
normalizeScopeIds,
|
|
13
|
+
type PresentationScopeAccess,
|
|
14
|
+
type PresentationScopeRequestStore,
|
|
15
|
+
} from '@cohesivesystems/presentation-core'
|
|
16
|
+
import {
|
|
17
|
+
PresentationScopeSelectionContext,
|
|
18
|
+
type PresentationScopeSelectionContextValue,
|
|
19
|
+
} from './scope-selection-context'
|
|
20
|
+
|
|
21
|
+
interface SelectedScopeOverride {
|
|
22
|
+
readonly identityKey: string
|
|
23
|
+
readonly scopeId: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface SelectedScopeIdsOverride {
|
|
27
|
+
readonly identityKey: string
|
|
28
|
+
readonly scopeIds: readonly string[]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Options for the generic presentation scope-selection provider.
|
|
33
|
+
*/
|
|
34
|
+
export interface PresentationScopeSelectionProviderProps<
|
|
35
|
+
TScopeContext,
|
|
36
|
+
TScopeMetadata = unknown,
|
|
37
|
+
> extends PropsWithChildren {
|
|
38
|
+
/** Whether scope context may be loaded. */
|
|
39
|
+
readonly enabled: boolean
|
|
40
|
+
|
|
41
|
+
/** Identity/session partition key used for cache and persisted selection state. */
|
|
42
|
+
readonly identityKey: string
|
|
43
|
+
|
|
44
|
+
/** Query key used to load the source scope context. */
|
|
45
|
+
readonly queryKey: QueryKey
|
|
46
|
+
|
|
47
|
+
/** Loads the source scope context. */
|
|
48
|
+
readonly loadScopeContext: () => Promise<TScopeContext>
|
|
49
|
+
|
|
50
|
+
/** Projects accessible scopes from the source context. */
|
|
51
|
+
readonly getScopes: (
|
|
52
|
+
scopeContext: TScopeContext
|
|
53
|
+
) => readonly PresentationScopeAccess<TScopeMetadata>[]
|
|
54
|
+
|
|
55
|
+
/** Resolves the default scope id from the source context and projected scopes. */
|
|
56
|
+
readonly getDefaultScopeId?: (
|
|
57
|
+
scopeContext: TScopeContext,
|
|
58
|
+
scopes: readonly PresentationScopeAccess<TScopeMetadata>[]
|
|
59
|
+
) => string | null
|
|
60
|
+
|
|
61
|
+
/** Prefix used for persisted local selection keys. */
|
|
62
|
+
readonly storageKeyPrefix: string
|
|
63
|
+
|
|
64
|
+
/** Optional request-scope store to synchronize with the primary selected scope. */
|
|
65
|
+
readonly requestStore?: PresentationScopeRequestStore
|
|
66
|
+
|
|
67
|
+
/** Label used for single-scope query/cache suffixes. */
|
|
68
|
+
readonly singleScopeQueryLabel?: string
|
|
69
|
+
|
|
70
|
+
/** Label used for multi-scope query/cache suffixes. */
|
|
71
|
+
readonly multipleScopesQueryLabel?: string
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Provides generic authorized-scope selection state for presentation hosts.
|
|
76
|
+
*/
|
|
77
|
+
export function PresentationScopeSelectionProvider<
|
|
78
|
+
TScopeContext,
|
|
79
|
+
TScopeMetadata = unknown,
|
|
80
|
+
>({
|
|
81
|
+
children,
|
|
82
|
+
enabled,
|
|
83
|
+
getDefaultScopeId,
|
|
84
|
+
getScopes,
|
|
85
|
+
identityKey,
|
|
86
|
+
loadScopeContext,
|
|
87
|
+
multipleScopesQueryLabel,
|
|
88
|
+
queryKey,
|
|
89
|
+
requestStore,
|
|
90
|
+
singleScopeQueryLabel,
|
|
91
|
+
storageKeyPrefix,
|
|
92
|
+
}: PresentationScopeSelectionProviderProps<TScopeContext, TScopeMetadata>) {
|
|
93
|
+
const [selectedScopeOverride, setSelectedScopeOverride] =
|
|
94
|
+
useState<SelectedScopeOverride | null>(null)
|
|
95
|
+
const [selectedScopeIdsOverrides, setSelectedScopeIdsOverrides] =
|
|
96
|
+
useState<Record<string, SelectedScopeIdsOverride>>({})
|
|
97
|
+
const scopeContextQuery = useQuery<TScopeContext>({
|
|
98
|
+
enabled,
|
|
99
|
+
queryFn: loadScopeContext,
|
|
100
|
+
queryKey,
|
|
101
|
+
retry: false,
|
|
102
|
+
})
|
|
103
|
+
const scopeContext = scopeContextQuery.data ?? null
|
|
104
|
+
const scopes = useMemo<readonly PresentationScopeAccess<TScopeMetadata>[]>(
|
|
105
|
+
() => scopeContext ? getScopes(scopeContext) : [],
|
|
106
|
+
[getScopes, scopeContext],
|
|
107
|
+
)
|
|
108
|
+
const scopeIdSet = useMemo(
|
|
109
|
+
() => new Set(scopes.map((scope) => scope.id)),
|
|
110
|
+
[scopes],
|
|
111
|
+
)
|
|
112
|
+
const selectedScopeId = useMemo(() => {
|
|
113
|
+
if (!enabled || !scopeContext) {
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
selectedScopeOverride?.identityKey === identityKey &&
|
|
119
|
+
isAllowedScope(selectedScopeOverride.scopeId, scopeIdSet)
|
|
120
|
+
) {
|
|
121
|
+
return selectedScopeOverride.scopeId
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const storedScopeId = readStoredScopeId(storageKeyPrefix, identityKey, 'single')
|
|
125
|
+
if (isAllowedScope(storedScopeId, scopeIdSet)) {
|
|
126
|
+
return storedScopeId
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return resolveDefaultScopeId(scopeContext, scopes, getDefaultScopeId)
|
|
130
|
+
}, [
|
|
131
|
+
enabled,
|
|
132
|
+
getDefaultScopeId,
|
|
133
|
+
identityKey,
|
|
134
|
+
scopeContext,
|
|
135
|
+
scopeIdSet,
|
|
136
|
+
scopes,
|
|
137
|
+
selectedScopeOverride,
|
|
138
|
+
storageKeyPrefix,
|
|
139
|
+
])
|
|
140
|
+
const singleScopeQuerySuffix = formatPresentationScopeSelectionQuerySuffix(
|
|
141
|
+
{
|
|
142
|
+
mode: 'single',
|
|
143
|
+
scopeId: selectedScopeId,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
multipleScopesLabel: multipleScopesQueryLabel,
|
|
147
|
+
singleScopeLabel: singleScopeQueryLabel,
|
|
148
|
+
},
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
useLayoutEffect(() => {
|
|
152
|
+
requestStore?.setSelection({
|
|
153
|
+
mode: 'single',
|
|
154
|
+
scopeId: selectedScopeId,
|
|
155
|
+
})
|
|
156
|
+
}, [requestStore, selectedScopeId])
|
|
157
|
+
|
|
158
|
+
const setSelectedScopeId = useCallback(
|
|
159
|
+
(scopeId: string) => {
|
|
160
|
+
if (!scopeIdSet.has(scopeId)) {
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
setSelectedScopeOverride({ identityKey, scopeId })
|
|
165
|
+
writeStoredScopeId(storageKeyPrefix, identityKey, 'single', scopeId)
|
|
166
|
+
},
|
|
167
|
+
[identityKey, scopeIdSet, storageKeyPrefix],
|
|
168
|
+
)
|
|
169
|
+
const getSelectedScopeIds = useCallback(
|
|
170
|
+
(purpose: string, fallbackScopeIds: readonly string[] = []) => {
|
|
171
|
+
const scopeIds =
|
|
172
|
+
selectedScopeIdsOverrides[purpose]?.identityKey === identityKey
|
|
173
|
+
? selectedScopeIdsOverrides[purpose].scopeIds
|
|
174
|
+
: readStoredScopeIds(storageKeyPrefix, identityKey, purpose)
|
|
175
|
+
|
|
176
|
+
return normalizeSelectedScopeIds(scopeIds, scopeIdSet, fallbackScopeIds)
|
|
177
|
+
},
|
|
178
|
+
[
|
|
179
|
+
identityKey,
|
|
180
|
+
scopeIdSet,
|
|
181
|
+
selectedScopeIdsOverrides,
|
|
182
|
+
storageKeyPrefix,
|
|
183
|
+
],
|
|
184
|
+
)
|
|
185
|
+
const setSelectedScopeIds = useCallback(
|
|
186
|
+
(purpose: string, scopeIds: readonly string[]) => {
|
|
187
|
+
const fallbackScopeIds = selectedScopeId ? [selectedScopeId] : []
|
|
188
|
+
const nextScopeIds = normalizeSelectedScopeIds(scopeIds, scopeIdSet, fallbackScopeIds)
|
|
189
|
+
setSelectedScopeIdsOverrides((current) => ({
|
|
190
|
+
...current,
|
|
191
|
+
[purpose]: {
|
|
192
|
+
identityKey,
|
|
193
|
+
scopeIds: nextScopeIds,
|
|
194
|
+
},
|
|
195
|
+
}))
|
|
196
|
+
writeStoredScopeIds(storageKeyPrefix, identityKey, purpose, nextScopeIds)
|
|
197
|
+
},
|
|
198
|
+
[identityKey, scopeIdSet, selectedScopeId, storageKeyPrefix],
|
|
199
|
+
)
|
|
200
|
+
const value = useMemo<PresentationScopeSelectionContextValue<TScopeContext, TScopeMetadata>>(
|
|
201
|
+
() => ({
|
|
202
|
+
getSelectedScopeIds,
|
|
203
|
+
isLoading: scopeContextQuery.isLoading,
|
|
204
|
+
scopes,
|
|
205
|
+
scopeContext,
|
|
206
|
+
selectedScopeId,
|
|
207
|
+
setSelectedScopeId,
|
|
208
|
+
setSelectedScopeIds,
|
|
209
|
+
singleScopeQuerySuffix,
|
|
210
|
+
}),
|
|
211
|
+
[
|
|
212
|
+
getSelectedScopeIds,
|
|
213
|
+
scopeContext,
|
|
214
|
+
scopeContextQuery.isLoading,
|
|
215
|
+
scopes,
|
|
216
|
+
selectedScopeId,
|
|
217
|
+
setSelectedScopeId,
|
|
218
|
+
setSelectedScopeIds,
|
|
219
|
+
singleScopeQuerySuffix,
|
|
220
|
+
],
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<PresentationScopeSelectionContext.Provider value={value}>
|
|
225
|
+
{children}
|
|
226
|
+
</PresentationScopeSelectionContext.Provider>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function resolveDefaultScopeId<TScopeContext, TScopeMetadata>(
|
|
231
|
+
scopeContext: TScopeContext,
|
|
232
|
+
scopes: readonly PresentationScopeAccess<TScopeMetadata>[],
|
|
233
|
+
getDefaultScopeId:
|
|
234
|
+
| ((
|
|
235
|
+
scopeContext: TScopeContext,
|
|
236
|
+
scopes: readonly PresentationScopeAccess<TScopeMetadata>[]
|
|
237
|
+
) => string | null)
|
|
238
|
+
| undefined,
|
|
239
|
+
) {
|
|
240
|
+
const scopeIds = new Set(scopes.map((scope) => scope.id))
|
|
241
|
+
const defaultScopeId = getDefaultScopeId?.(scopeContext, scopes)
|
|
242
|
+
if (defaultScopeId && scopeIds.has(defaultScopeId)) {
|
|
243
|
+
return defaultScopeId
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return scopes.find((scope) => scope.isDefault)?.id ?? scopes[0]?.id ?? null
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function normalizeSelectedScopeIds(
|
|
250
|
+
scopeIds: readonly string[],
|
|
251
|
+
allowedScopeIds: ReadonlySet<string>,
|
|
252
|
+
fallbackScopeIds: readonly string[],
|
|
253
|
+
) {
|
|
254
|
+
const selected = normalizeScopeIds(scopeIds)
|
|
255
|
+
.filter((scopeId) => allowedScopeIds.has(scopeId))
|
|
256
|
+
if (selected.length > 0) {
|
|
257
|
+
return selected
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return normalizeScopeIds(fallbackScopeIds)
|
|
261
|
+
.filter((scopeId) => allowedScopeIds.has(scopeId))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function isAllowedScope(
|
|
265
|
+
scopeId: string | null,
|
|
266
|
+
allowedScopeIds: ReadonlySet<string>,
|
|
267
|
+
): scopeId is string {
|
|
268
|
+
return scopeId !== null && allowedScopeIds.has(scopeId)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function readStoredScopeId(storageKeyPrefix: string, identityKey: string, purpose: string) {
|
|
272
|
+
if (typeof window === 'undefined') {
|
|
273
|
+
return null
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const value = window.localStorage.getItem(createStorageKey(storageKeyPrefix, identityKey, purpose))
|
|
277
|
+
return value && value.trim().length > 0 ? value : null
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function writeStoredScopeId(
|
|
281
|
+
storageKeyPrefix: string,
|
|
282
|
+
identityKey: string,
|
|
283
|
+
purpose: string,
|
|
284
|
+
scopeId: string,
|
|
285
|
+
) {
|
|
286
|
+
if (typeof window === 'undefined') {
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
window.localStorage.setItem(createStorageKey(storageKeyPrefix, identityKey, purpose), scopeId)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function readStoredScopeIds(storageKeyPrefix: string, identityKey: string, purpose: string) {
|
|
294
|
+
if (typeof window === 'undefined') {
|
|
295
|
+
return []
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
const value = window.localStorage.getItem(createStorageKey(storageKeyPrefix, identityKey, purpose))
|
|
300
|
+
return value ? JSON.parse(value) as string[] : []
|
|
301
|
+
} catch {
|
|
302
|
+
return []
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function writeStoredScopeIds(
|
|
307
|
+
storageKeyPrefix: string,
|
|
308
|
+
identityKey: string,
|
|
309
|
+
purpose: string,
|
|
310
|
+
scopeIds: readonly string[],
|
|
311
|
+
) {
|
|
312
|
+
if (typeof window === 'undefined') {
|
|
313
|
+
return
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
window.localStorage.setItem(
|
|
317
|
+
createStorageKey(storageKeyPrefix, identityKey, purpose),
|
|
318
|
+
JSON.stringify(scopeIds),
|
|
319
|
+
)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function createStorageKey(storageKeyPrefix: string, identityKey: string, purpose: string) {
|
|
323
|
+
return `${storageKeyPrefix}.${purpose}.${identityKey}`
|
|
324
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useLayoutEffect } from 'react'
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
PresentationScopeRequestSelection,
|
|
5
|
+
PresentationScopeRequestStore,
|
|
6
|
+
} from '@cohesivesystems/presentation-core'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Synchronizes a mounted route or surface with the current request-scope store.
|
|
10
|
+
*/
|
|
11
|
+
export function usePresentationScopeRequestSelection(
|
|
12
|
+
store: PresentationScopeRequestStore,
|
|
13
|
+
selection: PresentationScopeRequestSelection,
|
|
14
|
+
) {
|
|
15
|
+
const selectionKey = store.formatQuerySuffix(selection)
|
|
16
|
+
|
|
17
|
+
useLayoutEffect(() => {
|
|
18
|
+
store.setSelection(selection)
|
|
19
|
+
return () => store.setSelection({ mode: 'default' })
|
|
20
|
+
}, [selection, selectionKey, store])
|
|
21
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
navigationShellKinds,
|
|
5
|
+
type NavigationShellSlotDefinition,
|
|
6
|
+
} from '@cohesivesystems/presentation-contracts'
|
|
7
|
+
import type {
|
|
8
|
+
ProjectedNavigationShellLayout,
|
|
9
|
+
} from '@cohesivesystems/presentation-core'
|
|
10
|
+
import {
|
|
11
|
+
createNavigationShellFrameRendererRegistry,
|
|
12
|
+
getNavigationShellFrameRendererRegistryKeys,
|
|
13
|
+
resolveNavigationShellFrameRenderer,
|
|
14
|
+
type ProjectedNavigationShellFrameRenderContext,
|
|
15
|
+
} from './navigation-shell-frame-renderer-registry'
|
|
16
|
+
|
|
17
|
+
export interface StandardNavigationShellFrameLayout {
|
|
18
|
+
readonly headerClassName: string
|
|
19
|
+
readonly headerContentClassName: string
|
|
20
|
+
readonly headerNavigationClassName: string
|
|
21
|
+
readonly rootClassName: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type StandardNavigationShellLayout<TSlotLayout = unknown> =
|
|
25
|
+
ProjectedNavigationShellLayout<
|
|
26
|
+
StandardNavigationShellFrameLayout,
|
|
27
|
+
TSlotLayout
|
|
28
|
+
>
|
|
29
|
+
|
|
30
|
+
export type StandardNavigationShellFrameRenderContext<TSlotLayout = unknown> =
|
|
31
|
+
ProjectedNavigationShellFrameRenderContext<
|
|
32
|
+
StandardNavigationShellLayout<TSlotLayout>
|
|
33
|
+
>
|
|
34
|
+
|
|
35
|
+
export const standardNavigationShellFrameRenderers =
|
|
36
|
+
createNavigationShellFrameRendererRegistry([
|
|
37
|
+
{
|
|
38
|
+
kind: navigationShellKinds.topNavigation,
|
|
39
|
+
render: renderStandardTopNavigationShellFrame,
|
|
40
|
+
},
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
export const standardNavigationShellFrameRendererKeys =
|
|
44
|
+
getNavigationShellFrameRendererRegistryKeys(standardNavigationShellFrameRenderers)
|
|
45
|
+
|
|
46
|
+
export function renderStandardNavigationShellFrame(
|
|
47
|
+
context: StandardNavigationShellFrameRenderContext,
|
|
48
|
+
) {
|
|
49
|
+
const renderer = resolveNavigationShellFrameRenderer(
|
|
50
|
+
standardNavigationShellFrameRenderers,
|
|
51
|
+
context.navigation.Shell.Kind,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return renderer?.(context) ?? context.children
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function renderStandardTopNavigationShellFrame({
|
|
58
|
+
children,
|
|
59
|
+
layout,
|
|
60
|
+
renderSlot,
|
|
61
|
+
}: StandardNavigationShellFrameRenderContext) {
|
|
62
|
+
const frame = layout.frame
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className={frame.rootClassName}>
|
|
66
|
+
<header className={frame.headerClassName}>
|
|
67
|
+
<div className={frame.headerContentClassName}>
|
|
68
|
+
{layout.brandSlot ? (
|
|
69
|
+
<ShellSlot slot={layout.brandSlot}>
|
|
70
|
+
{renderSlot(layout.brandSlot)}
|
|
71
|
+
</ShellSlot>
|
|
72
|
+
) : null}
|
|
73
|
+
<div className={frame.headerNavigationClassName}>
|
|
74
|
+
{layout.primaryNavigationSlot ? (
|
|
75
|
+
<ShellSlot slot={layout.primaryNavigationSlot}>
|
|
76
|
+
{renderSlot(layout.primaryNavigationSlot)}
|
|
77
|
+
</ShellSlot>
|
|
78
|
+
) : null}
|
|
79
|
+
{layout.utilityActionSlots.map((slot) => (
|
|
80
|
+
<ShellSlot key={slot.Id} slot={slot}>
|
|
81
|
+
{renderSlot(slot)}
|
|
82
|
+
</ShellSlot>
|
|
83
|
+
))}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</header>
|
|
87
|
+
{layout.systemNoticeSlots.map((slot) => (
|
|
88
|
+
<ShellSlot key={slot.Id} slot={slot}>
|
|
89
|
+
{renderSlot(slot)}
|
|
90
|
+
</ShellSlot>
|
|
91
|
+
))}
|
|
92
|
+
<ShellSlot slot={layout.routedContentSlot}>
|
|
93
|
+
{layout.routedContentSlot ? renderSlot(layout.routedContentSlot) : children}
|
|
94
|
+
</ShellSlot>
|
|
95
|
+
</div>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function ShellSlot({
|
|
100
|
+
children,
|
|
101
|
+
}: {
|
|
102
|
+
readonly children: ReactNode
|
|
103
|
+
readonly slot: NavigationShellSlotDefinition | null
|
|
104
|
+
}) {
|
|
105
|
+
return <>{children}</>
|
|
106
|
+
}
|