@react-typed-forms/schemas 8.2.0 → 9.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.
- package/lib/controlBuilder.d.ts +9 -2
- package/lib/controlRender.d.ts +12 -11
- package/lib/hooks.d.ts +8 -8
- package/lib/index.js +323 -215
- package/lib/index.js.map +1 -1
- package/lib/renderers.d.ts +1 -0
- package/lib/schemaBuilder.d.ts +5 -2
- package/lib/types.d.ts +9 -1
- package/lib/util.d.ts +12 -0
- package/package.json +2 -2
- package/.babelrc +0 -4
- package/.rush/temp/operation/build/state.json +0 -3
- package/.rush/temp/operation/update-readme/state.json +0 -3
- package/.rush/temp/package-deps_build.json +0 -13
- package/.rush/temp/shrinkwrap-deps.json +0 -612
- package/src/controlBuilder.ts +0 -175
- package/src/controlRender.tsx +0 -790
- package/src/hooks.tsx +0 -373
- package/src/index.ts +0 -10
- package/src/internal.ts +0 -48
- package/src/renderers.tsx +0 -996
- package/src/schemaBuilder.ts +0 -171
- package/src/schemaInterface.ts +0 -31
- package/src/tailwind.tsx +0 -29
- package/src/types.ts +0 -423
- package/src/util.ts +0 -453
- package/src/validators.ts +0 -116
package/src/controlRender.tsx
DELETED
|
@@ -1,790 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
CSSProperties,
|
|
3
|
-
FC,
|
|
4
|
-
Fragment,
|
|
5
|
-
Key,
|
|
6
|
-
ReactNode,
|
|
7
|
-
useCallback,
|
|
8
|
-
useEffect,
|
|
9
|
-
} from "react";
|
|
10
|
-
import {
|
|
11
|
-
addElement,
|
|
12
|
-
Control,
|
|
13
|
-
ControlChange,
|
|
14
|
-
newControl,
|
|
15
|
-
removeElement,
|
|
16
|
-
trackControlChange,
|
|
17
|
-
useComponentTracking,
|
|
18
|
-
useControl,
|
|
19
|
-
useControlEffect,
|
|
20
|
-
} from "@react-typed-forms/core";
|
|
21
|
-
import {
|
|
22
|
-
AdornmentPlacement,
|
|
23
|
-
ControlAdornment,
|
|
24
|
-
ControlDefinition,
|
|
25
|
-
DataControlDefinition,
|
|
26
|
-
DisplayData,
|
|
27
|
-
DynamicPropertyType,
|
|
28
|
-
FieldOption,
|
|
29
|
-
GroupedControlsDefinition,
|
|
30
|
-
GroupRenderOptions,
|
|
31
|
-
isActionControlsDefinition,
|
|
32
|
-
isDataControlDefinition,
|
|
33
|
-
isDisplayControlsDefinition,
|
|
34
|
-
isGroupControlsDefinition,
|
|
35
|
-
RenderOptions,
|
|
36
|
-
SchemaField,
|
|
37
|
-
SchemaInterface,
|
|
38
|
-
} from "./types";
|
|
39
|
-
import {
|
|
40
|
-
ControlDataContext,
|
|
41
|
-
elementValueForField,
|
|
42
|
-
fieldDisplayName,
|
|
43
|
-
findChildDefinition,
|
|
44
|
-
findField,
|
|
45
|
-
isCompoundField,
|
|
46
|
-
useUpdatedRef,
|
|
47
|
-
} from "./util";
|
|
48
|
-
import { dataControl } from "./controlBuilder";
|
|
49
|
-
import {
|
|
50
|
-
defaultUseEvalExpressionHook,
|
|
51
|
-
useEvalAllowedOptionsHook,
|
|
52
|
-
useEvalDefaultValueHook,
|
|
53
|
-
useEvalDisabledHook,
|
|
54
|
-
useEvalDisplayHook,
|
|
55
|
-
UseEvalExpressionHook,
|
|
56
|
-
useEvalLabelText,
|
|
57
|
-
useEvalReadonlyHook,
|
|
58
|
-
useEvalStyleHook,
|
|
59
|
-
useEvalVisibilityHook,
|
|
60
|
-
} from "./hooks";
|
|
61
|
-
import { useValidationHook } from "./validators";
|
|
62
|
-
import { cc, useCalculatedControl } from "./internal";
|
|
63
|
-
import { defaultSchemaInterface } from "./schemaInterface";
|
|
64
|
-
|
|
65
|
-
export interface FormRenderer {
|
|
66
|
-
renderData: (
|
|
67
|
-
props: DataRendererProps,
|
|
68
|
-
) => (layout: ControlLayoutProps) => ControlLayoutProps;
|
|
69
|
-
renderGroup: (
|
|
70
|
-
props: GroupRendererProps,
|
|
71
|
-
) => (layout: ControlLayoutProps) => ControlLayoutProps;
|
|
72
|
-
renderDisplay: (props: DisplayRendererProps) => ReactNode;
|
|
73
|
-
renderAction: (props: ActionRendererProps) => ReactNode;
|
|
74
|
-
renderArray: (props: ArrayRendererProps) => ReactNode;
|
|
75
|
-
renderAdornment: (props: AdornmentProps) => AdornmentRenderer;
|
|
76
|
-
renderLabel: (
|
|
77
|
-
props: LabelRendererProps,
|
|
78
|
-
labelStart: ReactNode,
|
|
79
|
-
labelEnd: ReactNode,
|
|
80
|
-
) => ReactNode;
|
|
81
|
-
renderLayout: (props: ControlLayoutProps) => RenderedControl;
|
|
82
|
-
renderVisibility: (props: VisibilityRendererProps) => ReactNode;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface AdornmentProps {
|
|
86
|
-
adornment: ControlAdornment;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export const AppendAdornmentPriority = 0;
|
|
90
|
-
export const WrapAdornmentPriority = 1000;
|
|
91
|
-
|
|
92
|
-
export interface AdornmentRenderer {
|
|
93
|
-
apply(children: RenderedLayout): void;
|
|
94
|
-
adornment?: ControlAdornment;
|
|
95
|
-
priority: number;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export interface ArrayRendererProps {
|
|
99
|
-
addAction?: ActionRendererProps;
|
|
100
|
-
required: boolean;
|
|
101
|
-
removeAction?: (elemIndex: number) => ActionRendererProps;
|
|
102
|
-
elementCount: number;
|
|
103
|
-
renderElement: (elemIndex: number) => ReactNode;
|
|
104
|
-
elementKey: (elemIndex: number) => Key;
|
|
105
|
-
arrayControl: Control<any[] | undefined | null>;
|
|
106
|
-
className?: string;
|
|
107
|
-
style?: React.CSSProperties;
|
|
108
|
-
}
|
|
109
|
-
export interface Visibility {
|
|
110
|
-
visible: boolean;
|
|
111
|
-
showing: boolean;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export interface RenderedLayout {
|
|
115
|
-
labelStart?: ReactNode;
|
|
116
|
-
labelEnd?: ReactNode;
|
|
117
|
-
controlStart?: ReactNode;
|
|
118
|
-
controlEnd?: ReactNode;
|
|
119
|
-
label?: ReactNode;
|
|
120
|
-
children?: ReactNode;
|
|
121
|
-
errorControl?: Control<any>;
|
|
122
|
-
className?: string;
|
|
123
|
-
style?: React.CSSProperties;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export interface RenderedControl {
|
|
127
|
-
children: ReactNode;
|
|
128
|
-
className?: string;
|
|
129
|
-
style?: React.CSSProperties;
|
|
130
|
-
divRef?: (cb: HTMLElement | null) => void;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export interface VisibilityRendererProps extends RenderedControl {
|
|
134
|
-
visibility: Control<Visibility | undefined>;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export interface ControlLayoutProps {
|
|
138
|
-
label?: LabelRendererProps;
|
|
139
|
-
errorControl?: Control<any>;
|
|
140
|
-
adornments?: AdornmentRenderer[];
|
|
141
|
-
children?: ReactNode;
|
|
142
|
-
processLayout?: (props: ControlLayoutProps) => ControlLayoutProps;
|
|
143
|
-
className?: string | null;
|
|
144
|
-
style?: React.CSSProperties;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export enum LabelType {
|
|
148
|
-
Control,
|
|
149
|
-
Group,
|
|
150
|
-
}
|
|
151
|
-
export interface LabelRendererProps {
|
|
152
|
-
type: LabelType;
|
|
153
|
-
hide?: boolean | null;
|
|
154
|
-
label: ReactNode;
|
|
155
|
-
required?: boolean | null;
|
|
156
|
-
forId?: string;
|
|
157
|
-
className?: string;
|
|
158
|
-
}
|
|
159
|
-
export interface DisplayRendererProps {
|
|
160
|
-
data: DisplayData;
|
|
161
|
-
display?: Control<string | undefined>;
|
|
162
|
-
className?: string;
|
|
163
|
-
style?: React.CSSProperties;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export interface GroupRendererProps {
|
|
167
|
-
children: ControlDefinition[];
|
|
168
|
-
renderOptions: GroupRenderOptions;
|
|
169
|
-
renderChild: ChildRenderer;
|
|
170
|
-
className?: string;
|
|
171
|
-
style?: React.CSSProperties;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export interface DataRendererProps {
|
|
175
|
-
renderOptions: RenderOptions;
|
|
176
|
-
field: SchemaField;
|
|
177
|
-
id: string;
|
|
178
|
-
control: Control<any>;
|
|
179
|
-
readonly: boolean;
|
|
180
|
-
required: boolean;
|
|
181
|
-
options: FieldOption[] | undefined | null;
|
|
182
|
-
hidden: boolean;
|
|
183
|
-
className?: string;
|
|
184
|
-
style?: React.CSSProperties;
|
|
185
|
-
dataContext: ControlDataContext;
|
|
186
|
-
children: ControlDefinition[];
|
|
187
|
-
renderChild: ChildRenderer;
|
|
188
|
-
toArrayProps?: () => ArrayRendererProps;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export interface ActionRendererProps {
|
|
192
|
-
actionId: string;
|
|
193
|
-
actionText: string;
|
|
194
|
-
onClick: () => void;
|
|
195
|
-
className?: string;
|
|
196
|
-
style?: React.CSSProperties;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export interface ControlRenderProps {
|
|
200
|
-
control: Control<any>;
|
|
201
|
-
parentPath?: JsonPath[];
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
export interface FormContextOptions {
|
|
205
|
-
readonly?: boolean | null;
|
|
206
|
-
hidden?: boolean | null;
|
|
207
|
-
disabled?: boolean | null;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export interface DataControlProps {
|
|
211
|
-
definition: DataControlDefinition;
|
|
212
|
-
field: SchemaField;
|
|
213
|
-
dataContext: ControlDataContext;
|
|
214
|
-
control: Control<any>;
|
|
215
|
-
options: FormContextOptions;
|
|
216
|
-
style: React.CSSProperties | undefined;
|
|
217
|
-
renderChild: ChildRenderer;
|
|
218
|
-
allowedOptions?: Control<any[] | undefined>;
|
|
219
|
-
elementRenderer?: (elemIndex: number) => ReactNode;
|
|
220
|
-
}
|
|
221
|
-
export type CreateDataProps = (
|
|
222
|
-
controlProps: DataControlProps,
|
|
223
|
-
) => DataRendererProps;
|
|
224
|
-
|
|
225
|
-
export type JsonPath = string | number;
|
|
226
|
-
|
|
227
|
-
export interface DataContext {
|
|
228
|
-
data: Control<any>;
|
|
229
|
-
path: JsonPath[];
|
|
230
|
-
}
|
|
231
|
-
export interface ControlRenderOptions extends FormContextOptions {
|
|
232
|
-
useDataHook?: (c: ControlDefinition) => CreateDataProps;
|
|
233
|
-
useEvalExpressionHook?: UseEvalExpressionHook;
|
|
234
|
-
clearHidden?: boolean;
|
|
235
|
-
schemaInterface?: SchemaInterface;
|
|
236
|
-
}
|
|
237
|
-
export function useControlRenderer(
|
|
238
|
-
definition: ControlDefinition,
|
|
239
|
-
fields: SchemaField[],
|
|
240
|
-
renderer: FormRenderer,
|
|
241
|
-
options: ControlRenderOptions = {},
|
|
242
|
-
): FC<ControlRenderProps> {
|
|
243
|
-
const dataProps = options.useDataHook?.(definition) ?? defaultDataProps;
|
|
244
|
-
const schemaInterface = options.schemaInterface ?? defaultSchemaInterface;
|
|
245
|
-
const useExpr = options.useEvalExpressionHook ?? defaultUseEvalExpressionHook;
|
|
246
|
-
|
|
247
|
-
const schemaField = lookupSchemaField(definition, fields);
|
|
248
|
-
const useDefaultValue = useEvalDefaultValueHook(
|
|
249
|
-
useExpr,
|
|
250
|
-
definition,
|
|
251
|
-
schemaField,
|
|
252
|
-
);
|
|
253
|
-
const useIsVisible = useEvalVisibilityHook(useExpr, definition, schemaField);
|
|
254
|
-
const useIsReadonly = useEvalReadonlyHook(useExpr, definition);
|
|
255
|
-
const useIsDisabled = useEvalDisabledHook(useExpr, definition);
|
|
256
|
-
const useAllowedOptions = useEvalAllowedOptionsHook(useExpr, definition);
|
|
257
|
-
const useLabelText = useEvalLabelText(useExpr, definition);
|
|
258
|
-
const useCustomStyle = useEvalStyleHook(
|
|
259
|
-
useExpr,
|
|
260
|
-
DynamicPropertyType.Style,
|
|
261
|
-
definition,
|
|
262
|
-
);
|
|
263
|
-
const useLayoutStyle = useEvalStyleHook(
|
|
264
|
-
useExpr,
|
|
265
|
-
DynamicPropertyType.LayoutStyle,
|
|
266
|
-
definition,
|
|
267
|
-
);
|
|
268
|
-
const useDynamicDisplay = useEvalDisplayHook(useExpr, definition);
|
|
269
|
-
const useValidation = useValidationHook(definition);
|
|
270
|
-
const r = useUpdatedRef({ options, definition, fields, schemaField });
|
|
271
|
-
|
|
272
|
-
const Component = useCallback(
|
|
273
|
-
({ control: rootControl, parentPath = [] }: ControlRenderProps) => {
|
|
274
|
-
const stopTracking = useComponentTracking();
|
|
275
|
-
try {
|
|
276
|
-
const { definition: c, options, fields, schemaField } = r.current;
|
|
277
|
-
const parentDataContext: ControlDataContext = {
|
|
278
|
-
fields,
|
|
279
|
-
schemaInterface,
|
|
280
|
-
data: rootControl,
|
|
281
|
-
path: parentPath,
|
|
282
|
-
};
|
|
283
|
-
const readonlyControl = useIsReadonly(parentDataContext);
|
|
284
|
-
const disabledControl = useIsDisabled(parentDataContext);
|
|
285
|
-
const visibleControl = useIsVisible(parentDataContext);
|
|
286
|
-
const displayControl = useDynamicDisplay(parentDataContext);
|
|
287
|
-
const customStyle = useCustomStyle(parentDataContext).value;
|
|
288
|
-
const layoutStyle = useLayoutStyle(parentDataContext).value;
|
|
289
|
-
const labelText = useLabelText(parentDataContext);
|
|
290
|
-
const visible = visibleControl.current.value;
|
|
291
|
-
const visibility = useControl<Visibility | undefined>(() =>
|
|
292
|
-
visible != null
|
|
293
|
-
? {
|
|
294
|
-
visible,
|
|
295
|
-
showing: visible,
|
|
296
|
-
}
|
|
297
|
-
: undefined,
|
|
298
|
-
);
|
|
299
|
-
useControlEffect(
|
|
300
|
-
() => visibleControl.value,
|
|
301
|
-
(visible) => {
|
|
302
|
-
if (visible != null)
|
|
303
|
-
visibility.setValue((ex) => ({
|
|
304
|
-
visible,
|
|
305
|
-
showing: ex ? ex.showing : visible,
|
|
306
|
-
}));
|
|
307
|
-
},
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
const allowedOptions = useAllowedOptions(parentDataContext);
|
|
311
|
-
const defaultValueControl = useDefaultValue(parentDataContext);
|
|
312
|
-
const [parentControl, control, controlDataContext] = getControlData(
|
|
313
|
-
schemaField,
|
|
314
|
-
parentDataContext,
|
|
315
|
-
);
|
|
316
|
-
useControlEffect(
|
|
317
|
-
() => [
|
|
318
|
-
visibility.value,
|
|
319
|
-
defaultValueControl.value,
|
|
320
|
-
control,
|
|
321
|
-
isDataControlDefinition(definition) && definition.dontClearHidden,
|
|
322
|
-
parentControl?.isNull,
|
|
323
|
-
],
|
|
324
|
-
([vc, dv, cd, dontClear, parentNull]) => {
|
|
325
|
-
if (vc && cd && vc.visible === vc.showing) {
|
|
326
|
-
if (!vc.visible) {
|
|
327
|
-
if (options.clearHidden && !dontClear) {
|
|
328
|
-
cd.value = undefined;
|
|
329
|
-
}
|
|
330
|
-
} else if (cd.value == null) {
|
|
331
|
-
cd.value = dv;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
if (parentNull && parentControl?.isNull) {
|
|
335
|
-
parentControl.value = {};
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
true,
|
|
339
|
-
);
|
|
340
|
-
const myOptions = useCalculatedControl<FormContextOptions>(() => ({
|
|
341
|
-
hidden: options.hidden || !visibility.fields?.showing.value,
|
|
342
|
-
readonly: options.readonly || readonlyControl.value,
|
|
343
|
-
disabled: options.disabled || disabledControl.value,
|
|
344
|
-
})).value;
|
|
345
|
-
useValidation(
|
|
346
|
-
control ?? newControl(null),
|
|
347
|
-
!!myOptions.hidden,
|
|
348
|
-
parentDataContext,
|
|
349
|
-
);
|
|
350
|
-
const childOptions: ControlRenderOptions = { ...options, ...myOptions };
|
|
351
|
-
|
|
352
|
-
useEffect(() => {
|
|
353
|
-
if (control && typeof myOptions.disabled === "boolean")
|
|
354
|
-
control.disabled = myOptions.disabled;
|
|
355
|
-
}, [control, myOptions.disabled]);
|
|
356
|
-
if (parentControl?.isNull) return <></>;
|
|
357
|
-
|
|
358
|
-
const adornments =
|
|
359
|
-
definition.adornments?.map((x) =>
|
|
360
|
-
renderer.renderAdornment({ adornment: x }),
|
|
361
|
-
) ?? [];
|
|
362
|
-
const labelAndChildren = renderControlLayout({
|
|
363
|
-
definition: c,
|
|
364
|
-
renderer,
|
|
365
|
-
renderChild: (k, child, path) => (
|
|
366
|
-
<ControlRenderer
|
|
367
|
-
key={k}
|
|
368
|
-
control={controlDataContext.data}
|
|
369
|
-
fields={controlDataContext.fields}
|
|
370
|
-
definition={findChildDefinition(c, child)}
|
|
371
|
-
parentPath={
|
|
372
|
-
path
|
|
373
|
-
? [...controlDataContext.path, ...path]
|
|
374
|
-
: controlDataContext.path
|
|
375
|
-
}
|
|
376
|
-
renderer={renderer}
|
|
377
|
-
options={childOptions}
|
|
378
|
-
/>
|
|
379
|
-
),
|
|
380
|
-
createDataProps: dataProps,
|
|
381
|
-
formOptions: myOptions,
|
|
382
|
-
dataContext: controlDataContext,
|
|
383
|
-
control: displayControl ?? control,
|
|
384
|
-
labelText,
|
|
385
|
-
schemaField,
|
|
386
|
-
displayControl,
|
|
387
|
-
style: customStyle,
|
|
388
|
-
allowedOptions,
|
|
389
|
-
});
|
|
390
|
-
const renderedControl = renderer.renderLayout({
|
|
391
|
-
...labelAndChildren,
|
|
392
|
-
adornments,
|
|
393
|
-
className: c.layoutClass,
|
|
394
|
-
style: layoutStyle,
|
|
395
|
-
});
|
|
396
|
-
return renderer.renderVisibility({ visibility, ...renderedControl });
|
|
397
|
-
} finally {
|
|
398
|
-
stopTracking();
|
|
399
|
-
}
|
|
400
|
-
},
|
|
401
|
-
[
|
|
402
|
-
r,
|
|
403
|
-
dataProps,
|
|
404
|
-
useIsVisible,
|
|
405
|
-
useDefaultValue,
|
|
406
|
-
useIsReadonly,
|
|
407
|
-
useIsDisabled,
|
|
408
|
-
useCustomStyle,
|
|
409
|
-
useLayoutStyle,
|
|
410
|
-
useAllowedOptions,
|
|
411
|
-
useLabelText,
|
|
412
|
-
useDynamicDisplay,
|
|
413
|
-
useValidation,
|
|
414
|
-
renderer,
|
|
415
|
-
schemaInterface,
|
|
416
|
-
],
|
|
417
|
-
);
|
|
418
|
-
(Component as any).displayName = "RenderControl";
|
|
419
|
-
return Component;
|
|
420
|
-
}
|
|
421
|
-
export function lookupSchemaField(
|
|
422
|
-
c: ControlDefinition,
|
|
423
|
-
fields: SchemaField[],
|
|
424
|
-
): SchemaField | undefined {
|
|
425
|
-
const fieldName = isGroupControlsDefinition(c)
|
|
426
|
-
? c.compoundField
|
|
427
|
-
: isDataControlDefinition(c)
|
|
428
|
-
? c.field
|
|
429
|
-
: undefined;
|
|
430
|
-
return fieldName ? findField(fields, fieldName) : undefined;
|
|
431
|
-
}
|
|
432
|
-
export function getControlData(
|
|
433
|
-
schemaField: SchemaField | undefined,
|
|
434
|
-
parentContext: ControlDataContext,
|
|
435
|
-
): [Control<any> | undefined, Control<any> | undefined, ControlDataContext] {
|
|
436
|
-
const { data, path } = parentContext;
|
|
437
|
-
const parentControl = data.lookupControl(path);
|
|
438
|
-
const childPath = schemaField ? [...path, schemaField.field] : path;
|
|
439
|
-
const childControl =
|
|
440
|
-
schemaField && parentControl
|
|
441
|
-
? parentControl.fields?.[schemaField.field]
|
|
442
|
-
: undefined;
|
|
443
|
-
return [
|
|
444
|
-
parentControl,
|
|
445
|
-
childControl,
|
|
446
|
-
schemaField
|
|
447
|
-
? {
|
|
448
|
-
...parentContext,
|
|
449
|
-
path: childPath,
|
|
450
|
-
fields: isCompoundField(schemaField)
|
|
451
|
-
? schemaField.children
|
|
452
|
-
: parentContext.fields,
|
|
453
|
-
}
|
|
454
|
-
: parentContext,
|
|
455
|
-
];
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
export function ControlRenderer({
|
|
459
|
-
definition,
|
|
460
|
-
fields,
|
|
461
|
-
renderer,
|
|
462
|
-
options,
|
|
463
|
-
control,
|
|
464
|
-
parentPath,
|
|
465
|
-
}: {
|
|
466
|
-
definition: ControlDefinition;
|
|
467
|
-
fields: SchemaField[];
|
|
468
|
-
renderer: FormRenderer;
|
|
469
|
-
options?: ControlRenderOptions;
|
|
470
|
-
control: Control<any>;
|
|
471
|
-
parentPath?: JsonPath[];
|
|
472
|
-
}) {
|
|
473
|
-
const Render = useControlRenderer(definition, fields, renderer, options);
|
|
474
|
-
return <Render control={control} parentPath={parentPath} />;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function groupProps(
|
|
478
|
-
definition: GroupedControlsDefinition,
|
|
479
|
-
renderChild: ChildRenderer,
|
|
480
|
-
data: DataContext,
|
|
481
|
-
className: string | null | undefined,
|
|
482
|
-
style: React.CSSProperties | undefined,
|
|
483
|
-
): GroupRendererProps {
|
|
484
|
-
return {
|
|
485
|
-
children: definition.children ?? [],
|
|
486
|
-
renderChild,
|
|
487
|
-
renderOptions: definition.groupOptions ?? { type: "Standard" },
|
|
488
|
-
className: cc(className),
|
|
489
|
-
style,
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
export function defaultDataProps({
|
|
494
|
-
definition,
|
|
495
|
-
field,
|
|
496
|
-
control,
|
|
497
|
-
options,
|
|
498
|
-
elementRenderer,
|
|
499
|
-
style,
|
|
500
|
-
allowedOptions,
|
|
501
|
-
...props
|
|
502
|
-
}: DataControlProps): DataRendererProps {
|
|
503
|
-
const className = cc(definition.styleClass);
|
|
504
|
-
const required = !!definition.required;
|
|
505
|
-
const fieldOptions =
|
|
506
|
-
(field.options?.length ?? 0) === 0 ? null : field.options;
|
|
507
|
-
const allowed = allowedOptions?.value ?? [];
|
|
508
|
-
return {
|
|
509
|
-
children: definition.children ?? [],
|
|
510
|
-
control,
|
|
511
|
-
field,
|
|
512
|
-
id: "c" + control.uniqueId,
|
|
513
|
-
options:
|
|
514
|
-
fieldOptions && allowed.length > 0
|
|
515
|
-
? fieldOptions.filter((x) => allowed.includes(x.value))
|
|
516
|
-
: fieldOptions,
|
|
517
|
-
readonly: !!options.readonly,
|
|
518
|
-
renderOptions: definition.renderOptions ?? { type: "Standard" },
|
|
519
|
-
required,
|
|
520
|
-
hidden: !!options.hidden,
|
|
521
|
-
className,
|
|
522
|
-
style,
|
|
523
|
-
...props,
|
|
524
|
-
toArrayProps: elementRenderer
|
|
525
|
-
? () =>
|
|
526
|
-
defaultArrayProps(
|
|
527
|
-
control,
|
|
528
|
-
field,
|
|
529
|
-
required,
|
|
530
|
-
style,
|
|
531
|
-
className,
|
|
532
|
-
elementRenderer,
|
|
533
|
-
)
|
|
534
|
-
: undefined,
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
export function defaultArrayProps(
|
|
539
|
-
arrayControl: Control<any[] | undefined | null>,
|
|
540
|
-
field: SchemaField,
|
|
541
|
-
required: boolean,
|
|
542
|
-
style: CSSProperties | undefined,
|
|
543
|
-
className: string | undefined,
|
|
544
|
-
renderElement: (elemIndex: number) => ReactNode,
|
|
545
|
-
): ArrayRendererProps {
|
|
546
|
-
const noun = field.displayName ?? field.field;
|
|
547
|
-
const elems = arrayControl.elements ?? [];
|
|
548
|
-
return {
|
|
549
|
-
arrayControl,
|
|
550
|
-
elementCount: elems.length,
|
|
551
|
-
required,
|
|
552
|
-
addAction: {
|
|
553
|
-
actionId: "add",
|
|
554
|
-
actionText: "Add " + noun,
|
|
555
|
-
onClick: () => addElement(arrayControl, elementValueForField(field)),
|
|
556
|
-
},
|
|
557
|
-
elementKey: (i) => elems[i].uniqueId,
|
|
558
|
-
removeAction: (i: number) => ({
|
|
559
|
-
actionId: "",
|
|
560
|
-
actionText: "Remove",
|
|
561
|
-
onClick: () => removeElement(arrayControl, i),
|
|
562
|
-
}),
|
|
563
|
-
renderElement: (i) => renderElement(i),
|
|
564
|
-
className: cc(className),
|
|
565
|
-
style,
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
export type ChildRenderer = (
|
|
570
|
-
k: Key,
|
|
571
|
-
child: number | number[],
|
|
572
|
-
parentPath?: JsonPath[],
|
|
573
|
-
) => ReactNode;
|
|
574
|
-
|
|
575
|
-
export interface RenderControlProps {
|
|
576
|
-
definition: ControlDefinition;
|
|
577
|
-
renderer: FormRenderer;
|
|
578
|
-
renderChild: ChildRenderer;
|
|
579
|
-
createDataProps: CreateDataProps;
|
|
580
|
-
formOptions: FormContextOptions;
|
|
581
|
-
dataContext: ControlDataContext;
|
|
582
|
-
control?: Control<any>;
|
|
583
|
-
labelText?: Control<string | null | undefined>;
|
|
584
|
-
schemaField?: SchemaField;
|
|
585
|
-
displayControl?: Control<string | undefined>;
|
|
586
|
-
style?: React.CSSProperties;
|
|
587
|
-
allowedOptions?: Control<any[] | undefined>;
|
|
588
|
-
}
|
|
589
|
-
export function renderControlLayout({
|
|
590
|
-
definition: c,
|
|
591
|
-
renderer,
|
|
592
|
-
renderChild: childRenderer,
|
|
593
|
-
control: childControl,
|
|
594
|
-
schemaField,
|
|
595
|
-
dataContext,
|
|
596
|
-
formOptions: dataOptions,
|
|
597
|
-
createDataProps: dataProps,
|
|
598
|
-
displayControl,
|
|
599
|
-
style,
|
|
600
|
-
labelText,
|
|
601
|
-
allowedOptions,
|
|
602
|
-
}: RenderControlProps): ControlLayoutProps {
|
|
603
|
-
if (isDataControlDefinition(c)) {
|
|
604
|
-
return renderData(c);
|
|
605
|
-
}
|
|
606
|
-
if (isGroupControlsDefinition(c)) {
|
|
607
|
-
if (c.compoundField) {
|
|
608
|
-
return renderData(
|
|
609
|
-
dataControl(c.compoundField, c.title, {
|
|
610
|
-
children: c.children,
|
|
611
|
-
hideTitle: c.groupOptions?.hideTitle,
|
|
612
|
-
}),
|
|
613
|
-
);
|
|
614
|
-
}
|
|
615
|
-
return {
|
|
616
|
-
processLayout: renderer.renderGroup(
|
|
617
|
-
groupProps(c, childRenderer, dataContext, c.styleClass, style),
|
|
618
|
-
),
|
|
619
|
-
label: {
|
|
620
|
-
label: labelText?.value ?? c.title,
|
|
621
|
-
className: cc(c.labelClass),
|
|
622
|
-
type: LabelType.Group,
|
|
623
|
-
hide: c.groupOptions?.hideTitle,
|
|
624
|
-
},
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
if (isActionControlsDefinition(c)) {
|
|
628
|
-
return {
|
|
629
|
-
children: renderer.renderAction({
|
|
630
|
-
actionText: labelText?.value ?? c.title ?? c.actionId,
|
|
631
|
-
actionId: c.actionId,
|
|
632
|
-
onClick: () => {},
|
|
633
|
-
className: cc(c.styleClass),
|
|
634
|
-
style,
|
|
635
|
-
}),
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
if (isDisplayControlsDefinition(c)) {
|
|
639
|
-
return {
|
|
640
|
-
children: renderer.renderDisplay({
|
|
641
|
-
data: c.displayData ?? {},
|
|
642
|
-
className: cc(c.styleClass),
|
|
643
|
-
style,
|
|
644
|
-
display: displayControl,
|
|
645
|
-
}),
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
return {};
|
|
649
|
-
|
|
650
|
-
function renderData(c: DataControlDefinition, elemIndex?: number) {
|
|
651
|
-
if (!schemaField) return { children: "No schema field for: " + c.field };
|
|
652
|
-
if (!childControl) return { children: "No control for: " + c.field };
|
|
653
|
-
const props = dataProps({
|
|
654
|
-
definition: c,
|
|
655
|
-
field: schemaField,
|
|
656
|
-
dataContext:
|
|
657
|
-
elemIndex != null
|
|
658
|
-
? { ...dataContext, path: [...dataContext.path, elemIndex] }
|
|
659
|
-
: dataContext,
|
|
660
|
-
control:
|
|
661
|
-
elemIndex != null ? childControl!.elements[elemIndex] : childControl,
|
|
662
|
-
options: dataOptions,
|
|
663
|
-
style,
|
|
664
|
-
allowedOptions,
|
|
665
|
-
renderChild:
|
|
666
|
-
elemIndex != null
|
|
667
|
-
? (k, d, p) =>
|
|
668
|
-
childRenderer(k, d, p ? [elemIndex, ...p] : [elemIndex])
|
|
669
|
-
: childRenderer,
|
|
670
|
-
elementRenderer:
|
|
671
|
-
elemIndex == null && schemaField.collection
|
|
672
|
-
? (ei) => renderLayoutParts(renderData(c, ei), renderer).children
|
|
673
|
-
: undefined,
|
|
674
|
-
});
|
|
675
|
-
|
|
676
|
-
const label = !c.hideTitle
|
|
677
|
-
? controlTitle(labelText?.value ?? c.title, schemaField)
|
|
678
|
-
: undefined;
|
|
679
|
-
return {
|
|
680
|
-
processLayout: renderer.renderData(props),
|
|
681
|
-
label: {
|
|
682
|
-
type: LabelType.Control,
|
|
683
|
-
label,
|
|
684
|
-
forId: props.id,
|
|
685
|
-
required: c.required,
|
|
686
|
-
hide: c.hideTitle,
|
|
687
|
-
className: cc(c.labelClass),
|
|
688
|
-
},
|
|
689
|
-
errorControl: childControl,
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
export function appendMarkup(
|
|
695
|
-
k: keyof Omit<RenderedLayout, "errorControl" | "style" | "className">,
|
|
696
|
-
markup: ReactNode,
|
|
697
|
-
): (layout: RenderedLayout) => void {
|
|
698
|
-
return (layout) =>
|
|
699
|
-
(layout[k] = (
|
|
700
|
-
<>
|
|
701
|
-
{layout[k]}
|
|
702
|
-
{markup}
|
|
703
|
-
</>
|
|
704
|
-
));
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
export function wrapMarkup(
|
|
708
|
-
k: keyof Omit<RenderedLayout, "errorControl" | "style" | "className">,
|
|
709
|
-
wrap: (ex: ReactNode) => ReactNode,
|
|
710
|
-
): (layout: RenderedLayout) => void {
|
|
711
|
-
return (layout) => (layout[k] = wrap(layout[k]));
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
export function layoutKeyForPlacement(
|
|
715
|
-
pos: AdornmentPlacement,
|
|
716
|
-
): keyof Omit<RenderedLayout, "errorControl" | "style" | "className"> {
|
|
717
|
-
switch (pos) {
|
|
718
|
-
case AdornmentPlacement.ControlEnd:
|
|
719
|
-
return "controlEnd";
|
|
720
|
-
case AdornmentPlacement.ControlStart:
|
|
721
|
-
return "controlStart";
|
|
722
|
-
case AdornmentPlacement.LabelStart:
|
|
723
|
-
return "labelStart";
|
|
724
|
-
case AdornmentPlacement.LabelEnd:
|
|
725
|
-
return "labelEnd";
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
export function appendMarkupAt(
|
|
730
|
-
pos: AdornmentPlacement,
|
|
731
|
-
markup: ReactNode,
|
|
732
|
-
): (layout: RenderedLayout) => void {
|
|
733
|
-
return appendMarkup(layoutKeyForPlacement(pos), markup);
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
export function wrapMarkupAt(
|
|
737
|
-
pos: AdornmentPlacement,
|
|
738
|
-
wrap: (ex: ReactNode) => ReactNode,
|
|
739
|
-
): (layout: RenderedLayout) => void {
|
|
740
|
-
return wrapMarkup(layoutKeyForPlacement(pos), wrap);
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
export function renderLayoutParts(
|
|
744
|
-
props: ControlLayoutProps,
|
|
745
|
-
renderer: FormRenderer,
|
|
746
|
-
): RenderedLayout {
|
|
747
|
-
const { className, children, style, errorControl, label, adornments } =
|
|
748
|
-
props.processLayout?.(props) ?? props;
|
|
749
|
-
const layout: RenderedLayout = {
|
|
750
|
-
children,
|
|
751
|
-
errorControl,
|
|
752
|
-
style,
|
|
753
|
-
className: cc(className),
|
|
754
|
-
};
|
|
755
|
-
(adornments ?? [])
|
|
756
|
-
.sort((a, b) => a.priority - b.priority)
|
|
757
|
-
.forEach((x) => x.apply(layout));
|
|
758
|
-
layout.label =
|
|
759
|
-
label && !label.hide
|
|
760
|
-
? renderer.renderLabel(label, layout.labelStart, layout.labelEnd)
|
|
761
|
-
: undefined;
|
|
762
|
-
return layout;
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
export function controlTitle(
|
|
766
|
-
title: string | undefined | null,
|
|
767
|
-
field: SchemaField,
|
|
768
|
-
) {
|
|
769
|
-
return title ? title : fieldDisplayName(field);
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
function lookupControl(
|
|
773
|
-
base: Control<any> | undefined,
|
|
774
|
-
path: (string | number)[],
|
|
775
|
-
): Control<any> | undefined {
|
|
776
|
-
let index = 0;
|
|
777
|
-
while (index < path.length && base) {
|
|
778
|
-
const childId = path[index];
|
|
779
|
-
const c = base.current;
|
|
780
|
-
if (typeof childId === "string") {
|
|
781
|
-
const next = c.fields?.[childId];
|
|
782
|
-
if (!next) trackControlChange(base, ControlChange.Structure);
|
|
783
|
-
base = next;
|
|
784
|
-
} else {
|
|
785
|
-
base = c.elements?.[childId];
|
|
786
|
-
}
|
|
787
|
-
index++;
|
|
788
|
-
}
|
|
789
|
-
return base;
|
|
790
|
-
}
|