@react-typed-forms/schemas 15.2.0 → 16.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,54 +1,50 @@
1
1
  import React, {
2
- ButtonHTMLAttributes,
2
+ ComponentType,
3
3
  ElementType,
4
- FC,
5
4
  Fragment,
6
5
  HTMLAttributes,
7
- InputHTMLAttributes,
8
6
  Key,
9
- LabelHTMLAttributes,
10
7
  ReactElement,
11
8
  ReactNode,
12
- useCallback,
13
- useEffect,
14
9
  } from "react";
15
10
  import {
16
11
  addElement,
17
12
  Control,
18
- newControl,
19
13
  removeElement,
20
14
  RenderArrayElements,
21
- trackedValue,
22
- useComponentTracking,
23
- useComputed,
24
- useControl,
25
- useControlEffect,
26
15
  } from "@react-typed-forms/core";
27
16
  import {
17
+ ActionStyle,
28
18
  AdornmentPlacement,
29
19
  ArrayActionOptions,
30
- ControlActionHandler,
31
20
  ControlAdornment,
32
- ControlAdornmentType,
33
- ControlDataContext,
34
21
  ControlDefinition,
22
+ ControlDefinitionType,
23
+ ControlState,
35
24
  CustomDisplay,
36
25
  DataControlDefinition,
37
- DataRenderType,
26
+ defaultSchemaInterface,
38
27
  DisplayData,
39
28
  DisplayDataType,
40
- DynamicPropertyType,
41
- FormContextData,
29
+ FieldOption,
30
+ FormContextOptions,
42
31
  FormNode,
32
+ FormState,
43
33
  GroupRenderOptions,
34
+ GroupRenderType,
44
35
  isActionControl,
45
36
  isDataControl,
46
37
  isDisplayControl,
47
38
  isGroupControl,
48
- legacyFormNode,
39
+ JsonPath,
40
+ LengthValidator,
49
41
  lookupDataNode,
50
42
  RenderOptions,
51
- } from "./controlDefinition";
43
+ SchemaDataNode,
44
+ SchemaField,
45
+ SchemaInterface,
46
+ ValidatorType,
47
+ } from "@astroapps/forms-core";
52
48
  import {
53
49
  applyLengthRestrictions,
54
50
  ControlClasses,
@@ -56,53 +52,82 @@ import {
56
52
  ExternalEditAction,
57
53
  fieldDisplayName,
58
54
  getExternalEditData,
59
- getGroupClassOverrides,
60
- isControlDisplayOnly,
61
- JsonPath,
62
55
  rendererClass,
63
- useUpdatedRef,
64
56
  } from "./util";
65
57
  import { createAction, dataControl } from "./controlBuilder";
66
58
  import {
67
- defaultUseEvalExpressionHook,
68
- EvalExpressionHook,
69
- useEvalActionHook,
70
- useEvalAllowedOptionsHook,
71
- useEvalDefaultValueHook,
72
- useEvalDisabledHook,
73
- useEvalDisplayHook,
74
- UseEvalExpressionHook,
75
- useEvalLabelText,
76
- useEvalReadonlyHook,
77
- useEvalStyleHook,
78
- useEvalVisibilityHook,
79
- } from "./hooks";
80
- import { useMakeValidationHook, ValidationContext } from "./validators";
81
- import { useDynamicHooks } from "./dynamicHooks";
82
- import { defaultSchemaInterface } from "./defaultSchemaInterface";
83
- import {
84
- LengthValidator,
85
- SchemaValidator,
86
- ValidatorType,
87
- } from "./schemaValidator";
88
- import {
89
- createSchemaLookup,
90
- FieldOption,
91
- makeSchemaDataNode,
92
- SchemaDataNode,
93
- SchemaField,
94
- SchemaInterface,
95
- } from "./schemaField";
59
+ ActionRendererProps,
60
+ ControlActionHandler,
61
+ ControlDataContext,
62
+ RunExpression,
63
+ } from "./types";
96
64
 
65
+ export interface HtmlIconProperties {
66
+ className?: string;
67
+ style?: React.CSSProperties;
68
+ iconLibrary?: string;
69
+ iconName?: string;
70
+ }
71
+
72
+ export interface HtmlLabelProperties {
73
+ htmlFor?: string;
74
+ className?: string;
75
+ textClass?: string;
76
+ children?: ReactNode;
77
+ }
78
+
79
+ export interface HtmlDivProperties {
80
+ id?: string;
81
+ className?: string;
82
+ textClass?: string;
83
+ style?: React.CSSProperties;
84
+ children?: ReactNode;
85
+ text?: string;
86
+ html?: string;
87
+ nativeRef?: (e: HTMLElement | null) => void;
88
+ inline?: boolean;
89
+ }
90
+
91
+ export interface HtmlInputProperties {
92
+ id?: string;
93
+ className?: string;
94
+ textClass?: string;
95
+ name?: string;
96
+ type?: string;
97
+ checked?: boolean;
98
+ style?: React.CSSProperties;
99
+ readOnly?: boolean;
100
+ placeholder?: string;
101
+ value?: string | number;
102
+ onBlur?: () => void;
103
+ disabled?: boolean;
104
+ inputRef?: (e: HTMLElement | null) => void;
105
+ onChangeValue?: (value: string) => void;
106
+ onChangeChecked?: (checked: boolean) => void;
107
+ }
108
+
109
+ export interface HtmlButtonProperties {
110
+ className?: string;
111
+ textClass?: string;
112
+ disabled?: boolean;
113
+ style?: React.CSSProperties;
114
+ onClick?: () => void;
115
+ inline?: boolean;
116
+ children?: ReactNode;
117
+ title?: string;
118
+ notWrapInText?: boolean;
119
+ androidRippleColor?: string;
120
+ nonTextContent?: boolean;
121
+ }
97
122
  export interface HtmlComponents {
98
- Div: ElementType<HTMLAttributes<HTMLDivElement>, "div">;
123
+ Div: ComponentType<HtmlDivProperties>;
99
124
  Span: ElementType<HTMLAttributes<HTMLSpanElement>>;
100
- Button: ElementType<ButtonHTMLAttributes<HTMLButtonElement>>;
101
- I: ElementType<HTMLAttributes<HTMLElement>>;
102
- Label: ElementType<LabelHTMLAttributes<HTMLLabelElement>>;
125
+ Button: ComponentType<HtmlButtonProperties>;
126
+ I: ComponentType<HtmlIconProperties>;
127
+ Label: ComponentType<HtmlLabelProperties>;
103
128
  B: ElementType<HTMLAttributes<HTMLElement>>;
104
129
  H1: ElementType<HTMLAttributes<HTMLElement>>;
105
- Input: ElementType<InputHTMLAttributes<HTMLInputElement>, "input">;
130
+ Input: ComponentType<HtmlInputProperties>;
106
131
  }
107
132
  /**
108
133
  * Interface for rendering different types of form controls.
@@ -187,7 +212,6 @@ export interface FormRenderer {
187
212
  * @returns A React node.
188
213
  */
189
214
  renderLabelText: (props: ReactNode) => ReactNode;
190
- renderText: (props: ReactNode, className?: string) => ReactNode;
191
215
 
192
216
  html: HtmlComponents;
193
217
  }
@@ -195,7 +219,7 @@ export interface FormRenderer {
195
219
  export interface AdornmentProps {
196
220
  adornment: ControlAdornment;
197
221
  dataContext: ControlDataContext;
198
- useExpr?: UseEvalExpressionHook;
222
+ runExpression?: RunExpression;
199
223
  designMode?: boolean;
200
224
  formOptions: FormContextOptions;
201
225
  }
@@ -241,6 +265,7 @@ export interface RenderedLayout {
241
265
  className?: string;
242
266
  style?: React.CSSProperties;
243
267
  wrapLayout: (layout: ReactElement) => ReactElement;
268
+ inline?: boolean;
244
269
  }
245
270
 
246
271
  export interface RenderedControl {
@@ -248,6 +273,7 @@ export interface RenderedControl {
248
273
  className?: string;
249
274
  style?: React.CSSProperties;
250
275
  divRef?: (cb: HTMLElement | null) => void;
276
+ inline?: boolean;
251
277
  }
252
278
 
253
279
  export interface VisibilityRendererProps extends RenderedControl {
@@ -262,6 +288,7 @@ export interface ControlLayoutProps {
262
288
  processLayout?: (props: ControlLayoutProps) => ControlLayoutProps;
263
289
  className?: string | null;
264
290
  style?: React.CSSProperties;
291
+ inline?: boolean;
265
292
  }
266
293
 
267
294
  /**
@@ -318,6 +345,11 @@ export interface LabelRendererProps {
318
345
  * The CSS class name for the label.
319
346
  */
320
347
  className?: string;
348
+
349
+ /**
350
+ * The CSS class name for the label text.
351
+ */
352
+ textClass?: string;
321
353
  }
322
354
 
323
355
  /**
@@ -344,26 +376,27 @@ export interface DisplayRendererProps {
344
376
  */
345
377
  className?: string;
346
378
 
379
+ textClass?: string;
380
+
347
381
  /**
348
382
  * The CSS styles for the display renderer.
349
383
  */
350
384
  style?: React.CSSProperties;
385
+ inline?: boolean;
351
386
  }
352
387
 
353
- export type ChildVisibilityFunc = (
354
- child: ControlDefinition,
355
- parentNode?: SchemaDataNode,
356
- dontOverride?: boolean,
357
- ) => EvalExpressionHook<boolean>;
358
388
  export interface ParentRendererProps {
359
389
  formNode: FormNode;
390
+ state: ControlState;
360
391
  renderChild: ChildRenderer;
361
392
  className?: string;
393
+ textClass?: string;
362
394
  style?: React.CSSProperties;
363
395
  dataContext: ControlDataContext;
364
- useChildVisibility: ChildVisibilityFunc;
365
- useEvalExpression: UseEvalExpressionHook;
396
+ getChildState(node: FormNode, parent?: SchemaDataNode): ControlState;
397
+ runExpression: RunExpression;
366
398
  designMode?: boolean;
399
+ actionOnClick?: ControlActionHandler;
367
400
  }
368
401
 
369
402
  export interface GroupRendererProps extends ParentRendererProps {
@@ -375,7 +408,6 @@ export interface DataRendererProps extends ParentRendererProps {
375
408
  renderOptions: RenderOptions;
376
409
  definition: DataControlDefinition;
377
410
  field: SchemaField;
378
- elementIndex?: number;
379
411
  id: string;
380
412
  control: Control<any>;
381
413
  readonly: boolean;
@@ -384,16 +416,7 @@ export interface DataRendererProps extends ParentRendererProps {
384
416
  hidden: boolean;
385
417
  dataNode: SchemaDataNode;
386
418
  displayOnly: boolean;
387
- }
388
-
389
- export interface ActionRendererProps {
390
- actionId: string;
391
- actionText: string;
392
- actionData?: any;
393
- onClick: () => void;
394
- className?: string | null;
395
- style?: React.CSSProperties;
396
- disabled?: boolean;
419
+ inline: boolean;
397
420
  }
398
421
 
399
422
  export interface ControlRenderProps {
@@ -401,411 +424,57 @@ export interface ControlRenderProps {
401
424
  parentPath?: JsonPath[];
402
425
  }
403
426
 
404
- export interface FormContextOptions {
405
- readonly?: boolean | null;
406
- hidden?: boolean | null;
407
- disabled?: boolean | null;
408
- displayOnly?: boolean;
409
- }
410
-
411
- export interface DataControlProps {
412
- formNode: FormNode;
413
- definition: DataControlDefinition;
414
- dataContext: ControlDataContext;
415
- control: Control<any>;
416
- formOptions: FormContextOptions;
417
- style?: React.CSSProperties | undefined;
418
- renderChild: ChildRenderer;
419
- elementIndex?: number;
420
- allowedOptions?: Control<any[] | undefined>;
421
- useChildVisibility: ChildVisibilityFunc;
422
- useEvalExpression: UseEvalExpressionHook;
423
- schemaInterface?: SchemaInterface;
424
- designMode?: boolean;
425
- styleClass?: string;
426
- layoutClass?: string;
427
- }
428
-
429
427
  export type CreateDataProps = (
430
- controlProps: DataControlProps,
428
+ controlProps: RenderLayoutProps,
429
+ definition: DataControlDefinition,
430
+ control: Control<any>,
431
431
  ) => DataRendererProps;
432
432
 
433
- export interface ControlRenderOptions
434
- extends FormContextOptions,
435
- ControlClasses {
433
+ export interface ControlRenderOptions extends ControlClasses {
434
+ formState?: FormState;
436
435
  useDataHook?: (c: ControlDefinition) => CreateDataProps;
437
436
  actionOnClick?: ControlActionHandler;
438
437
  customDisplay?: (
439
438
  customId: string,
440
439
  displayProps: DisplayRendererProps,
441
440
  ) => ReactNode;
442
- useValidationHook?: (
443
- validator: SchemaValidator,
444
- ctx: ValidationContext,
445
- ) => void;
446
- useEvalExpressionHook?: UseEvalExpressionHook;
447
441
  adjustLayout?: (
448
442
  context: ControlDataContext,
449
443
  layout: ControlLayoutProps,
450
444
  ) => ControlLayoutProps;
445
+ readonly?: boolean | null;
446
+ hidden?: boolean | null;
447
+ disabled?: boolean | null;
448
+ displayOnly?: boolean;
449
+ inline?: boolean;
451
450
  clearHidden?: boolean;
451
+ stateKey?: string;
452
452
  schemaInterface?: SchemaInterface;
453
- elementIndex?: number;
454
- formData?: FormContextData;
455
- }
456
-
457
- export function useControlRenderer(
458
- definition: ControlDefinition,
459
- fields: SchemaField[],
460
- renderer: FormRenderer,
461
- options: ControlRenderOptions = {},
462
- ): FC<ControlRenderProps> {
463
- const r = useUpdatedRef({ definition, fields, renderer, options });
464
- return useCallback(
465
- ({ control, parentPath }) => {
466
- return (
467
- <ControlRenderer
468
- {...r.current}
469
- control={control}
470
- parentPath={parentPath}
471
- />
472
- );
473
- },
474
- [r],
475
- );
476
- }
477
- export function useControlRendererComponent(
478
- controlOrFormNode: ControlDefinition | FormNode,
479
- renderer: FormRenderer,
480
- options: ControlRenderOptions = {},
481
- parentDataNode: SchemaDataNode,
482
- ): FC<{}> {
483
- const [definition, formNode] =
484
- "definition" in controlOrFormNode
485
- ? [controlOrFormNode.definition, controlOrFormNode]
486
- : [controlOrFormNode, legacyFormNode(controlOrFormNode)];
487
- const dataProps = options.useDataHook?.(definition) ?? defaultDataProps;
488
- const elementIndex = options.elementIndex;
489
- const schemaInterface = options.schemaInterface ?? defaultSchemaInterface;
490
- const useExpr = options.useEvalExpressionHook ?? defaultUseEvalExpressionHook;
491
-
492
- let dataNode: SchemaDataNode | undefined;
493
- if (elementIndex != null) {
494
- dataNode = parentDataNode.getChildElement(elementIndex);
495
- } else {
496
- dataNode = lookupDataNode(definition, parentDataNode);
497
- }
498
- const useValidation = useMakeValidationHook(
499
- definition,
500
- options.useValidationHook,
501
- );
502
- const dynamicHooks = useDynamicHooks({
503
- defaultValueControl: useEvalDefaultValueHook(useExpr, definition),
504
- visibleControl: useEvalVisibilityHook(useExpr, definition),
505
- readonlyControl: useEvalReadonlyHook(useExpr, definition),
506
- disabledControl: useEvalDisabledHook(useExpr, definition),
507
- allowedOptions: useEvalAllowedOptionsHook(useExpr, definition),
508
- labelText: useEvalLabelText(useExpr, definition),
509
- actionData: useEvalActionHook(useExpr, definition),
510
- customStyle: useEvalStyleHook(
511
- useExpr,
512
- DynamicPropertyType.Style,
513
- definition,
514
- ),
515
- layoutStyle: useEvalStyleHook(
516
- useExpr,
517
- DynamicPropertyType.LayoutStyle,
518
- definition,
519
- ),
520
- displayControl: useEvalDisplayHook(useExpr, definition),
521
- });
522
-
523
- const r = useUpdatedRef({
524
- options,
525
- definition,
526
- elementIndex,
527
- parentDataNode,
528
- dataNode,
529
- formNode,
530
- });
531
-
532
- if (formNode == null) debugger;
533
- const Component = useCallback(() => {
534
- const stopTracking = useComponentTracking();
535
-
536
- try {
537
- const {
538
- definition: c,
539
- options,
540
- elementIndex,
541
- parentDataNode: pdn,
542
- dataNode: dn,
543
- formNode,
544
- } = r.current;
545
- const formData = options.formData ?? {};
546
- const dataContext: ControlDataContext = {
547
- schemaInterface,
548
- dataNode: dn,
549
- parentNode: pdn,
550
- formData,
551
- };
552
- const {
553
- readonlyControl,
554
- disabledControl,
555
- visibleControl,
556
- displayControl,
557
- layoutStyle,
558
- labelText,
559
- customStyle,
560
- allowedOptions,
561
- defaultValueControl,
562
- actionData,
563
- } = dynamicHooks(dataContext);
564
-
565
- const visible = visibleControl.current.value;
566
- const visibility = useControl<Visibility | undefined>(() =>
567
- visible != null
568
- ? {
569
- visible,
570
- showing: visible,
571
- }
572
- : undefined,
573
- );
574
- useControlEffect(
575
- () => visibleControl.value,
576
- (visible) => {
577
- if (visible != null)
578
- visibility.setValue((ex) => ({
579
- visible,
580
- showing: ex ? ex.showing : visible,
581
- }));
582
- },
583
- );
584
-
585
- const parentControl = parentDataNode.control!;
586
- const control = dataNode?.control;
587
- useControlEffect(
588
- () => [
589
- visibility.value,
590
- defaultValueControl.value,
591
- control?.isNull,
592
- isDataControl(definition) && definition.dontClearHidden,
593
- definition.adornments?.some(
594
- (x) => x.type === ControlAdornmentType.Optional,
595
- ) ||
596
- (isDataControl(definition) &&
597
- definition.renderOptions?.type == DataRenderType.NullToggle),
598
- parentControl.isNull,
599
- options.hidden,
600
- readonlyControl.value,
601
- ],
602
- ([vc, dv, _, dontClear, dontDefault, parentNull, hidden, ro]) => {
603
- if (!ro) {
604
- if (control) {
605
- if (vc && vc.visible === vc.showing) {
606
- if (hidden || !vc.visible) {
607
- control.setValue((x) =>
608
- options.clearHidden && !dontClear
609
- ? undefined
610
- : x == null && dontClear && !dontDefault
611
- ? dv
612
- : x,
613
- );
614
- } else if (!dontDefault)
615
- control.setValue((x) => (x != null ? x : dv));
616
- }
617
- } else if (parentNull) {
618
- parentControl.setValue((x) => x ?? {});
619
- }
620
- }
621
- },
622
- true,
623
- );
624
- const myOptionsControl = useComputed<FormContextOptions>(() => ({
625
- hidden: options.hidden || !visibility.fields?.showing.value,
626
- readonly: options.readonly || readonlyControl.value,
627
- disabled: options.disabled || disabledControl.value,
628
- displayOnly: options.displayOnly || isControlDisplayOnly(c),
629
- }));
630
- const myOptions = trackedValue(myOptionsControl);
631
- useValidation({
632
- control: control ?? newControl(null),
633
- hiddenControl: myOptionsControl.fields.hidden,
634
- dataContext,
635
- });
636
- const { styleClass, labelClass, layoutClass, ...inheritableOptions } =
637
- options;
638
- const childOptions: ControlRenderOptions = {
639
- ...inheritableOptions,
640
- ...myOptions,
641
- elementIndex: undefined,
642
- };
643
-
644
- useEffect(() => {
645
- if (
646
- control &&
647
- typeof myOptions.disabled === "boolean" &&
648
- control.disabled != myOptions.disabled
649
- )
650
- control.disabled = myOptions.disabled;
651
- }, [control, myOptions.disabled]);
652
- if (parentControl.isNull) return <></>;
653
-
654
- const adornments =
655
- definition.adornments?.map((x) =>
656
- renderer.renderAdornment({
657
- adornment: x,
658
- dataContext,
659
- useExpr,
660
- formOptions: myOptions,
661
- }),
662
- ) ?? [];
663
- const otherChildNodes =
664
- definition.childRefId &&
665
- formNode.tree.getByRefId(definition.childRefId)?.getChildNodes();
666
-
667
- const labelAndChildren = renderControlLayout({
668
- formNode: otherChildNodes
669
- ? formNode.tree.createTempNode(
670
- formNode.id,
671
- definition,
672
- otherChildNodes,
673
- )
674
- : formNode,
675
- definition: c,
676
- renderer,
677
- renderChild: (k, child, options) => {
678
- const overrideClasses = getGroupClassOverrides(c);
679
- const { parentDataNode, ...renderOptions } = options ?? {};
680
- const dContext =
681
- parentDataNode ?? dataContext.dataNode ?? dataContext.parentNode;
682
- const allChildOptions = {
683
- ...childOptions,
684
- ...overrideClasses,
685
- ...renderOptions,
686
- };
687
- return (
688
- <NewControlRenderer
689
- key={k}
690
- definition={child}
691
- renderer={renderer}
692
- parentDataNode={dContext}
693
- options={allChildOptions}
694
- />
695
- );
696
- },
697
- createDataProps: dataProps,
698
- formOptions: myOptions,
699
- dataContext,
700
- control: displayControl ?? control,
701
- elementIndex,
702
- schemaInterface,
703
- labelText,
704
- displayControl,
705
- style: customStyle.value,
706
- allowedOptions,
707
- customDisplay: options.customDisplay,
708
- actionDataControl: actionData,
709
- actionOnClick: options.actionOnClick,
710
- styleClass: options.styleClass,
711
- labelClass: options.labelClass,
712
- useEvalExpression: useExpr,
713
- useChildVisibility: (childDef, parentNode, dontOverride) => {
714
- return useEvalVisibilityHook(
715
- useExpr,
716
- childDef,
717
- !dontOverride
718
- ? lookupDataNode(
719
- childDef,
720
- parentNode ?? dataNode ?? parentDataNode,
721
- )
722
- : undefined,
723
- );
724
- },
725
- });
726
- const layoutProps: ControlLayoutProps = {
727
- ...labelAndChildren,
728
- adornments,
729
- className: rendererClass(options.layoutClass, c.layoutClass),
730
- style: layoutStyle.value,
731
- };
732
- const renderedControl = renderer.renderLayout(
733
- options.adjustLayout?.(dataContext, layoutProps) ?? layoutProps,
734
- );
735
- return renderer.renderVisibility({ visibility, ...renderedControl });
736
- } finally {
737
- stopTracking();
738
- }
739
- }, [r, dataProps, useValidation, renderer, schemaInterface, dynamicHooks]);
740
- (Component as any).displayName = "RenderControl";
741
- return Component;
742
- }
743
-
744
- export function ControlRenderer({
745
- definition,
746
- fields,
747
- renderer,
748
- options,
749
- control,
750
- parentPath,
751
- }: {
752
- definition: ControlDefinition;
753
- fields: SchemaField[];
754
- renderer: FormRenderer;
755
- options?: ControlRenderOptions;
756
- control: Control<any>;
757
- parentPath?: JsonPath[];
758
- }) {
759
- const schemaDataNode = makeSchemaDataNode(
760
- createSchemaLookup({ "": fields }).getSchema("")!,
761
- control,
762
- );
763
- const Render = useControlRendererComponent(
764
- definition,
765
- renderer,
766
- options,
767
- schemaDataNode,
768
- );
769
- return <Render />;
770
- }
771
-
772
- export function NewControlRenderer({
773
- definition,
774
- renderer,
775
- options,
776
- parentDataNode,
777
- }: {
778
- definition: ControlDefinition | FormNode;
779
- renderer: FormRenderer;
780
- options?: ControlRenderOptions;
781
- parentDataNode: SchemaDataNode;
782
- }) {
783
- const Render = useControlRendererComponent(
784
- definition,
785
- renderer,
786
- options,
787
- parentDataNode,
788
- );
789
- return <Render />;
453
+ variables?: Record<string, any>;
790
454
  }
791
455
 
792
- export function defaultDataProps({
793
- definition,
794
- control,
795
- formOptions,
796
- style,
797
- allowedOptions,
798
- schemaInterface = defaultSchemaInterface,
799
- styleClass,
800
- ...props
801
- }: DataControlProps): DataRendererProps {
456
+ export function defaultDataProps(
457
+ {
458
+ formOptions,
459
+ style,
460
+ allowedOptions,
461
+ schemaInterface = defaultSchemaInterface,
462
+ styleClass,
463
+ textClass: tc,
464
+ displayOnly,
465
+ inline,
466
+ ...props
467
+ }: RenderLayoutProps,
468
+ definition: DataControlDefinition,
469
+ control: Control<any>,
470
+ ): DataRendererProps {
802
471
  const dataNode = props.dataContext.dataNode!;
803
472
  const field = dataNode.schema.field;
804
473
  const className = rendererClass(styleClass, definition.styleClass);
805
- const displayOnly = !!formOptions.displayOnly;
474
+ const textClass = rendererClass(tc, definition.textClass);
806
475
  const required = !!definition.required && !displayOnly;
807
476
  const fieldOptions = schemaInterface.getDataOptions(dataNode);
808
- const _allowed = allowedOptions?.value ?? [];
477
+ const _allowed = allowedOptions ?? [];
809
478
  const allowed = Array.isArray(_allowed) ? _allowed : [_allowed];
810
479
  return {
811
480
  dataNode,
@@ -813,38 +482,43 @@ export function defaultDataProps({
813
482
  control,
814
483
  field,
815
484
  id: "c" + control.uniqueId,
485
+ inline: !!inline,
816
486
  options:
817
487
  allowed.length > 0
818
488
  ? allowed
819
489
  .map((x) =>
820
490
  typeof x === "object"
821
491
  ? x
822
- : (fieldOptions?.find((y) => y.value == x) ?? {
492
+ : fieldOptions?.find((y) => y.value == x) ?? {
823
493
  name: x.toString(),
824
494
  value: x,
825
- }),
495
+ },
826
496
  )
827
497
  .filter((x) => x != null)
828
498
  : fieldOptions,
829
499
  readonly: !!formOptions.readonly,
830
- displayOnly,
500
+ displayOnly: !!displayOnly,
831
501
  renderOptions: definition.renderOptions ?? { type: "Standard" },
832
502
  required,
833
503
  hidden: !!formOptions.hidden,
834
504
  className,
505
+ textClass,
835
506
  style,
836
507
  ...props,
837
508
  };
838
509
  }
839
510
 
840
511
  export interface ChildRendererOptions {
841
- elementIndex?: number;
842
512
  parentDataNode?: SchemaDataNode;
843
- formData?: FormContextData;
513
+ inline?: boolean;
844
514
  displayOnly?: boolean;
845
515
  styleClass?: string;
846
516
  layoutClass?: string;
847
517
  labelClass?: string;
518
+ labelTextClass?: string;
519
+ actionOnClick?: ControlActionHandler;
520
+ stateKey?: string;
521
+ variables?: Record<string, any>;
848
522
  }
849
523
 
850
524
  export type ChildRenderer = (
@@ -853,23 +527,20 @@ export type ChildRenderer = (
853
527
  options?: ChildRendererOptions,
854
528
  ) => ReactNode;
855
529
 
856
- export interface RenderControlProps {
857
- definition: ControlDefinition;
530
+ export interface RenderLayoutProps {
858
531
  formNode: FormNode;
859
532
  renderer: FormRenderer;
533
+ state: ControlState;
860
534
  renderChild: ChildRenderer;
861
535
  createDataProps: CreateDataProps;
862
536
  formOptions: FormContextOptions;
863
537
  dataContext: ControlDataContext;
864
538
  control?: Control<any>;
865
- labelText?: Control<string | null | undefined>;
866
- elementIndex?: number;
867
- displayControl?: Control<string | undefined>;
868
539
  style?: React.CSSProperties;
869
- allowedOptions?: Control<any[] | undefined>;
870
- actionDataControl?: Control<any | undefined | null>;
871
- useChildVisibility: ChildVisibilityFunc;
872
- useEvalExpression: UseEvalExpressionHook;
540
+ allowedOptions?: any[];
541
+ getChildState(node: FormNode, parent?: SchemaDataNode): ControlState;
542
+ runExpression: RunExpression;
543
+
873
544
  actionOnClick?: ControlActionHandler;
874
545
  schemaInterface?: SchemaInterface;
875
546
  designMode?: boolean;
@@ -878,30 +549,38 @@ export interface RenderControlProps {
878
549
  displayProps: DisplayRendererProps,
879
550
  ) => ReactNode;
880
551
  labelClass?: string;
552
+ labelTextClass?: string;
881
553
  styleClass?: string;
554
+ textClass?: string;
555
+ inline?: boolean;
556
+ displayOnly?: boolean;
882
557
  }
883
558
  export function renderControlLayout(
884
- props: RenderControlProps,
559
+ props: RenderLayoutProps,
885
560
  ): ControlLayoutProps {
886
561
  const {
887
- definition: c,
888
562
  renderer,
889
563
  renderChild,
890
564
  control,
891
565
  dataContext,
892
566
  createDataProps: dataProps,
893
- displayControl,
894
567
  style,
895
- labelText,
896
- useChildVisibility,
897
568
  designMode,
898
569
  customDisplay,
899
- useEvalExpression,
570
+ runExpression,
900
571
  labelClass,
572
+ labelTextClass,
901
573
  styleClass,
574
+ textClass,
902
575
  formNode,
576
+ formOptions,
577
+ actionOnClick,
578
+ state,
579
+ getChildState,
580
+ inline,
581
+ displayOnly,
903
582
  } = props;
904
-
583
+ const c = state.definition;
905
584
  if (isDataControl(c)) {
906
585
  return renderData(c);
907
586
  }
@@ -916,33 +595,48 @@ export function renderControlLayout(
916
595
  }
917
596
 
918
597
  return {
598
+ inline,
919
599
  processLayout: renderer.renderGroup({
920
600
  formNode,
601
+ state,
921
602
  definition: c,
922
603
  renderChild,
923
- useEvalExpression,
604
+ runExpression,
924
605
  dataContext,
925
606
  renderOptions: c.groupOptions ?? { type: "Standard" },
926
607
  className: rendererClass(styleClass, c.styleClass),
927
- useChildVisibility,
608
+ textClass: rendererClass(textClass, c.textClass),
928
609
  style,
929
610
  designMode,
611
+ actionOnClick,
612
+ getChildState,
930
613
  }),
931
614
  label: {
932
- label: labelText?.value ?? c.title,
615
+ label: c.title,
933
616
  className: rendererClass(labelClass, c.labelClass),
617
+ textClass: rendererClass(labelTextClass, c.labelTextClass),
934
618
  type: LabelType.Group,
935
619
  hide: c.groupOptions?.hideTitle,
936
620
  },
937
621
  };
938
622
  }
939
623
  if (isActionControl(c)) {
940
- const actionData = props.actionDataControl?.value ?? c.actionData;
624
+ const actionData = c.actionData;
625
+ const actionStyle = c.actionStyle ?? ActionStyle.Button;
626
+ const actionContent =
627
+ actionStyle == ActionStyle.Group ? renderActionGroup() : undefined;
941
628
  return {
629
+ inline,
942
630
  children: renderer.renderAction({
943
- actionText: labelText?.value ?? c.title ?? c.actionId,
631
+ actionText: c.title ?? c.actionId,
944
632
  actionId: c.actionId,
945
633
  actionData,
634
+ actionContent,
635
+ actionStyle,
636
+ textClass: rendererClass(textClass, c.textClass),
637
+ iconPlacement: c.iconPlacement,
638
+ icon: c.icon,
639
+ inline,
946
640
  onClick:
947
641
  props.actionOnClick?.(c.actionId, actionData, dataContext) ??
948
642
  (() => {}),
@@ -950,22 +644,36 @@ export function renderControlLayout(
950
644
  style,
951
645
  }),
952
646
  };
647
+
648
+ function renderActionGroup() {
649
+ const childDefs = formNode.getResolvedChildren();
650
+ const childDef = {
651
+ type: ControlDefinitionType.Group,
652
+ groupOptions: { type: GroupRenderType.Contents, hideTitle: true },
653
+ children: childDefs,
654
+ };
655
+ const childNode: FormNode = formNode.createChildNode("child", childDef);
656
+ return renderChild("child", childNode, {});
657
+ }
953
658
  }
954
659
  if (isDisplayControl(c)) {
955
660
  const data = c.displayData ?? {};
956
661
  const displayProps = {
957
662
  data,
958
663
  className: rendererClass(styleClass, c.styleClass),
664
+ textClass: rendererClass(textClass, c.textClass),
959
665
  style,
960
- display: displayControl,
961
666
  dataContext,
667
+ inline,
962
668
  };
963
669
  if (data.type === DisplayDataType.Custom && customDisplay) {
964
670
  return {
671
+ inline,
965
672
  children: customDisplay((data as CustomDisplay).customId, displayProps),
966
673
  };
967
674
  }
968
675
  return {
676
+ inline,
969
677
  children: renderer.renderDisplay(displayProps),
970
678
  };
971
679
  }
@@ -973,29 +681,22 @@ export function renderControlLayout(
973
681
 
974
682
  function renderData(c: DataControlDefinition): ControlLayoutProps {
975
683
  if (!control) return { children: "No control for: " + c.field };
976
- const rendererProps = dataProps(
977
- props as RenderControlProps & {
978
- definition: DataControlDefinition;
979
- control: Control<any>;
980
- },
981
- );
982
-
684
+ const rendererProps = dataProps(props, c, control);
983
685
  const label = !c.hideTitle
984
- ? controlTitle(
985
- labelText?.value ?? c.title,
986
- props.dataContext.dataNode!.schema.field,
987
- )
686
+ ? controlTitle(c.title, props.dataContext.dataNode!.schema.field)
988
687
  : undefined;
989
688
  return {
689
+ inline,
990
690
  processLayout: renderer.renderData(rendererProps),
991
691
  label: {
992
692
  type:
993
693
  (c.children?.length ?? 0) > 0 ? LabelType.Group : LabelType.Control,
994
694
  label,
995
695
  forId: rendererProps.id,
996
- required: c.required && !props.formOptions.displayOnly,
696
+ required: c.required && !displayOnly,
997
697
  hide: c.hideTitle,
998
698
  className: rendererClass(labelClass, c.labelClass),
699
+ textClass: rendererClass(labelTextClass, c.labelTextClass),
999
700
  },
1000
701
  errorControl: control,
1001
702
  };
@@ -1010,6 +711,7 @@ type MarkupKeys = keyof Omit<
1010
711
  | "wrapLayout"
1011
712
  | "readonly"
1012
713
  | "disabled"
714
+ | "inline"
1013
715
  >;
1014
716
  export function appendMarkup(
1015
717
  k: MarkupKeys,
@@ -1071,13 +773,21 @@ export function renderLayoutParts(
1071
773
  props: ControlLayoutProps,
1072
774
  renderer: FormRenderer,
1073
775
  ): RenderedLayout {
1074
- const { className, children, style, errorControl, label, adornments } =
1075
- props.processLayout?.(props) ?? props;
776
+ const {
777
+ className,
778
+ children,
779
+ style,
780
+ errorControl,
781
+ label,
782
+ adornments,
783
+ inline,
784
+ } = props.processLayout?.(props) ?? props;
1076
785
  const layout: RenderedLayout = {
1077
786
  children,
1078
787
  errorControl,
1079
788
  style,
1080
789
  className: className!,
790
+ inline,
1081
791
  wrapLayout: (x) => x,
1082
792
  };
1083
793
  (adornments ?? [])
@@ -1269,14 +979,25 @@ export function applyArrayLengthRestrictions(
1269
979
  }
1270
980
 
1271
981
  export function fieldOptionAdornment(p: DataRendererProps) {
1272
- return (o: FieldOption, i: number, selected: boolean) => (
1273
- <RenderArrayElements array={p.formNode.getChildNodes()}>
1274
- {(cd, i) =>
982
+ return (o: FieldOption, fieldIndex: number, selected: boolean) => (
983
+ <RenderArrayElements
984
+ array={p.formNode.getChildNodes()}
985
+ children={(cd, i) =>
1275
986
  p.renderChild(i, cd, {
1276
987
  parentDataNode: p.dataContext.parentNode,
1277
- formData: { option: o, optionSelected: selected },
988
+ stateKey: fieldIndex.toString(),
989
+ variables: { formData: { option: o, optionSelected: selected } },
1278
990
  })
1279
991
  }
1280
- </RenderArrayElements>
992
+ />
1281
993
  );
1282
994
  }
995
+
996
+ export function lookupChildDataContext(
997
+ dataContext: ControlDataContext,
998
+ c: ControlDefinition,
999
+ ): ControlDataContext {
1000
+ const parentNode = dataContext.dataNode ?? dataContext.parentNode;
1001
+ const dataNode = lookupDataNode(c, parentNode);
1002
+ return { ...dataContext, parentNode, dataNode };
1003
+ }