@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.
@@ -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
- }