@makeswift/runtime 0.0.0-a500663

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.
@@ -0,0 +1,10 @@
1
+ export type {
2
+ Descriptor as PropControllerDescriptor,
3
+ DescriptorValueType as PropControllerDescriptorValueType,
4
+ Device,
5
+ DeviceOverride,
6
+ ResponsiveValue,
7
+ ResponsiveValueType,
8
+ Length,
9
+ } from './descriptors'
10
+ export * as Props from './descriptors'
package/src/react.ts ADDED
@@ -0,0 +1,3 @@
1
+ export type { Action } from './state/actions'
2
+ export { ActionTypes, changeDocument } from './state/actions'
3
+ export { Document, Element, RuntimeProvider, ReactRuntime } from './runtimes/react'
@@ -0,0 +1,223 @@
1
+ import {
2
+ createContext,
3
+ forwardRef,
4
+ memo,
5
+ ReactNode,
6
+ Ref,
7
+ useCallback,
8
+ useContext,
9
+ useEffect,
10
+ useState,
11
+ } from 'react'
12
+ import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector'
13
+
14
+ import * as ReactPage from '../state/react-page'
15
+ import type * as ReactBuilderPreview from '../state/react-builder-preview'
16
+ import {
17
+ changeComponentHandle,
18
+ mountComponentEffect,
19
+ registerComponentEffect,
20
+ registerReactComponentEffect,
21
+ } from '../state/actions'
22
+ import type {
23
+ PropControllerDescriptor,
24
+ PropControllerDescriptorValueType,
25
+ } from '../prop-controllers'
26
+ import { ComponentIcon } from '../state/modules/components-meta'
27
+
28
+ const contextDefaultValue = ReactPage.configureStore()
29
+
30
+ export const ReactRuntime = {
31
+ registerComponent<
32
+ P extends Record<string, PropControllerDescriptor>,
33
+ C extends ReactPage.ComponentType<{ [K in keyof P]?: PropControllerDescriptorValueType<P[K]> }>
34
+ >(
35
+ component: C,
36
+ {
37
+ type,
38
+ label,
39
+ icon = 'Cube40',
40
+ hidden = false,
41
+ props,
42
+ }: { type: string; label: string; icon?: ComponentIcon; hidden?: boolean; props?: P },
43
+ ): () => void {
44
+ const unregisterComponent = contextDefaultValue.dispatch(
45
+ registerComponentEffect(type, { label, icon, hidden }, props ?? {}),
46
+ )
47
+
48
+ const unregisterReactComponent = contextDefaultValue.dispatch(
49
+ registerReactComponentEffect(type, (component as unknown) as ReactPage.ComponentType),
50
+ )
51
+
52
+ return () => {
53
+ unregisterComponent()
54
+ unregisterReactComponent()
55
+ }
56
+ },
57
+ }
58
+
59
+ const Context = createContext(contextDefaultValue)
60
+
61
+ type RuntimeProviderProps = {
62
+ defaultRootElements?: Map<string, ReactPage.Element>
63
+ children?: ReactNode
64
+ }
65
+
66
+ export function RuntimeProvider({
67
+ children,
68
+ defaultRootElements,
69
+ }: RuntimeProviderProps): JSX.Element {
70
+ const [store, setStore] = useState(() =>
71
+ ReactPage.configureStore({
72
+ preloadedState: contextDefaultValue.getState(),
73
+ rootElements: defaultRootElements,
74
+ }),
75
+ )
76
+
77
+ useEffect(() => {
78
+ // TODO(miguel): perform a more robust validation.
79
+ const isInBuilder = window.parent !== window
80
+
81
+ if (!isInBuilder) return
82
+
83
+ const initializePromise = initializeReactBuilderPreview()
84
+
85
+ return () => {
86
+ initializePromise.then(cleanUp => {
87
+ cleanUp()
88
+ })
89
+ }
90
+
91
+ async function initializeReactBuilderPreview(): Promise<() => void> {
92
+ const ReactBuilderPreview = await import('../state/react-builder-preview')
93
+
94
+ const store = await new Promise<ReactBuilderPreview.Store>(resolve => {
95
+ setStore(store => {
96
+ const nextStore = ReactBuilderPreview.configureStore({ preloadedState: store.getState() })
97
+
98
+ resolve(nextStore)
99
+
100
+ return nextStore
101
+ })
102
+ })
103
+
104
+ return store.dispatch(ReactBuilderPreview.initialize())
105
+ }
106
+ }, [])
107
+
108
+ return <Context.Provider value={store}>{children}</Context.Provider>
109
+ }
110
+
111
+ type State = ReactPage.State | ReactBuilderPreview.State
112
+
113
+ function useSelector<R>(selector: (state: State) => R): R {
114
+ const store = useContext(Context)
115
+
116
+ return useSyncExternalStoreWithSelector(store.subscribe, store.getState, store.getState, selector)
117
+ }
118
+
119
+ function useComponent(type: string): ReactPage.ComponentType | null {
120
+ return useSelector(state => ReactPage.getReactComponent(state, type))
121
+ }
122
+
123
+ function useDocumentRootElement(documentKey: string): ReactPage.Element | null {
124
+ return useSelector(state => ReactPage.getDocumentRootElement(state, documentKey))
125
+ }
126
+
127
+ type Dispatch = ReactPage.Dispatch & ReactBuilderPreview.Dispatch
128
+
129
+ function useDispatch(): Dispatch {
130
+ const store = useContext(Context)
131
+
132
+ return store.dispatch
133
+ }
134
+
135
+ type ElementDataProps = {
136
+ elementData: ReactPage.ElementData
137
+ }
138
+
139
+ const ElementData = memo(
140
+ forwardRef(function ElementData(
141
+ { elementData }: ElementDataProps,
142
+ ref: Ref<unknown>,
143
+ ): JSX.Element {
144
+ const Component = useComponent(elementData.type)
145
+
146
+ if (Component == null) {
147
+ return (
148
+ <div ref={ref as Ref<HTMLDivElement>}>
149
+ <p>Component Not Found</p>
150
+ <pre>
151
+ <code>{JSON.stringify(elementData, null, 2)}</code>
152
+ </pre>
153
+ </div>
154
+ )
155
+ }
156
+
157
+ return <Component {...elementData.props} key={elementData.key} ref={ref} />
158
+ }),
159
+ )
160
+
161
+ type ElementRefereceProps = {
162
+ elementReference: ReactPage.ElementReference
163
+ }
164
+
165
+ const ElementReference = memo(
166
+ forwardRef(function ElementReference(
167
+ { elementReference }: ElementRefereceProps,
168
+ ref: Ref<unknown>,
169
+ ): JSX.Element {
170
+ return (
171
+ <div ref={ref as Ref<HTMLDivElement>}>
172
+ <p>Not Implemented</p>
173
+ <pre>
174
+ <code>{JSON.stringify(elementReference, null, 2)}</code>
175
+ </pre>
176
+ </div>
177
+ )
178
+ }),
179
+ )
180
+
181
+ type ElementProps = {
182
+ element: ReactPage.Element
183
+ }
184
+
185
+ export const Element = memo(function Element({ element }: ElementProps): JSX.Element {
186
+ const elementKey = element.key
187
+ const dispatch = useDispatch()
188
+ const ref = useCallback(
189
+ (handle: unknown): void => {
190
+ dispatch(changeComponentHandle(elementKey, handle))
191
+ },
192
+ [dispatch, elementKey],
193
+ )
194
+
195
+ useEffect(() => dispatch(mountComponentEffect(elementKey)), [dispatch, elementKey])
196
+
197
+ return ReactPage.isElementReference(element) ? (
198
+ <ElementReference key={elementKey} ref={ref} elementReference={element} />
199
+ ) : (
200
+ <ElementData key={elementKey} ref={ref} elementData={element} />
201
+ )
202
+ })
203
+
204
+ type DocumentProps = {
205
+ documentKey: string
206
+ }
207
+
208
+ export const Document = memo(function Document({ documentKey }: DocumentProps): JSX.Element {
209
+ const documentRootElement = useDocumentRootElement(documentKey)
210
+
211
+ if (documentRootElement == null) {
212
+ return (
213
+ <div>
214
+ <p>Document Not Found</p>
215
+ <pre>
216
+ <code>{JSON.stringify({ documentKey }, null, 2)}</code>
217
+ </pre>
218
+ </div>
219
+ )
220
+ }
221
+
222
+ return <Element element={documentRootElement} />
223
+ })
@@ -0,0 +1,239 @@
1
+ import type { Operation } from 'ot-json0'
2
+
3
+ import type { ComponentType } from './modules/react-components'
4
+ import type { Measurable, BoxModel } from './modules/box-models'
5
+ import type { ThunkAction } from 'redux-thunk'
6
+ import { ComponentMeta } from './modules/components-meta'
7
+ import { PropControllerDescriptor } from '../prop-controllers'
8
+ import type { Size } from './react-builder-preview'
9
+
10
+ export const ActionTypes = {
11
+ CHANGE_DOCUMENT: 'CHANGE_DOCUMENT',
12
+
13
+ REGISTER_COMPONENT: 'REGISTER_COMPONENT',
14
+ UNREGISTER_COMPONENT: 'UNREGISTER_COMPONENT',
15
+
16
+ REGISTER_REACT_COMPONENT: 'REGISTER_REACT_COMPONENT',
17
+ UNREGISTER_REACT_COMPONENT: 'UNREGISTER_REACT_COMPONENT',
18
+
19
+ MOUNT_COMPONENT: 'MOUNT_COMPONENT',
20
+ UNMOUNT_COMPONENT: 'UNMOUNT_COMPONENT',
21
+
22
+ CHANGE_COMPONENT_HANDLE: 'CHANGE_COMPONENT_HANDLE',
23
+
24
+ REGISTER_MEASURABLE: 'REGISTER_MEASURABLE',
25
+ UNREGISTER_MEASURABLE: 'UNREGISTER_MEASURABLE',
26
+
27
+ CHANGE_ELEMENT_BOX_MODELS: 'CHANGE_ELEMENT_BOX_MODELS',
28
+
29
+ CHANGE_DOCUMENT_ELEMENT_SIZE: 'CHANGE_DOCUMENT_ELEMENT_SIZE',
30
+ CHANGE_DOCUMENT_ELEMENT_SCROLL_TOP: 'CHANGE_DOCUMENT_ELEMENT_SCROLL_TOP',
31
+ } as const
32
+
33
+ type ChangeDocumentAction = {
34
+ type: typeof ActionTypes.CHANGE_DOCUMENT
35
+ payload: { documentKey: string; operation: Operation }
36
+ }
37
+
38
+ type RegisterComponentAction = {
39
+ type: typeof ActionTypes.REGISTER_COMPONENT
40
+ payload: {
41
+ type: string
42
+ meta: ComponentMeta
43
+ propControllerDescriptors: Record<string, PropControllerDescriptor>
44
+ }
45
+ }
46
+
47
+ type UnregisterComponentAction = {
48
+ type: typeof ActionTypes.UNREGISTER_COMPONENT
49
+ payload: { type: string }
50
+ }
51
+
52
+ type RegisterReactComponentAction = {
53
+ type: typeof ActionTypes.REGISTER_REACT_COMPONENT
54
+ payload: { type: string; component: ComponentType }
55
+ }
56
+
57
+ type UnregisterReactComponentAction = {
58
+ type: typeof ActionTypes.UNREGISTER_REACT_COMPONENT
59
+ payload: { type: string }
60
+ }
61
+
62
+ type MountComponentAction = {
63
+ type: typeof ActionTypes.MOUNT_COMPONENT
64
+ payload: { elementKey: string }
65
+ }
66
+
67
+ type UnmountComponentAction = {
68
+ type: typeof ActionTypes.UNMOUNT_COMPONENT
69
+ payload: { elementKey: string }
70
+ }
71
+
72
+ type ChangeComponentHandleAction = {
73
+ type: typeof ActionTypes.CHANGE_COMPONENT_HANDLE
74
+ payload: { elementKey: string; componentHandle: unknown }
75
+ }
76
+
77
+ type RegisterMeasurableAction = {
78
+ type: typeof ActionTypes.REGISTER_MEASURABLE
79
+ payload: { elementKey: string; measurable: Measurable }
80
+ }
81
+
82
+ type UnregisterMeasurableAction = {
83
+ type: typeof ActionTypes.UNREGISTER_MEASURABLE
84
+ payload: { elementKey: string }
85
+ }
86
+
87
+ type ChangeElementBoxModelsAction = {
88
+ type: typeof ActionTypes.CHANGE_ELEMENT_BOX_MODELS
89
+ payload: { changedElementBoxModels: Map<string, BoxModel | null> }
90
+ }
91
+
92
+ type ChangeDocumentElementSizeAction = {
93
+ type: typeof ActionTypes.CHANGE_DOCUMENT_ELEMENT_SIZE
94
+ payload: { size: Size }
95
+ }
96
+
97
+ type ChangeDocumentElementScrollTopAction = {
98
+ type: typeof ActionTypes.CHANGE_DOCUMENT_ELEMENT_SCROLL_TOP
99
+ payload: { scrollTop: number }
100
+ }
101
+
102
+ export type Action =
103
+ | ChangeDocumentAction
104
+ | RegisterComponentAction
105
+ | UnregisterComponentAction
106
+ | RegisterReactComponentAction
107
+ | UnregisterReactComponentAction
108
+ | MountComponentAction
109
+ | UnmountComponentAction
110
+ | ChangeComponentHandleAction
111
+ | RegisterMeasurableAction
112
+ | UnregisterMeasurableAction
113
+ | ChangeElementBoxModelsAction
114
+ | ChangeDocumentElementSizeAction
115
+ | ChangeDocumentElementScrollTopAction
116
+
117
+ export function changeDocument(documentKey: string, operation: Operation): ChangeDocumentAction {
118
+ return { type: ActionTypes.CHANGE_DOCUMENT, payload: { documentKey, operation } }
119
+ }
120
+
121
+ export function registerComponent(
122
+ type: string,
123
+ meta: ComponentMeta,
124
+ propControllerDescriptors: Record<string, PropControllerDescriptor>,
125
+ ): RegisterComponentAction {
126
+ return {
127
+ type: ActionTypes.REGISTER_COMPONENT,
128
+ payload: { type, meta, propControllerDescriptors },
129
+ }
130
+ }
131
+
132
+ export function unregisterComponent(type: string): UnregisterComponentAction {
133
+ return { type: ActionTypes.UNREGISTER_COMPONENT, payload: { type } }
134
+ }
135
+
136
+ export function registerComponentEffect(
137
+ type: string,
138
+ meta: ComponentMeta,
139
+ propControllerDescriptors: Record<string, PropControllerDescriptor>,
140
+ ): ThunkAction<() => void, unknown, unknown, Action> {
141
+ return dispatch => {
142
+ dispatch(registerComponent(type, meta, propControllerDescriptors))
143
+
144
+ return () => {
145
+ dispatch(unregisterComponent(type))
146
+ }
147
+ }
148
+ }
149
+
150
+ function registerReactComponent(
151
+ type: string,
152
+ component: ComponentType,
153
+ ): RegisterReactComponentAction {
154
+ return { type: ActionTypes.REGISTER_REACT_COMPONENT, payload: { type, component } }
155
+ }
156
+
157
+ function unregisterReactComponent(type: string): UnregisterReactComponentAction {
158
+ return { type: ActionTypes.UNREGISTER_REACT_COMPONENT, payload: { type } }
159
+ }
160
+
161
+ export function registerReactComponentEffect(
162
+ type: string,
163
+ component: ComponentType,
164
+ ): ThunkAction<() => void, unknown, unknown, Action> {
165
+ return dispatch => {
166
+ dispatch(registerReactComponent(type, component))
167
+
168
+ return () => {
169
+ dispatch(unregisterReactComponent(type))
170
+ }
171
+ }
172
+ }
173
+
174
+ export function mountComponent(elementKey: string): MountComponentAction {
175
+ return { type: ActionTypes.MOUNT_COMPONENT, payload: { elementKey } }
176
+ }
177
+
178
+ export function unmountComponent(elementKey: string): UnmountComponentAction {
179
+ return { type: ActionTypes.UNMOUNT_COMPONENT, payload: { elementKey } }
180
+ }
181
+
182
+ export function mountComponentEffect(
183
+ elementKey: string,
184
+ ): ThunkAction<() => void, unknown, unknown, Action> {
185
+ return dispatch => {
186
+ dispatch(mountComponent(elementKey))
187
+
188
+ return () => {
189
+ dispatch(unmountComponent(elementKey))
190
+ }
191
+ }
192
+ }
193
+
194
+ export function changeComponentHandle(
195
+ elementKey: string,
196
+ componentHandle: unknown,
197
+ ): ChangeComponentHandleAction {
198
+ return { type: ActionTypes.CHANGE_COMPONENT_HANDLE, payload: { elementKey, componentHandle } }
199
+ }
200
+
201
+ export function registerMeasurable(
202
+ elementKey: string,
203
+ measurable: Measurable,
204
+ ): RegisterMeasurableAction {
205
+ return { type: ActionTypes.REGISTER_MEASURABLE, payload: { elementKey, measurable } }
206
+ }
207
+
208
+ export function unregisterMeasurable(elementKey: string): UnregisterMeasurableAction {
209
+ return { type: ActionTypes.UNREGISTER_MEASURABLE, payload: { elementKey } }
210
+ }
211
+
212
+ export function registerMeasurableEffect(
213
+ elementKey: string,
214
+ measurable: Measurable,
215
+ ): ThunkAction<() => void, unknown, unknown, Action> {
216
+ return dispatch => {
217
+ dispatch(registerMeasurable(elementKey, measurable))
218
+
219
+ return () => {
220
+ dispatch(unregisterMeasurable(elementKey))
221
+ }
222
+ }
223
+ }
224
+
225
+ export function changeElementBoxModels(
226
+ changedElementBoxModels: Map<string, BoxModel | null>,
227
+ ): ChangeElementBoxModelsAction {
228
+ return { type: ActionTypes.CHANGE_ELEMENT_BOX_MODELS, payload: { changedElementBoxModels } }
229
+ }
230
+
231
+ export function changeDocumentElementSize(size: Size): ChangeDocumentElementSizeAction {
232
+ return { type: ActionTypes.CHANGE_DOCUMENT_ELEMENT_SIZE, payload: { size } }
233
+ }
234
+
235
+ export function changeDocumentElementScrollTop(
236
+ scrollTop: number,
237
+ ): ChangeDocumentElementScrollTopAction {
238
+ return { type: ActionTypes.CHANGE_DOCUMENT_ELEMENT_SCROLL_TOP, payload: { scrollTop } }
239
+ }
@@ -0,0 +1,112 @@
1
+ import {
2
+ BoxModel,
3
+ createBox as createBoxWithoutScroll,
4
+ CreateBoxArgs,
5
+ getBox as getBoxWithoutScroll,
6
+ withScroll,
7
+ } from 'css-box-model'
8
+
9
+ import { Action, ActionTypes } from '../actions'
10
+
11
+ export type { BoxModel }
12
+
13
+ export function parse(rawString: string): number {
14
+ const value = Number(rawString.replace(/px$/, ''))
15
+
16
+ return Number.isFinite(value) ? value : 0
17
+ }
18
+
19
+ export function createBox(boxArgs: CreateBoxArgs): BoxModel {
20
+ return withScroll(createBoxWithoutScroll(boxArgs))
21
+ }
22
+
23
+ export function getBox(element: Element): BoxModel {
24
+ return withScroll(getBoxWithoutScroll(element))
25
+ }
26
+
27
+ export interface BoxModelHandle {
28
+ getBoxModel(): BoxModel | null
29
+ }
30
+
31
+ export type Measurable = Element | BoxModelHandle
32
+
33
+ export function isMeasurable(value: unknown): value is Measurable {
34
+ if (value instanceof Element) return true
35
+
36
+ if (
37
+ typeof value === 'object' &&
38
+ value !== null &&
39
+ 'getBoxModel' in value &&
40
+ typeof (value as { getBoxModel: unknown }).getBoxModel === 'function'
41
+ ) {
42
+ return true
43
+ }
44
+
45
+ return false
46
+ }
47
+
48
+ export function measure(measurable: Measurable): BoxModel | null {
49
+ if (measurable instanceof Element) return getBox(measurable)
50
+
51
+ return measurable.getBoxModel()
52
+ }
53
+
54
+ export type State = {
55
+ measurables: Map<string, Measurable>
56
+ boxModels: Map<string, BoxModel>
57
+ }
58
+
59
+ export function getInitialState(): State {
60
+ return { measurables: new Map(), boxModels: new Map() }
61
+ }
62
+
63
+ export function getMeasurables(state: State): Map<string, Measurable> {
64
+ return state.measurables
65
+ }
66
+
67
+ export function getBoxModels(state: State): Map<string, BoxModel> {
68
+ return state.boxModels
69
+ }
70
+
71
+ export function getBoxModel(state: State, elementKey: string): BoxModel | null {
72
+ return getBoxModels(state).get(elementKey) ?? null
73
+ }
74
+
75
+ export function reducer(state: State = getInitialState(), action: Action) {
76
+ switch (action.type) {
77
+ case ActionTypes.REGISTER_MEASURABLE:
78
+ return {
79
+ ...state,
80
+ measurables: new Map(getMeasurables(state)).set(
81
+ action.payload.elementKey,
82
+ action.payload.measurable,
83
+ ),
84
+ }
85
+
86
+ case ActionTypes.UNREGISTER_MEASURABLE: {
87
+ const nextMeasurables = new Map(getMeasurables(state))
88
+
89
+ const deleted = nextMeasurables.delete(action.payload.elementKey)
90
+
91
+ return deleted ? { ...state, measurables: nextMeasurables } : state
92
+ }
93
+
94
+ case ActionTypes.CHANGE_ELEMENT_BOX_MODELS: {
95
+ const { changedElementBoxModels } = action.payload
96
+
97
+ if (changedElementBoxModels.size === 0) return state
98
+
99
+ const nextBoxModels = new Map(getBoxModels(state))
100
+
101
+ changedElementBoxModels.forEach((boxModel, elementKey) => {
102
+ if (boxModel == null) nextBoxModels.delete(elementKey)
103
+ else nextBoxModels.set(elementKey, boxModel)
104
+ })
105
+
106
+ return { ...state, boxModels: nextBoxModels }
107
+ }
108
+
109
+ default:
110
+ return state
111
+ }
112
+ }
@@ -0,0 +1,44 @@
1
+ import { Action, ActionTypes } from '../actions'
2
+
3
+ export type ComponentIcon =
4
+ | 'Carousel40'
5
+ | 'Code40'
6
+ | 'Countdown40'
7
+ | 'Cube40'
8
+ | 'Divider40'
9
+ | 'Form40'
10
+ | 'Navigation40'
11
+ | 'SocialLinks40'
12
+ | 'Video40'
13
+
14
+ export type ComponentMeta = { label: string; icon: ComponentIcon; hidden: boolean }
15
+
16
+ export type State = Map<string, ComponentMeta>
17
+
18
+ export function getInitialState({
19
+ componentsMeta = new Map(),
20
+ }: { componentsMeta?: Map<string, ComponentMeta> } = {}): State {
21
+ return componentsMeta
22
+ }
23
+
24
+ export function getComponentsMeta(state: State): Map<string, ComponentMeta> {
25
+ return state
26
+ }
27
+
28
+ export function reducer(state: State = getInitialState(), action: Action): State {
29
+ switch (action.type) {
30
+ case ActionTypes.REGISTER_COMPONENT:
31
+ return new Map(state).set(action.payload.type, action.payload.meta)
32
+
33
+ case ActionTypes.UNREGISTER_COMPONENT: {
34
+ const nextState = new Map(state)
35
+
36
+ const deleted = nextState.delete(action.payload.type)
37
+
38
+ return deleted ? nextState : state
39
+ }
40
+
41
+ default:
42
+ return state
43
+ }
44
+ }
@@ -0,0 +1,45 @@
1
+ import { Action, ActionTypes } from '../actions'
2
+ import { PropControllerDescriptor } from '../../prop-controllers'
3
+
4
+ export type { PropControllerDescriptor }
5
+
6
+ export type State = Map<string, Record<string, PropControllerDescriptor>>
7
+
8
+ export function getInitialState({
9
+ propControllerDescriptors = new Map(),
10
+ }: {
11
+ propControllerDescriptors?: Map<string, Record<string, PropControllerDescriptor>>
12
+ } = {}): State {
13
+ return propControllerDescriptors
14
+ }
15
+
16
+ function getPropControllerDescriptors(
17
+ state: State,
18
+ ): Map<string, Record<string, PropControllerDescriptor>> {
19
+ return state
20
+ }
21
+
22
+ export function getComponentPropControllerDescriptors(
23
+ state: State,
24
+ componentType: string,
25
+ ): Record<string, PropControllerDescriptor> | null {
26
+ return getPropControllerDescriptors(state).get(componentType) ?? null
27
+ }
28
+
29
+ export function reducer(state: State = getInitialState(), action: Action): State {
30
+ switch (action.type) {
31
+ case ActionTypes.REGISTER_COMPONENT:
32
+ return new Map(state).set(action.payload.type, action.payload.propControllerDescriptors)
33
+
34
+ case ActionTypes.UNREGISTER_COMPONENT: {
35
+ const nextState = new Map(state)
36
+
37
+ const deleted = nextState.delete(action.payload.type)
38
+
39
+ return deleted ? nextState : state
40
+ }
41
+
42
+ default:
43
+ return state
44
+ }
45
+ }