@react-typed-forms/schemas 5.0.3 → 7.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/.rush/temp/shrinkwrap-deps.json +39 -11
- package/lib/controlBuilder.d.ts +2 -2
- package/lib/controlRender.d.ts +75 -21
- package/lib/hooks.d.ts +10 -6
- package/lib/index.d.ts +1 -0
- package/lib/index.js +511 -254
- package/lib/index.js.map +1 -1
- package/lib/internal.d.ts +1 -0
- package/lib/renderers.d.ts +21 -11
- package/lib/schemaInterface.d.ts +4 -0
- package/lib/types.d.ts +48 -8
- package/lib/util.d.ts +9 -6
- package/lib/validators.d.ts +2 -2
- package/package.json +2 -2
- package/src/controlBuilder.ts +3 -3
- package/src/controlRender.tsx +256 -167
- package/src/hooks.tsx +101 -16
- package/src/index.ts +1 -0
- package/src/internal.ts +4 -0
- package/src/renderers.tsx +224 -86
- package/src/schemaInterface.ts +31 -0
- package/src/tailwind.tsx +5 -1
- package/src/types.ts +62 -5
- package/src/util.ts +40 -19
- package/src/validators.ts +3 -3
package/src/renderers.tsx
CHANGED
|
@@ -3,7 +3,6 @@ import React, {
|
|
|
3
3
|
Fragment,
|
|
4
4
|
ReactElement,
|
|
5
5
|
ReactNode,
|
|
6
|
-
useCallback,
|
|
7
6
|
useEffect,
|
|
8
7
|
useMemo,
|
|
9
8
|
useState,
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
ActionRendererProps,
|
|
15
14
|
AdornmentProps,
|
|
16
15
|
AdornmentRenderer,
|
|
16
|
+
appendMarkupAt,
|
|
17
17
|
ArrayRendererProps,
|
|
18
18
|
ControlLayoutProps,
|
|
19
19
|
DataRendererProps,
|
|
@@ -22,18 +22,29 @@ import {
|
|
|
22
22
|
GroupRendererProps,
|
|
23
23
|
LabelRendererProps,
|
|
24
24
|
LabelType,
|
|
25
|
+
RenderedControl,
|
|
25
26
|
RenderedLayout,
|
|
26
27
|
renderLayoutParts,
|
|
27
|
-
|
|
28
|
+
VisibilityRendererProps,
|
|
28
29
|
} from "./controlRender";
|
|
29
30
|
import {
|
|
31
|
+
AdornmentPlacement,
|
|
32
|
+
ControlAdornment,
|
|
33
|
+
ControlAdornmentType,
|
|
30
34
|
DataRenderType,
|
|
31
35
|
DisplayDataType,
|
|
32
36
|
FieldOption,
|
|
33
37
|
FieldType,
|
|
38
|
+
FlexRenderer,
|
|
34
39
|
GridRenderer,
|
|
35
40
|
HtmlDisplay,
|
|
41
|
+
IconAdornment,
|
|
42
|
+
IconDisplay,
|
|
43
|
+
isDisplayOnlyRenderer,
|
|
44
|
+
isFlexRenderer,
|
|
36
45
|
isGridRenderer,
|
|
46
|
+
SchemaField,
|
|
47
|
+
SchemaInterface,
|
|
37
48
|
TextDisplay,
|
|
38
49
|
} from "./types";
|
|
39
50
|
import { hasOptions } from "./util";
|
|
@@ -53,7 +64,10 @@ export interface DefaultRenderers {
|
|
|
53
64
|
export interface LayoutRendererRegistration {
|
|
54
65
|
type: "layout";
|
|
55
66
|
match?: (props: ControlLayoutProps) => boolean;
|
|
56
|
-
render: (
|
|
67
|
+
render: (
|
|
68
|
+
props: ControlLayoutProps,
|
|
69
|
+
renderers: FormRenderer,
|
|
70
|
+
) => RenderedControl;
|
|
57
71
|
}
|
|
58
72
|
export interface DataRendererRegistration {
|
|
59
73
|
type: "data";
|
|
@@ -64,7 +78,6 @@ export interface DataRendererRegistration {
|
|
|
64
78
|
match?: (props: DataRendererProps) => boolean;
|
|
65
79
|
render: (
|
|
66
80
|
props: DataRendererProps,
|
|
67
|
-
asArray: (() => ReactNode) | undefined,
|
|
68
81
|
renderers: FormRenderer,
|
|
69
82
|
) => ReactNode | ((layout: ControlLayoutProps) => ControlLayoutProps);
|
|
70
83
|
}
|
|
@@ -94,7 +107,10 @@ export interface ArrayRendererRegistration {
|
|
|
94
107
|
export interface GroupRendererRegistration {
|
|
95
108
|
type: "group";
|
|
96
109
|
renderType?: string | string[];
|
|
97
|
-
render: (
|
|
110
|
+
render: (
|
|
111
|
+
props: GroupRendererProps,
|
|
112
|
+
renderers: FormRenderer,
|
|
113
|
+
) => ReactElement | ((layout: ControlLayoutProps) => ControlLayoutProps);
|
|
98
114
|
}
|
|
99
115
|
|
|
100
116
|
export interface DisplayRendererRegistration {
|
|
@@ -114,10 +130,7 @@ export interface AdornmentRendererRegistration {
|
|
|
114
130
|
|
|
115
131
|
export interface VisibilityRendererRegistration {
|
|
116
132
|
type: "visibility";
|
|
117
|
-
render: (
|
|
118
|
-
visibility: Control<Visibility | undefined>,
|
|
119
|
-
children: () => ReactNode,
|
|
120
|
-
) => ReactNode;
|
|
133
|
+
render: (props: VisibilityRendererProps) => ReactNode;
|
|
121
134
|
}
|
|
122
135
|
|
|
123
136
|
export type RendererRegistration =
|
|
@@ -196,7 +209,6 @@ export function createFormRenderer(
|
|
|
196
209
|
|
|
197
210
|
function renderData(
|
|
198
211
|
props: DataRendererProps,
|
|
199
|
-
asArray: (() => ReactNode) | undefined,
|
|
200
212
|
): (layout: ControlLayoutProps) => ControlLayoutProps {
|
|
201
213
|
const {
|
|
202
214
|
renderOptions: { type: renderType },
|
|
@@ -214,17 +226,21 @@ export function createFormRenderer(
|
|
|
214
226
|
(!x.match || x.match(props)),
|
|
215
227
|
) ?? defaultRenderers.data;
|
|
216
228
|
|
|
217
|
-
const result = renderer.render(props,
|
|
229
|
+
const result = renderer.render(props, formRenderers);
|
|
218
230
|
if (typeof result === "function") return result;
|
|
219
231
|
return (l) => ({ ...l, children: result });
|
|
220
232
|
}
|
|
221
233
|
|
|
222
|
-
function renderGroup(
|
|
234
|
+
function renderGroup(
|
|
235
|
+
props: GroupRendererProps,
|
|
236
|
+
): (layout: ControlLayoutProps) => ControlLayoutProps {
|
|
223
237
|
const renderType = props.renderOptions.type;
|
|
224
238
|
const renderer =
|
|
225
239
|
groupRegistrations.find((x) => isOneOf(x.renderType, renderType)) ??
|
|
226
240
|
defaultRenderers.group;
|
|
227
|
-
|
|
241
|
+
const result = renderer.render(props, formRenderers);
|
|
242
|
+
if (typeof result === "function") return result;
|
|
243
|
+
return (l) => ({ ...l, children: result });
|
|
228
244
|
}
|
|
229
245
|
|
|
230
246
|
function renderAction(props: ActionRendererProps) {
|
|
@@ -314,32 +330,32 @@ export function createDefaultArrayRenderer(
|
|
|
314
330
|
} = options ?? {};
|
|
315
331
|
function render(
|
|
316
332
|
{
|
|
317
|
-
|
|
318
|
-
|
|
333
|
+
elementCount,
|
|
334
|
+
renderElement,
|
|
319
335
|
addAction,
|
|
320
336
|
removeAction,
|
|
321
|
-
|
|
337
|
+
elementKey,
|
|
322
338
|
required,
|
|
323
339
|
}: ArrayRendererProps,
|
|
324
340
|
{ renderAction }: FormRenderer,
|
|
325
341
|
) {
|
|
326
|
-
const showRemove = !required ||
|
|
342
|
+
const showRemove = !required || elementCount > 1;
|
|
327
343
|
return (
|
|
328
344
|
<div>
|
|
329
345
|
<div className={clsx(className, removeAction && removableClass)}>
|
|
330
|
-
{Array.from({ length:
|
|
346
|
+
{Array.from({ length: elementCount }, (_, x) =>
|
|
331
347
|
removeAction ? (
|
|
332
|
-
<Fragment key={
|
|
348
|
+
<Fragment key={elementKey(x)}>
|
|
333
349
|
<div className={clsx(childClass, removableChildClass)}>
|
|
334
|
-
{
|
|
350
|
+
{renderElement(x)}
|
|
335
351
|
</div>
|
|
336
352
|
<div className={removeActionClass}>
|
|
337
353
|
{showRemove && renderAction(removeAction(x))}
|
|
338
354
|
</div>
|
|
339
355
|
</Fragment>
|
|
340
356
|
) : (
|
|
341
|
-
<div key={
|
|
342
|
-
{
|
|
357
|
+
<div key={elementKey(x)} className={childClass}>
|
|
358
|
+
{renderElement(x)}
|
|
343
359
|
</div>
|
|
344
360
|
),
|
|
345
361
|
)}
|
|
@@ -364,6 +380,8 @@ interface DefaultGroupRendererOptions {
|
|
|
364
380
|
gridStyles?: (columns: GridRenderer) => StyleProps;
|
|
365
381
|
gridClassName?: string;
|
|
366
382
|
defaultGridColumns?: number;
|
|
383
|
+
flexClassName?: string;
|
|
384
|
+
defaultFlexGap?: string;
|
|
367
385
|
}
|
|
368
386
|
|
|
369
387
|
export function createDefaultGroupRenderer(
|
|
@@ -375,6 +393,8 @@ export function createDefaultGroupRenderer(
|
|
|
375
393
|
defaultGridColumns = 2,
|
|
376
394
|
gridClassName,
|
|
377
395
|
standardClassName,
|
|
396
|
+
flexClassName,
|
|
397
|
+
defaultFlexGap,
|
|
378
398
|
} = options ?? {};
|
|
379
399
|
|
|
380
400
|
function defaultGridStyles({
|
|
@@ -389,17 +409,38 @@ export function createDefaultGroupRenderer(
|
|
|
389
409
|
};
|
|
390
410
|
}
|
|
391
411
|
|
|
412
|
+
function flexStyles(options: FlexRenderer): StyleProps {
|
|
413
|
+
return {
|
|
414
|
+
className: flexClassName,
|
|
415
|
+
style: {
|
|
416
|
+
display: "flex",
|
|
417
|
+
gap: options.gap ? options.gap : defaultFlexGap,
|
|
418
|
+
flexDirection: options.direction
|
|
419
|
+
? (options.direction as any)
|
|
420
|
+
: undefined,
|
|
421
|
+
},
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
392
425
|
function render(props: GroupRendererProps) {
|
|
393
426
|
const { childCount, renderChild, renderOptions } = props;
|
|
394
427
|
|
|
395
428
|
const { style, className: gcn } = isGridRenderer(renderOptions)
|
|
396
429
|
? gridStyles(renderOptions)
|
|
430
|
+
: isFlexRenderer(renderOptions)
|
|
431
|
+
? flexStyles(renderOptions)
|
|
397
432
|
: ({ className: standardClassName } as StyleProps);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
433
|
+
|
|
434
|
+
return (cp: ControlLayoutProps) => {
|
|
435
|
+
return {
|
|
436
|
+
...cp,
|
|
437
|
+
children: (
|
|
438
|
+
<div className={clsx(props.className, className, gcn)} style={style}>
|
|
439
|
+
{Array.from({ length: childCount }, (_, x) => renderChild(x))}
|
|
440
|
+
</div>
|
|
441
|
+
),
|
|
442
|
+
};
|
|
443
|
+
};
|
|
403
444
|
}
|
|
404
445
|
return { type: "group", render };
|
|
405
446
|
}
|
|
@@ -412,37 +453,57 @@ export function createDefaultDisplayRenderer(
|
|
|
412
453
|
options: DefaultDisplayRendererOptions = {},
|
|
413
454
|
): DisplayRendererRegistration {
|
|
414
455
|
return {
|
|
415
|
-
render: (
|
|
416
|
-
switch (data.type) {
|
|
417
|
-
case DisplayDataType.Text:
|
|
418
|
-
return (
|
|
419
|
-
<div className={options.textClassName}>
|
|
420
|
-
{(data as TextDisplay).text}
|
|
421
|
-
</div>
|
|
422
|
-
);
|
|
423
|
-
case DisplayDataType.Html:
|
|
424
|
-
return (
|
|
425
|
-
<div
|
|
426
|
-
className={options.htmlClassName}
|
|
427
|
-
dangerouslySetInnerHTML={{
|
|
428
|
-
__html: (data as HtmlDisplay).html,
|
|
429
|
-
}}
|
|
430
|
-
/>
|
|
431
|
-
);
|
|
432
|
-
default:
|
|
433
|
-
return <h1>Unknown display type: {data.type}</h1>;
|
|
434
|
-
}
|
|
435
|
-
},
|
|
456
|
+
render: (props) => <DefaultDisplay {...options} {...props} />,
|
|
436
457
|
type: "display",
|
|
437
458
|
};
|
|
438
459
|
}
|
|
439
460
|
|
|
461
|
+
export function DefaultDisplay({
|
|
462
|
+
data,
|
|
463
|
+
display,
|
|
464
|
+
className,
|
|
465
|
+
style,
|
|
466
|
+
...options
|
|
467
|
+
}: DefaultDisplayRendererOptions & DisplayRendererProps) {
|
|
468
|
+
switch (data.type) {
|
|
469
|
+
case DisplayDataType.Icon:
|
|
470
|
+
return (
|
|
471
|
+
<i
|
|
472
|
+
style={style}
|
|
473
|
+
className={clsx(
|
|
474
|
+
className,
|
|
475
|
+
display ? display.value : (data as IconDisplay).iconClass,
|
|
476
|
+
)}
|
|
477
|
+
/>
|
|
478
|
+
);
|
|
479
|
+
case DisplayDataType.Text:
|
|
480
|
+
return (
|
|
481
|
+
<div style={style} className={clsx(className, options.textClassName)}>
|
|
482
|
+
{display ? display.value : (data as TextDisplay).text}
|
|
483
|
+
</div>
|
|
484
|
+
);
|
|
485
|
+
case DisplayDataType.Html:
|
|
486
|
+
return (
|
|
487
|
+
<div
|
|
488
|
+
style={style}
|
|
489
|
+
className={clsx(className, options.htmlClassName)}
|
|
490
|
+
dangerouslySetInnerHTML={{
|
|
491
|
+
__html: display ? display.value ?? "" : (data as HtmlDisplay).html,
|
|
492
|
+
}}
|
|
493
|
+
/>
|
|
494
|
+
);
|
|
495
|
+
default:
|
|
496
|
+
return <h1>Unknown display type: {data.type}</h1>;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
440
500
|
export const DefaultBoolOptions: FieldOption[] = [
|
|
441
501
|
{ name: "Yes", value: true },
|
|
442
502
|
{ name: "No", value: false },
|
|
443
503
|
];
|
|
444
504
|
interface DefaultDataRendererOptions {
|
|
445
505
|
inputClass?: string;
|
|
506
|
+
displayOnlyClass?: string;
|
|
446
507
|
selectOptions?: SelectRendererOptions;
|
|
447
508
|
booleanOptions?: FieldOption[];
|
|
448
509
|
optionRenderer?: DataRendererRegistration;
|
|
@@ -452,37 +513,67 @@ export function createDefaultDataRenderer(
|
|
|
452
513
|
options: DefaultDataRendererOptions = {},
|
|
453
514
|
): DataRendererRegistration {
|
|
454
515
|
const selectRenderer = createSelectRenderer(options.selectOptions ?? {});
|
|
455
|
-
const { inputClass, booleanOptions, optionRenderer } = {
|
|
516
|
+
const { inputClass, booleanOptions, optionRenderer, displayOnlyClass } = {
|
|
456
517
|
optionRenderer: selectRenderer,
|
|
457
518
|
booleanOptions: DefaultBoolOptions,
|
|
458
519
|
...options,
|
|
459
520
|
};
|
|
460
|
-
return createDataRenderer((props,
|
|
461
|
-
if (asArray) {
|
|
462
|
-
return asArray();
|
|
463
|
-
}
|
|
464
|
-
let renderType = props.renderOptions.type;
|
|
521
|
+
return createDataRenderer((props, renderers) => {
|
|
465
522
|
const fieldType = props.field.type;
|
|
523
|
+
if (props.toArrayProps) {
|
|
524
|
+
return (p) => ({
|
|
525
|
+
...p,
|
|
526
|
+
children: renderers.renderArray(props.toArrayProps!()),
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
if (fieldType === FieldType.Compound) {
|
|
530
|
+
return renderers.renderGroup({
|
|
531
|
+
style: props.style,
|
|
532
|
+
className: props.className,
|
|
533
|
+
renderOptions: { type: "Standard", hideTitle: true },
|
|
534
|
+
renderChild: (i) => props.renderChild(i, i, { control: props.control }),
|
|
535
|
+
childCount: props.childCount,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
const renderOptions = props.renderOptions;
|
|
539
|
+
let renderType = renderOptions.type;
|
|
466
540
|
if (fieldType == FieldType.Any) return <>No control for Any</>;
|
|
541
|
+
if (isDisplayOnlyRenderer(renderOptions))
|
|
542
|
+
return (p) => ({
|
|
543
|
+
...p,
|
|
544
|
+
className: displayOnlyClass,
|
|
545
|
+
children: (
|
|
546
|
+
<DefaultDisplayOnly
|
|
547
|
+
field={props.field}
|
|
548
|
+
schemaInterface={props.dataContext.schemaInterface}
|
|
549
|
+
control={props.control}
|
|
550
|
+
className={props.className}
|
|
551
|
+
style={props.style}
|
|
552
|
+
emptyText={renderOptions.emptyText}
|
|
553
|
+
/>
|
|
554
|
+
),
|
|
555
|
+
});
|
|
467
556
|
const isBool = fieldType === FieldType.Bool;
|
|
468
557
|
if (booleanOptions != null && isBool && props.options == null) {
|
|
469
|
-
return renderers.renderData(
|
|
470
|
-
{ ...props, options: booleanOptions },
|
|
471
|
-
undefined,
|
|
472
|
-
);
|
|
558
|
+
return renderers.renderData({ ...props, options: booleanOptions });
|
|
473
559
|
}
|
|
474
560
|
if (renderType === DataRenderType.Standard && hasOptions(props)) {
|
|
475
|
-
return optionRenderer.render(props,
|
|
561
|
+
return optionRenderer.render(props, renderers);
|
|
476
562
|
}
|
|
477
563
|
switch (renderType) {
|
|
478
564
|
case DataRenderType.Dropdown:
|
|
479
|
-
return selectRenderer.render(props,
|
|
565
|
+
return selectRenderer.render(props, renderers);
|
|
480
566
|
}
|
|
481
567
|
return renderType === DataRenderType.Checkbox ? (
|
|
482
|
-
<Fcheckbox
|
|
568
|
+
<Fcheckbox
|
|
569
|
+
style={props.style}
|
|
570
|
+
className={props.className}
|
|
571
|
+
control={props.control}
|
|
572
|
+
/>
|
|
483
573
|
) : (
|
|
484
574
|
<ControlInput
|
|
485
|
-
className={inputClass}
|
|
575
|
+
className={clsx(props.className, inputClass)}
|
|
576
|
+
style={props.style}
|
|
486
577
|
id={props.id}
|
|
487
578
|
readOnly={props.readonly}
|
|
488
579
|
control={props.control}
|
|
@@ -492,6 +583,33 @@ export function createDefaultDataRenderer(
|
|
|
492
583
|
});
|
|
493
584
|
}
|
|
494
585
|
|
|
586
|
+
export function DefaultDisplayOnly({
|
|
587
|
+
control,
|
|
588
|
+
className,
|
|
589
|
+
emptyText,
|
|
590
|
+
schemaInterface,
|
|
591
|
+
field,
|
|
592
|
+
style,
|
|
593
|
+
}: {
|
|
594
|
+
control: Control<any>;
|
|
595
|
+
field: SchemaField;
|
|
596
|
+
schemaInterface: SchemaInterface;
|
|
597
|
+
className?: string;
|
|
598
|
+
style?: React.CSSProperties;
|
|
599
|
+
emptyText?: string | null;
|
|
600
|
+
}) {
|
|
601
|
+
const v = control.value;
|
|
602
|
+
const text =
|
|
603
|
+
(schemaInterface.isEmptyValue(field, v)
|
|
604
|
+
? emptyText
|
|
605
|
+
: schemaInterface.textValue(field, v)) ?? "";
|
|
606
|
+
return (
|
|
607
|
+
<div style={style} className={className}>
|
|
608
|
+
{text}
|
|
609
|
+
</div>
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
|
|
495
613
|
export function ControlInput({
|
|
496
614
|
control,
|
|
497
615
|
convert,
|
|
@@ -522,7 +640,18 @@ export function createDefaultAdornmentRenderer(
|
|
|
522
640
|
): AdornmentRendererRegistration {
|
|
523
641
|
return {
|
|
524
642
|
type: "adornment",
|
|
525
|
-
render: ({ adornment }) => ({
|
|
643
|
+
render: ({ adornment }) => ({
|
|
644
|
+
apply: (rl) => {
|
|
645
|
+
if (isIconAdornment(adornment)) {
|
|
646
|
+
return appendMarkupAt(
|
|
647
|
+
adornment.placement ?? AdornmentPlacement.ControlStart,
|
|
648
|
+
<i className={adornment.iconClass} />,
|
|
649
|
+
)(rl);
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
priority: 0,
|
|
653
|
+
adornment,
|
|
654
|
+
}),
|
|
526
655
|
};
|
|
527
656
|
}
|
|
528
657
|
|
|
@@ -562,12 +691,19 @@ function createDefaultLayoutRenderer(
|
|
|
562
691
|
options: DefaultLayoutRendererOptions = {},
|
|
563
692
|
) {
|
|
564
693
|
return createLayoutRenderer((props, renderers) => {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
{...options}
|
|
569
|
-
/>
|
|
694
|
+
const layout = renderLayoutParts(
|
|
695
|
+
{ ...props, className: clsx(props.className, options.className) },
|
|
696
|
+
renderers,
|
|
570
697
|
);
|
|
698
|
+
return {
|
|
699
|
+
children: <DefaultLayout layout={layout} {...options} />,
|
|
700
|
+
className: layout.className,
|
|
701
|
+
style: layout.style,
|
|
702
|
+
divRef: (e) =>
|
|
703
|
+
e && props.errorControl
|
|
704
|
+
? (props.errorControl.meta.scrollElement = e)
|
|
705
|
+
: undefined,
|
|
706
|
+
};
|
|
571
707
|
});
|
|
572
708
|
}
|
|
573
709
|
|
|
@@ -639,6 +775,10 @@ function isOneOf<A>(x: A | A[] | undefined, v: A) {
|
|
|
639
775
|
return x == null ? true : Array.isArray(x) ? x.includes(v) : v === x;
|
|
640
776
|
}
|
|
641
777
|
|
|
778
|
+
export function isIconAdornment(a: ControlAdornment): a is IconAdornment {
|
|
779
|
+
return a.type === ControlAdornmentType.Icon;
|
|
780
|
+
}
|
|
781
|
+
|
|
642
782
|
export function createLayoutRenderer(
|
|
643
783
|
render: LayoutRendererRegistration["render"],
|
|
644
784
|
options?: Partial<LayoutRendererRegistration>,
|
|
@@ -691,7 +831,7 @@ export function createSelectRenderer(options: SelectRendererOptions = {}) {
|
|
|
691
831
|
return createDataRenderer(
|
|
692
832
|
(props, asArray) => (
|
|
693
833
|
<SelectDataRenderer
|
|
694
|
-
className={options.className}
|
|
834
|
+
className={clsx(props.className, options.className)}
|
|
695
835
|
state={props.control}
|
|
696
836
|
id={props.id}
|
|
697
837
|
options={props.options!}
|
|
@@ -795,49 +935,47 @@ export function createInputConversion(ft: string): InputConversion {
|
|
|
795
935
|
}
|
|
796
936
|
|
|
797
937
|
export function createDefaultVisibilityRenderer() {
|
|
798
|
-
return createVisibilityRenderer((
|
|
799
|
-
<DefaultVisibility visibility={cv} children={ch} />
|
|
800
|
-
));
|
|
938
|
+
return createVisibilityRenderer((props) => <DefaultVisibility {...props} />);
|
|
801
939
|
}
|
|
802
940
|
|
|
803
941
|
export function DefaultVisibility({
|
|
804
942
|
visibility,
|
|
805
943
|
children,
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
}) {
|
|
944
|
+
className,
|
|
945
|
+
style,
|
|
946
|
+
divRef,
|
|
947
|
+
}: VisibilityRendererProps) {
|
|
810
948
|
const v = visibility.value;
|
|
811
949
|
useEffect(() => {
|
|
812
950
|
if (v) {
|
|
813
951
|
visibility.setValue((ex) => ({ visible: v.visible, showing: v.visible }));
|
|
814
952
|
}
|
|
815
953
|
}, [v?.visible]);
|
|
816
|
-
return v?.visible ?
|
|
954
|
+
return v?.visible ? (
|
|
955
|
+
<div className={clsx(className)} style={style} ref={divRef}>
|
|
956
|
+
{children}
|
|
957
|
+
</div>
|
|
958
|
+
) : (
|
|
959
|
+
<></>
|
|
960
|
+
);
|
|
817
961
|
}
|
|
818
962
|
|
|
819
963
|
export function DefaultLayout({
|
|
820
|
-
className,
|
|
821
964
|
errorClass,
|
|
965
|
+
className,
|
|
822
966
|
layout: { controlEnd, controlStart, label, children, errorControl },
|
|
823
967
|
}: DefaultLayoutRendererOptions & {
|
|
824
968
|
layout: RenderedLayout;
|
|
825
969
|
}) {
|
|
826
970
|
const ec = errorControl;
|
|
827
971
|
const errorText = ec && ec.touched ? ec.error : undefined;
|
|
828
|
-
const refCb = useCallback(
|
|
829
|
-
(e: HTMLDivElement | null) => {
|
|
830
|
-
if (ec) ec.meta.scrollElement = e;
|
|
831
|
-
},
|
|
832
|
-
[ec],
|
|
833
|
-
);
|
|
834
972
|
return (
|
|
835
|
-
|
|
973
|
+
<>
|
|
836
974
|
{label}
|
|
837
975
|
{controlStart}
|
|
838
976
|
{children}
|
|
839
977
|
{errorText && <div className={errorClass}>{errorText}</div>}
|
|
840
978
|
{controlEnd}
|
|
841
|
-
|
|
979
|
+
</>
|
|
842
980
|
);
|
|
843
981
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { FieldType, SchemaField, SchemaInterface } from "./types";
|
|
2
|
+
|
|
3
|
+
export const defaultSchemaInterface: SchemaInterface = {
|
|
4
|
+
isEmptyValue: defaultIsEmpty,
|
|
5
|
+
textValue: defaultTextValue,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function defaultIsEmpty(f: SchemaField, value: any): boolean {
|
|
9
|
+
if (f.collection)
|
|
10
|
+
return Array.isArray(value) ? value.length === 0 : value == null;
|
|
11
|
+
switch (f.type) {
|
|
12
|
+
case FieldType.String:
|
|
13
|
+
return !value;
|
|
14
|
+
default:
|
|
15
|
+
return value == null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function defaultTextValue(
|
|
20
|
+
f: SchemaField,
|
|
21
|
+
value: any,
|
|
22
|
+
): string | undefined {
|
|
23
|
+
switch (f.type) {
|
|
24
|
+
case FieldType.DateTime:
|
|
25
|
+
return new Date(value).toLocaleDateString();
|
|
26
|
+
case FieldType.Date:
|
|
27
|
+
return new Date(value).toLocaleDateString();
|
|
28
|
+
default:
|
|
29
|
+
return value != null ? value.toString() : undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/tailwind.tsx
CHANGED
|
@@ -12,8 +12,9 @@ export const defaultTailwindTheme: DefaultRendererOptions = {
|
|
|
12
12
|
addActionClass: "my-2",
|
|
13
13
|
},
|
|
14
14
|
group: {
|
|
15
|
-
standardClassName: "
|
|
15
|
+
standardClassName: "flex flex-col gap-4",
|
|
16
16
|
gridClassName: "gap-x-2 gap-y-4",
|
|
17
|
+
flexClassName: "gap-2",
|
|
17
18
|
},
|
|
18
19
|
action: {
|
|
19
20
|
className: "bg-primary rounded-lg p-3 text-white",
|
|
@@ -22,4 +23,7 @@ export const defaultTailwindTheme: DefaultRendererOptions = {
|
|
|
22
23
|
className: "flex flex-col",
|
|
23
24
|
errorClass: "text-sm text-danger-500",
|
|
24
25
|
},
|
|
26
|
+
data: {
|
|
27
|
+
displayOnlyClass: "flex flex-row items-center gap-2",
|
|
28
|
+
},
|
|
25
29
|
};
|