@react-typed-forms/schemas 7.3.2 → 8.1.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 +6 -0
- package/lib/controlRender.d.ts +16 -9
- package/lib/hooks.d.ts +1 -0
- package/lib/index.js +206 -94
- package/lib/index.js.map +1 -1
- package/lib/renderers.d.ts +2 -1
- package/lib/schemaBuilder.d.ts +1 -0
- package/lib/tailwind.d.ts +27 -2
- package/lib/types.d.ts +3 -1
- package/lib/util.d.ts +4 -1
- package/package.json +1 -1
- package/src/controlBuilder.ts +46 -1
- package/src/controlRender.tsx +69 -44
- package/src/hooks.tsx +24 -3
- package/src/renderers.tsx +33 -22
- package/src/schemaBuilder.ts +25 -0
- package/src/tailwind.tsx +2 -2
- package/src/types.ts +3 -1
- package/src/util.ts +38 -3
package/lib/renderers.d.ts
CHANGED
|
@@ -65,6 +65,7 @@ export declare function createFormRenderer(customRenderers?: RendererRegistratio
|
|
|
65
65
|
interface DefaultLabelRendererOptions {
|
|
66
66
|
className?: string;
|
|
67
67
|
groupLabelClass?: string;
|
|
68
|
+
controlLabelClass?: string;
|
|
68
69
|
requiredElement?: ReactNode;
|
|
69
70
|
}
|
|
70
71
|
interface DefaultActionRendererOptions {
|
|
@@ -174,7 +175,7 @@ type InputConversion = [string, (s: any) => any, (a: any) => string | number];
|
|
|
174
175
|
export declare function createInputConversion(ft: string): InputConversion;
|
|
175
176
|
export declare function createDefaultVisibilityRenderer(): VisibilityRendererRegistration;
|
|
176
177
|
export declare function DefaultVisibility({ visibility, children, className, style, divRef, }: VisibilityRendererProps): React.JSX.Element;
|
|
177
|
-
export declare function DefaultLayout({ errorClass,
|
|
178
|
+
export declare function DefaultLayout({ errorClass, layout: { controlEnd, controlStart, label, children, errorControl }, }: DefaultLayoutRendererOptions & {
|
|
178
179
|
layout: RenderedLayout;
|
|
179
180
|
}): React.JSX.Element;
|
|
180
181
|
export {};
|
package/lib/schemaBuilder.d.ts
CHANGED
|
@@ -87,4 +87,5 @@ export declare function defaultScalarField(field: string, displayName: string):
|
|
|
87
87
|
export declare function defaultCompoundField(field: string, displayName: string, collection: boolean): CompoundField & {
|
|
88
88
|
type: FieldType.Compound;
|
|
89
89
|
};
|
|
90
|
+
export declare function mergeField(field: SchemaField, mergeInto: SchemaField[]): SchemaField[];
|
|
90
91
|
export {};
|
package/lib/tailwind.d.ts
CHANGED
|
@@ -1,2 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
export declare const defaultTailwindTheme:
|
|
1
|
+
import React from "react";
|
|
2
|
+
export declare const defaultTailwindTheme: {
|
|
3
|
+
label: {
|
|
4
|
+
groupLabelClass: string;
|
|
5
|
+
requiredElement: React.JSX.Element;
|
|
6
|
+
};
|
|
7
|
+
array: {
|
|
8
|
+
removableClass: string;
|
|
9
|
+
childClass: string;
|
|
10
|
+
addActionClass: string;
|
|
11
|
+
};
|
|
12
|
+
group: {
|
|
13
|
+
standardClassName: string;
|
|
14
|
+
gridClassName: string;
|
|
15
|
+
flexClassName: string;
|
|
16
|
+
};
|
|
17
|
+
action: {
|
|
18
|
+
className: string;
|
|
19
|
+
};
|
|
20
|
+
layout: {
|
|
21
|
+
className: string;
|
|
22
|
+
errorClass: string;
|
|
23
|
+
};
|
|
24
|
+
data: {
|
|
25
|
+
displayOnlyClass: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
package/lib/types.d.ts
CHANGED
|
@@ -51,6 +51,7 @@ export interface ControlDefinition {
|
|
|
51
51
|
title?: string | null;
|
|
52
52
|
styleClass?: string | null;
|
|
53
53
|
layoutClass?: string | null;
|
|
54
|
+
labelClass?: string | null;
|
|
54
55
|
dynamic?: DynamicProperty[] | null;
|
|
55
56
|
adornments?: ControlAdornment[] | null;
|
|
56
57
|
children?: ControlDefinition[] | null;
|
|
@@ -73,7 +74,8 @@ export declare enum DynamicPropertyType {
|
|
|
73
74
|
Display = "Display",
|
|
74
75
|
Style = "Style",
|
|
75
76
|
LayoutStyle = "LayoutStyle",
|
|
76
|
-
AllowedOptions = "AllowedOptions"
|
|
77
|
+
AllowedOptions = "AllowedOptions",
|
|
78
|
+
Label = "Label"
|
|
77
79
|
}
|
|
78
80
|
export interface EntityExpression {
|
|
79
81
|
type: string;
|
package/lib/util.d.ts
CHANGED
|
@@ -38,4 +38,7 @@ export declare function cleanDataForSchema(v: {
|
|
|
38
38
|
[k: string]: any;
|
|
39
39
|
} | undefined, fields: SchemaField[]): any;
|
|
40
40
|
export declare function getAllReferencedClasses(c: ControlDefinition): string[];
|
|
41
|
-
export declare function jsonPathString(jsonPath: JsonPath[]): string;
|
|
41
|
+
export declare function jsonPathString(jsonPath: JsonPath[], customIndex?: (n: number) => string): string;
|
|
42
|
+
export declare function findChildDefinition(parent: ControlDefinition, childPath: number | number[]): ControlDefinition;
|
|
43
|
+
export declare function getOverrideClass(className?: string | null): string | null | undefined;
|
|
44
|
+
export declare function rendererClass(controlClass?: string | null, globalClass?: string | null): string | undefined;
|
package/package.json
CHANGED
package/src/controlBuilder.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
CompoundField,
|
|
2
3
|
ControlDefinition,
|
|
3
4
|
ControlDefinitionType,
|
|
4
5
|
DataControlDefinition,
|
|
@@ -18,7 +19,8 @@ import {
|
|
|
18
19
|
} from "./types";
|
|
19
20
|
import { ActionRendererProps } from "./controlRender";
|
|
20
21
|
import { useMemo } from "react";
|
|
21
|
-
import { addMissingControls } from "./util";
|
|
22
|
+
import { addMissingControls, isCompoundField } from "./util";
|
|
23
|
+
import { mergeField } from "./schemaBuilder";
|
|
22
24
|
|
|
23
25
|
export function dataControl(
|
|
24
26
|
field: string,
|
|
@@ -128,3 +130,46 @@ export function useControlDefinitionForSchema(
|
|
|
128
130
|
[sf, definition],
|
|
129
131
|
);
|
|
130
132
|
}
|
|
133
|
+
|
|
134
|
+
export interface CustomRenderOptions {
|
|
135
|
+
value: string;
|
|
136
|
+
name: string;
|
|
137
|
+
fields: SchemaField[];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function addCustomDataRenderOptions(
|
|
141
|
+
controlFields: SchemaField[],
|
|
142
|
+
customRenderOptions: CustomRenderOptions[],
|
|
143
|
+
): SchemaField[] {
|
|
144
|
+
return controlFields.map((x) =>
|
|
145
|
+
x.field === "renderOptions" && isCompoundField(x) ? addRenderOptions(x) : x,
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
function addRenderOptions(roField: CompoundField): CompoundField {
|
|
149
|
+
const children = roField.children;
|
|
150
|
+
const withTypes = children.map((x) =>
|
|
151
|
+
x.field === "type" ? addRenderOptionType(x) : x,
|
|
152
|
+
);
|
|
153
|
+
return {
|
|
154
|
+
...roField,
|
|
155
|
+
children: customRenderOptions.reduce(
|
|
156
|
+
(renderOptionFields, ro) =>
|
|
157
|
+
ro.fields
|
|
158
|
+
.map((x) => ({ ...x, onlyForTypes: [ro.value] }))
|
|
159
|
+
.reduce((af, x) => mergeField(x, af), renderOptionFields),
|
|
160
|
+
withTypes,
|
|
161
|
+
),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function addRenderOptionType(typeField: SchemaField): SchemaField {
|
|
166
|
+
const options = typeField.options ?? [];
|
|
167
|
+
return {
|
|
168
|
+
...typeField,
|
|
169
|
+
options: [
|
|
170
|
+
...options,
|
|
171
|
+
...customRenderOptions.map(({ name, value }) => ({ name, value })),
|
|
172
|
+
],
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
package/src/controlRender.tsx
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
DisplayData,
|
|
27
27
|
DynamicPropertyType,
|
|
28
28
|
FieldOption,
|
|
29
|
+
GroupedControlsDefinition,
|
|
29
30
|
GroupRenderOptions,
|
|
30
31
|
isActionControlsDefinition,
|
|
31
32
|
isDataControlDefinition,
|
|
@@ -39,6 +40,7 @@ import {
|
|
|
39
40
|
ControlDataContext,
|
|
40
41
|
elementValueForField,
|
|
41
42
|
fieldDisplayName,
|
|
43
|
+
findChildDefinition,
|
|
42
44
|
findField,
|
|
43
45
|
isCompoundField,
|
|
44
46
|
useUpdatedRef,
|
|
@@ -51,6 +53,7 @@ import {
|
|
|
51
53
|
useEvalDisabledHook,
|
|
52
54
|
useEvalDisplayHook,
|
|
53
55
|
UseEvalExpressionHook,
|
|
56
|
+
useEvalLabelText,
|
|
54
57
|
useEvalReadonlyHook,
|
|
55
58
|
useEvalStyleHook,
|
|
56
59
|
useEvalVisibilityHook,
|
|
@@ -99,7 +102,7 @@ export interface ArrayRendererProps {
|
|
|
99
102
|
elementCount: number;
|
|
100
103
|
renderElement: (elemIndex: number) => ReactNode;
|
|
101
104
|
elementKey: (elemIndex: number) => Key;
|
|
102
|
-
arrayControl
|
|
105
|
+
arrayControl: Control<any[] | undefined | null>;
|
|
103
106
|
className?: string;
|
|
104
107
|
style?: React.CSSProperties;
|
|
105
108
|
}
|
|
@@ -151,6 +154,7 @@ export interface LabelRendererProps {
|
|
|
151
154
|
label: ReactNode;
|
|
152
155
|
required?: boolean | null;
|
|
153
156
|
forId?: string;
|
|
157
|
+
className?: string;
|
|
154
158
|
}
|
|
155
159
|
export interface DisplayRendererProps {
|
|
156
160
|
data: DisplayData;
|
|
@@ -160,15 +164,14 @@ export interface DisplayRendererProps {
|
|
|
160
164
|
}
|
|
161
165
|
|
|
162
166
|
export interface GroupRendererProps {
|
|
167
|
+
children: ControlDefinition[];
|
|
163
168
|
renderOptions: GroupRenderOptions;
|
|
164
|
-
|
|
165
|
-
renderChild: (child: number) => ReactNode;
|
|
169
|
+
renderChild: ChildRenderer;
|
|
166
170
|
className?: string;
|
|
167
171
|
style?: React.CSSProperties;
|
|
168
172
|
}
|
|
169
173
|
|
|
170
174
|
export interface DataRendererProps {
|
|
171
|
-
definition: DataControlDefinition;
|
|
172
175
|
renderOptions: RenderOptions;
|
|
173
176
|
field: SchemaField;
|
|
174
177
|
id: string;
|
|
@@ -180,7 +183,7 @@ export interface DataRendererProps {
|
|
|
180
183
|
className?: string;
|
|
181
184
|
style?: React.CSSProperties;
|
|
182
185
|
dataContext: ControlDataContext;
|
|
183
|
-
|
|
186
|
+
children: ControlDefinition[];
|
|
184
187
|
renderChild: ChildRenderer;
|
|
185
188
|
toArrayProps?: () => ArrayRendererProps;
|
|
186
189
|
}
|
|
@@ -211,7 +214,6 @@ export interface DataControlProps {
|
|
|
211
214
|
control: Control<any>;
|
|
212
215
|
options: FormContextOptions;
|
|
213
216
|
style: React.CSSProperties | undefined;
|
|
214
|
-
childCount: number;
|
|
215
217
|
renderChild: ChildRenderer;
|
|
216
218
|
allowedOptions?: Control<any[] | undefined>;
|
|
217
219
|
elementRenderer?: (elemIndex: number) => ReactNode;
|
|
@@ -252,6 +254,7 @@ export function useControlRenderer(
|
|
|
252
254
|
const useIsReadonly = useEvalReadonlyHook(useExpr, definition);
|
|
253
255
|
const useIsDisabled = useEvalDisabledHook(useExpr, definition);
|
|
254
256
|
const useAllowedOptions = useEvalAllowedOptionsHook(useExpr, definition);
|
|
257
|
+
const useLabelText = useEvalLabelText(useExpr, definition);
|
|
255
258
|
const useCustomStyle = useEvalStyleHook(
|
|
256
259
|
useExpr,
|
|
257
260
|
DynamicPropertyType.Style,
|
|
@@ -283,6 +286,7 @@ export function useControlRenderer(
|
|
|
283
286
|
const displayControl = useDynamicDisplay(parentDataContext);
|
|
284
287
|
const customStyle = useCustomStyle(parentDataContext).value;
|
|
285
288
|
const layoutStyle = useLayoutStyle(parentDataContext).value;
|
|
289
|
+
const labelText = useLabelText(parentDataContext);
|
|
286
290
|
const visible = visibleControl.current.value;
|
|
287
291
|
const visibility = useControl<Visibility | undefined>(() =>
|
|
288
292
|
visible != null
|
|
@@ -343,13 +347,7 @@ export function useControlRenderer(
|
|
|
343
347
|
!!myOptions.hidden,
|
|
344
348
|
parentDataContext,
|
|
345
349
|
);
|
|
346
|
-
const
|
|
347
|
-
c.children?.map((cd) =>
|
|
348
|
-
useControlRenderer(cd, controlDataContext.fields, renderer, {
|
|
349
|
-
...options,
|
|
350
|
-
...myOptions,
|
|
351
|
-
}),
|
|
352
|
-
) ?? [];
|
|
350
|
+
const childOptions: ControlRenderOptions = { ...options, ...myOptions };
|
|
353
351
|
|
|
354
352
|
useEffect(() => {
|
|
355
353
|
if (control && typeof myOptions.disabled === "boolean")
|
|
@@ -364,15 +362,26 @@ export function useControlRenderer(
|
|
|
364
362
|
const labelAndChildren = renderControlLayout({
|
|
365
363
|
definition: c,
|
|
366
364
|
renderer,
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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
|
+
),
|
|
372
380
|
createDataProps: dataProps,
|
|
373
381
|
formOptions: myOptions,
|
|
374
382
|
dataContext: controlDataContext,
|
|
375
383
|
control: displayControl ?? control,
|
|
384
|
+
labelText,
|
|
376
385
|
schemaField,
|
|
377
386
|
displayControl,
|
|
378
387
|
style: customStyle,
|
|
@@ -399,6 +408,7 @@ export function useControlRenderer(
|
|
|
399
408
|
useCustomStyle,
|
|
400
409
|
useLayoutStyle,
|
|
401
410
|
useAllowedOptions,
|
|
411
|
+
useLabelText,
|
|
402
412
|
useDynamicDisplay,
|
|
403
413
|
useValidation,
|
|
404
414
|
renderer,
|
|
@@ -445,19 +455,36 @@ export function getControlData(
|
|
|
445
455
|
];
|
|
446
456
|
}
|
|
447
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
|
+
|
|
448
477
|
function groupProps(
|
|
449
|
-
|
|
450
|
-
childCount: number,
|
|
478
|
+
definition: GroupedControlsDefinition,
|
|
451
479
|
renderChild: ChildRenderer,
|
|
452
480
|
data: DataContext,
|
|
453
481
|
className: string | null | undefined,
|
|
454
482
|
style: React.CSSProperties | undefined,
|
|
455
483
|
): GroupRendererProps {
|
|
456
484
|
return {
|
|
457
|
-
|
|
458
|
-
renderChild
|
|
459
|
-
|
|
460
|
-
renderOptions,
|
|
485
|
+
children: definition.children ?? [],
|
|
486
|
+
renderChild,
|
|
487
|
+
renderOptions: definition.groupOptions ?? { type: "Standard" },
|
|
461
488
|
className: cc(className),
|
|
462
489
|
style,
|
|
463
490
|
};
|
|
@@ -479,7 +506,7 @@ export function defaultDataProps({
|
|
|
479
506
|
(field.options?.length ?? 0) === 0 ? null : field.options;
|
|
480
507
|
const allowed = allowedOptions?.value ?? [];
|
|
481
508
|
return {
|
|
482
|
-
definition,
|
|
509
|
+
children: definition.children ?? [],
|
|
483
510
|
control,
|
|
484
511
|
field,
|
|
485
512
|
id: "c" + control.uniqueId,
|
|
@@ -541,19 +568,19 @@ export function defaultArrayProps(
|
|
|
541
568
|
|
|
542
569
|
export type ChildRenderer = (
|
|
543
570
|
k: Key,
|
|
544
|
-
|
|
545
|
-
|
|
571
|
+
child: number | number[],
|
|
572
|
+
parentPath?: JsonPath[],
|
|
546
573
|
) => ReactNode;
|
|
547
574
|
|
|
548
575
|
export interface RenderControlProps {
|
|
549
576
|
definition: ControlDefinition;
|
|
550
577
|
renderer: FormRenderer;
|
|
551
|
-
childCount: number;
|
|
552
578
|
renderChild: ChildRenderer;
|
|
553
579
|
createDataProps: CreateDataProps;
|
|
554
580
|
formOptions: FormContextOptions;
|
|
555
581
|
dataContext: ControlDataContext;
|
|
556
582
|
control?: Control<any>;
|
|
583
|
+
labelText?: Control<string | null | undefined>;
|
|
557
584
|
schemaField?: SchemaField;
|
|
558
585
|
displayControl?: Control<string | undefined>;
|
|
559
586
|
style?: React.CSSProperties;
|
|
@@ -562,7 +589,6 @@ export interface RenderControlProps {
|
|
|
562
589
|
export function renderControlLayout({
|
|
563
590
|
definition: c,
|
|
564
591
|
renderer,
|
|
565
|
-
childCount,
|
|
566
592
|
renderChild: childRenderer,
|
|
567
593
|
control: childControl,
|
|
568
594
|
schemaField,
|
|
@@ -571,6 +597,7 @@ export function renderControlLayout({
|
|
|
571
597
|
createDataProps: dataProps,
|
|
572
598
|
displayControl,
|
|
573
599
|
style,
|
|
600
|
+
labelText,
|
|
574
601
|
allowedOptions,
|
|
575
602
|
}: RenderControlProps): ControlLayoutProps {
|
|
576
603
|
if (isDataControlDefinition(c)) {
|
|
@@ -587,17 +614,11 @@ export function renderControlLayout({
|
|
|
587
614
|
}
|
|
588
615
|
return {
|
|
589
616
|
processLayout: renderer.renderGroup(
|
|
590
|
-
groupProps(
|
|
591
|
-
c.groupOptions,
|
|
592
|
-
childCount,
|
|
593
|
-
childRenderer,
|
|
594
|
-
dataContext,
|
|
595
|
-
c.styleClass,
|
|
596
|
-
style,
|
|
597
|
-
),
|
|
617
|
+
groupProps(c, childRenderer, dataContext, c.styleClass, style),
|
|
598
618
|
),
|
|
599
619
|
label: {
|
|
600
|
-
label: c.title,
|
|
620
|
+
label: labelText?.value ?? c.title,
|
|
621
|
+
className: cc(c.labelClass),
|
|
601
622
|
type: LabelType.Group,
|
|
602
623
|
hide: c.groupOptions?.hideTitle,
|
|
603
624
|
},
|
|
@@ -606,7 +627,7 @@ export function renderControlLayout({
|
|
|
606
627
|
if (isActionControlsDefinition(c)) {
|
|
607
628
|
return {
|
|
608
629
|
children: renderer.renderAction({
|
|
609
|
-
actionText: c.title ?? c.actionId,
|
|
630
|
+
actionText: labelText?.value ?? c.title ?? c.actionId,
|
|
610
631
|
actionId: c.actionId,
|
|
611
632
|
onClick: () => {},
|
|
612
633
|
className: cc(c.styleClass),
|
|
@@ -640,26 +661,30 @@ export function renderControlLayout({
|
|
|
640
661
|
elemIndex != null ? childControl!.elements[elemIndex] : childControl,
|
|
641
662
|
options: dataOptions,
|
|
642
663
|
style,
|
|
643
|
-
childCount,
|
|
644
664
|
allowedOptions,
|
|
645
|
-
renderChild:
|
|
665
|
+
renderChild:
|
|
666
|
+
elemIndex != null
|
|
667
|
+
? (k, d, p) =>
|
|
668
|
+
childRenderer(k, d, p ? [elemIndex, ...p] : [elemIndex])
|
|
669
|
+
: childRenderer,
|
|
646
670
|
elementRenderer:
|
|
647
671
|
elemIndex == null && schemaField.collection
|
|
648
672
|
? (ei) => renderLayoutParts(renderData(c, ei), renderer).children
|
|
649
673
|
: undefined,
|
|
650
674
|
});
|
|
651
675
|
|
|
652
|
-
const
|
|
653
|
-
? controlTitle(c.title, schemaField)
|
|
676
|
+
const label = !c.hideTitle
|
|
677
|
+
? controlTitle(labelText?.value ?? c.title, schemaField)
|
|
654
678
|
: undefined;
|
|
655
679
|
return {
|
|
656
680
|
processLayout: renderer.renderData(props),
|
|
657
681
|
label: {
|
|
658
682
|
type: LabelType.Control,
|
|
659
|
-
label
|
|
683
|
+
label,
|
|
660
684
|
forId: props.id,
|
|
661
685
|
required: c.required,
|
|
662
686
|
hide: c.hideTitle,
|
|
687
|
+
className: cc(c.labelClass),
|
|
663
688
|
},
|
|
664
689
|
errorControl: childControl,
|
|
665
690
|
};
|
package/src/hooks.tsx
CHANGED
|
@@ -306,15 +306,16 @@ export function useJsonataExpression(
|
|
|
306
306
|
dataContext: DataContext,
|
|
307
307
|
bindings?: () => Record<string, any>,
|
|
308
308
|
): Control<any> {
|
|
309
|
-
const pathString = jsonPathString(dataContext.path);
|
|
309
|
+
const pathString = jsonPathString(dataContext.path, (x) => `#$i[${x}]`);
|
|
310
|
+
const fullExpr = pathString ? pathString + ".(" + jExpr + ")" : jExpr;
|
|
310
311
|
const compiledExpr = useMemo(() => {
|
|
311
312
|
try {
|
|
312
|
-
return jsonata(
|
|
313
|
+
return jsonata(fullExpr);
|
|
313
314
|
} catch (e) {
|
|
314
315
|
console.error(e);
|
|
315
316
|
return jsonata("null");
|
|
316
317
|
}
|
|
317
|
-
}, [
|
|
318
|
+
}, [fullExpr]);
|
|
318
319
|
const control = useControl();
|
|
319
320
|
const listenerRef = useRef<() => void>();
|
|
320
321
|
const [ref] = useRefState(() =>
|
|
@@ -350,3 +351,23 @@ export function useJsonataExpression(
|
|
|
350
351
|
}, [compiledExpr]);
|
|
351
352
|
return control;
|
|
352
353
|
}
|
|
354
|
+
|
|
355
|
+
export function useEvalLabelText(
|
|
356
|
+
useExpr: UseEvalExpressionHook,
|
|
357
|
+
definition: ControlDefinition,
|
|
358
|
+
): EvalExpressionHook<string | null> {
|
|
359
|
+
const dynamicValue = useEvalDynamicHook(
|
|
360
|
+
definition,
|
|
361
|
+
DynamicPropertyType.Label,
|
|
362
|
+
useExpr,
|
|
363
|
+
);
|
|
364
|
+
return useCallback(
|
|
365
|
+
(ctx) => {
|
|
366
|
+
if (dynamicValue) {
|
|
367
|
+
return dynamicValue(ctx);
|
|
368
|
+
}
|
|
369
|
+
return useControl(null);
|
|
370
|
+
},
|
|
371
|
+
[dynamicValue],
|
|
372
|
+
);
|
|
373
|
+
}
|
package/src/renderers.tsx
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
AdornmentPlacement,
|
|
32
32
|
ControlAdornment,
|
|
33
33
|
ControlAdornmentType,
|
|
34
|
+
ControlDefinitionType,
|
|
34
35
|
DataRenderType,
|
|
35
36
|
DisplayDataType,
|
|
36
37
|
FieldOption,
|
|
@@ -47,7 +48,7 @@ import {
|
|
|
47
48
|
SchemaInterface,
|
|
48
49
|
TextDisplay,
|
|
49
50
|
} from "./types";
|
|
50
|
-
import { hasOptions } from "./util";
|
|
51
|
+
import { getOverrideClass, hasOptions, rendererClass } from "./util";
|
|
51
52
|
|
|
52
53
|
export interface DefaultRenderers {
|
|
53
54
|
data: DataRendererRegistration;
|
|
@@ -264,6 +265,7 @@ export function createFormRenderer(
|
|
|
264
265
|
interface DefaultLabelRendererOptions {
|
|
265
266
|
className?: string;
|
|
266
267
|
groupLabelClass?: string;
|
|
268
|
+
controlLabelClass?: string;
|
|
267
269
|
requiredElement?: ReactNode;
|
|
268
270
|
}
|
|
269
271
|
|
|
@@ -286,16 +288,21 @@ export function createDefaultActionRenderer(
|
|
|
286
288
|
export function createDefaultLabelRenderer(
|
|
287
289
|
options: DefaultLabelRendererOptions = { requiredElement: <span> *</span> },
|
|
288
290
|
): LabelRendererRegistration {
|
|
289
|
-
const { className, groupLabelClass, requiredElement } =
|
|
291
|
+
const { className, groupLabelClass, controlLabelClass, requiredElement } =
|
|
292
|
+
options;
|
|
290
293
|
return {
|
|
291
294
|
render: (props, labelStart, labelEnd) => (
|
|
292
295
|
<>
|
|
293
296
|
{labelStart}
|
|
294
297
|
<label
|
|
295
298
|
htmlFor={props.forId}
|
|
296
|
-
className={
|
|
297
|
-
className,
|
|
298
|
-
|
|
299
|
+
className={rendererClass(
|
|
300
|
+
props.className,
|
|
301
|
+
clsx(
|
|
302
|
+
className,
|
|
303
|
+
props.type === LabelType.Group && groupLabelClass,
|
|
304
|
+
props.type === LabelType.Control && controlLabelClass,
|
|
305
|
+
),
|
|
299
306
|
)}
|
|
300
307
|
>
|
|
301
308
|
{props.label}
|
|
@@ -423,7 +430,7 @@ export function createDefaultGroupRenderer(
|
|
|
423
430
|
}
|
|
424
431
|
|
|
425
432
|
function render(props: GroupRendererProps) {
|
|
426
|
-
const {
|
|
433
|
+
const { renderChild, renderOptions, children } = props;
|
|
427
434
|
|
|
428
435
|
const { style, className: gcn } = isGridRenderer(renderOptions)
|
|
429
436
|
? gridStyles(renderOptions)
|
|
@@ -435,8 +442,11 @@ export function createDefaultGroupRenderer(
|
|
|
435
442
|
return {
|
|
436
443
|
...cp,
|
|
437
444
|
children: (
|
|
438
|
-
<div
|
|
439
|
-
{
|
|
445
|
+
<div
|
|
446
|
+
className={rendererClass(props.className, clsx(className, gcn))}
|
|
447
|
+
style={style}
|
|
448
|
+
>
|
|
449
|
+
{children?.map((c, i) => renderChild(i, i))}
|
|
440
450
|
</div>
|
|
441
451
|
),
|
|
442
452
|
};
|
|
@@ -471,14 +481,17 @@ export function DefaultDisplay({
|
|
|
471
481
|
<i
|
|
472
482
|
style={style}
|
|
473
483
|
className={clsx(
|
|
474
|
-
className,
|
|
484
|
+
getOverrideClass(className),
|
|
475
485
|
display ? display.value : (data as IconDisplay).iconClass,
|
|
476
486
|
)}
|
|
477
487
|
/>
|
|
478
488
|
);
|
|
479
489
|
case DisplayDataType.Text:
|
|
480
490
|
return (
|
|
481
|
-
<div
|
|
491
|
+
<div
|
|
492
|
+
style={style}
|
|
493
|
+
className={rendererClass(className, options.textClassName)}
|
|
494
|
+
>
|
|
482
495
|
{display ? display.value : (data as TextDisplay).text}
|
|
483
496
|
</div>
|
|
484
497
|
);
|
|
@@ -486,7 +499,7 @@ export function DefaultDisplay({
|
|
|
486
499
|
return (
|
|
487
500
|
<div
|
|
488
501
|
style={style}
|
|
489
|
-
className={
|
|
502
|
+
className={rendererClass(className, options.htmlClassName)}
|
|
490
503
|
dangerouslySetInnerHTML={{
|
|
491
504
|
__html: display ? display.value ?? "" : (data as HtmlDisplay).html,
|
|
492
505
|
}}
|
|
@@ -530,13 +543,9 @@ export function createDefaultDataRenderer(
|
|
|
530
543
|
return renderers.renderGroup({
|
|
531
544
|
style: props.style,
|
|
532
545
|
className: props.className,
|
|
546
|
+
children: props.children,
|
|
533
547
|
renderOptions: { type: "Standard", hideTitle: true },
|
|
534
|
-
renderChild:
|
|
535
|
-
props.renderChild(i, i, {
|
|
536
|
-
control: props.dataContext.data,
|
|
537
|
-
parentPath: props.dataContext.path,
|
|
538
|
-
}),
|
|
539
|
-
childCount: props.childCount,
|
|
548
|
+
renderChild: props.renderChild,
|
|
540
549
|
});
|
|
541
550
|
}
|
|
542
551
|
const renderOptions = props.renderOptions;
|
|
@@ -576,7 +585,7 @@ export function createDefaultDataRenderer(
|
|
|
576
585
|
/>
|
|
577
586
|
) : (
|
|
578
587
|
<ControlInput
|
|
579
|
-
className={
|
|
588
|
+
className={rendererClass(props.className, inputClass)}
|
|
580
589
|
style={props.style}
|
|
581
590
|
id={props.id}
|
|
582
591
|
readOnly={props.readonly}
|
|
@@ -608,7 +617,7 @@ export function DefaultDisplayOnly({
|
|
|
608
617
|
? emptyText
|
|
609
618
|
: schemaInterface.textValue(field, v)) ?? "";
|
|
610
619
|
return (
|
|
611
|
-
<div style={style} className={className}>
|
|
620
|
+
<div style={style} className={rendererClass(className)}>
|
|
612
621
|
{text}
|
|
613
622
|
</div>
|
|
614
623
|
);
|
|
@@ -696,7 +705,10 @@ function createDefaultLayoutRenderer(
|
|
|
696
705
|
) {
|
|
697
706
|
return createLayoutRenderer((props, renderers) => {
|
|
698
707
|
const layout = renderLayoutParts(
|
|
699
|
-
{
|
|
708
|
+
{
|
|
709
|
+
...props,
|
|
710
|
+
className: rendererClass(props.className, options.className),
|
|
711
|
+
},
|
|
700
712
|
renderers,
|
|
701
713
|
);
|
|
702
714
|
return {
|
|
@@ -835,7 +847,7 @@ export function createSelectRenderer(options: SelectRendererOptions = {}) {
|
|
|
835
847
|
return createDataRenderer(
|
|
836
848
|
(props, asArray) => (
|
|
837
849
|
<SelectDataRenderer
|
|
838
|
-
className={
|
|
850
|
+
className={rendererClass(props.className, options.className)}
|
|
839
851
|
state={props.control}
|
|
840
852
|
id={props.id}
|
|
841
853
|
options={props.options!}
|
|
@@ -966,7 +978,6 @@ export function DefaultVisibility({
|
|
|
966
978
|
|
|
967
979
|
export function DefaultLayout({
|
|
968
980
|
errorClass,
|
|
969
|
-
className,
|
|
970
981
|
layout: { controlEnd, controlStart, label, children, errorControl },
|
|
971
982
|
}: DefaultLayoutRendererOptions & {
|
|
972
983
|
layout: RenderedLayout;
|
package/src/schemaBuilder.ts
CHANGED
|
@@ -144,3 +144,28 @@ export function defaultCompoundField(
|
|
|
144
144
|
children: [],
|
|
145
145
|
};
|
|
146
146
|
}
|
|
147
|
+
|
|
148
|
+
export function mergeField(
|
|
149
|
+
field: SchemaField,
|
|
150
|
+
mergeInto: SchemaField[],
|
|
151
|
+
): SchemaField[] {
|
|
152
|
+
const existing = mergeInto.find((x) => x.field === field.field);
|
|
153
|
+
if (existing) {
|
|
154
|
+
return mergeInto.map((x) =>
|
|
155
|
+
x !== existing
|
|
156
|
+
? x
|
|
157
|
+
: {
|
|
158
|
+
...x,
|
|
159
|
+
onlyForTypes: mergeTypes(x.onlyForTypes, field.onlyForTypes),
|
|
160
|
+
},
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
return [...mergeInto, field];
|
|
164
|
+
|
|
165
|
+
function mergeTypes(f?: string[] | null, s?: string[] | null) {
|
|
166
|
+
if (!f) return s;
|
|
167
|
+
if (!s) return f;
|
|
168
|
+
const extras = s.filter((x) => !f.includes(x));
|
|
169
|
+
return extras.length ? [...f, ...extras] : f;
|
|
170
|
+
}
|
|
171
|
+
}
|