@astroapps/forms-core 1.0.1

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.
@@ -0,0 +1,704 @@
1
+ import { SchemaValidator } from "./schemaValidator";
2
+ import { SchemaField } from "./schemaField";
3
+ import { EntityExpression } from "./entityExpression";
4
+ import { SchemaDataNode } from "./schemaDataNode";
5
+ import { SchemaNode } from "./schemaNode";
6
+
7
+ /**
8
+ * Represents any control definition.
9
+ */
10
+ export type AnyControlDefinition =
11
+ | DataControlDefinition
12
+ | GroupedControlsDefinition
13
+ | ActionControlDefinition
14
+ | DisplayControlDefinition;
15
+
16
+ /**
17
+ * Represents a control definition.
18
+ */
19
+ export interface ControlDefinition {
20
+ type: string;
21
+ id?: string | null;
22
+ childRefId?: string | null;
23
+ title?: string | null;
24
+ hidden?: boolean | null;
25
+ styleClass?: string | null;
26
+ textClass?: string | null;
27
+ layoutClass?: string | null;
28
+ labelClass?: string | null;
29
+ labelTextClass?: string | null;
30
+ placement?: string | null;
31
+ dynamic?: DynamicProperty[] | null;
32
+ adornments?: ControlAdornment[] | null;
33
+ children?: ControlDefinition[] | null;
34
+ }
35
+
36
+ export enum ControlDefinitionType {
37
+ Data = "Data",
38
+ Group = "Group",
39
+ Display = "Display",
40
+ Action = "Action",
41
+ }
42
+
43
+ export interface DynamicProperty {
44
+ type: string;
45
+ expr: EntityExpression;
46
+ }
47
+
48
+ export enum DynamicPropertyType {
49
+ Visible = "Visible",
50
+ DefaultValue = "DefaultValue",
51
+ Readonly = "Readonly",
52
+ Disabled = "Disabled",
53
+ Display = "Display",
54
+ Style = "Style",
55
+ LayoutStyle = "LayoutStyle",
56
+ AllowedOptions = "AllowedOptions",
57
+ Label = "Label",
58
+ ActionData = "ActionData",
59
+ }
60
+
61
+ export interface ControlAdornment {
62
+ type: string;
63
+ }
64
+
65
+ export enum AdornmentPlacement {
66
+ ControlStart = "ControlStart",
67
+ ControlEnd = "ControlEnd",
68
+ LabelStart = "LabelStart",
69
+ LabelEnd = "LabelEnd",
70
+ }
71
+
72
+ export enum ControlAdornmentType {
73
+ Tooltip = "Tooltip",
74
+ Accordion = "Accordion",
75
+ HelpText = "HelpText",
76
+ Icon = "Icon",
77
+ SetField = "SetField",
78
+ Optional = "Optional",
79
+ }
80
+
81
+ export enum IconLibrary {
82
+ FontAwesome = "FontAwesome",
83
+ Material = "Material",
84
+ CssClass = "CssClass",
85
+ }
86
+
87
+ export interface IconReference {
88
+ library: string;
89
+ name: string;
90
+ }
91
+
92
+ export interface IconAdornment extends ControlAdornment {
93
+ type: ControlAdornmentType.Icon;
94
+ iconClass: string;
95
+ icon?: IconReference;
96
+ placement?: AdornmentPlacement | null;
97
+ }
98
+
99
+ export interface TooltipAdornment extends ControlAdornment {
100
+ type: ControlAdornmentType.Tooltip;
101
+ tooltip: string;
102
+ }
103
+
104
+ export interface AccordionAdornment extends ControlAdornment {
105
+ type: ControlAdornmentType.Accordion;
106
+ title: string;
107
+ defaultExpanded?: boolean | null;
108
+ }
109
+
110
+ export interface HelpTextAdornment extends ControlAdornment {
111
+ type: ControlAdornmentType.HelpText;
112
+ helpText: string;
113
+ placement?: AdornmentPlacement | null;
114
+ }
115
+
116
+ export interface SetFieldAdornment extends ControlAdornment {
117
+ type: ControlAdornmentType.SetField;
118
+ field: string;
119
+ defaultOnly?: boolean | null;
120
+ expression?: EntityExpression;
121
+ }
122
+
123
+ export interface OptionalAdornment extends ControlAdornment {
124
+ type: ControlAdornmentType.Optional;
125
+ placement?: AdornmentPlacement | null;
126
+ allowNull?: boolean;
127
+ editSelectable?: boolean;
128
+ }
129
+
130
+ export interface DataControlDefinition extends ControlDefinition {
131
+ type: ControlDefinitionType.Data;
132
+ field: string;
133
+ required?: boolean | null;
134
+ renderOptions?: RenderOptions | null;
135
+ defaultValue?: any;
136
+ readonly?: boolean | null;
137
+ disabled?: boolean | null;
138
+ validators?: SchemaValidator[] | null;
139
+ hideTitle?: boolean | null;
140
+ dontClearHidden?: boolean | null;
141
+ }
142
+
143
+ export interface RenderOptions {
144
+ type: string;
145
+ }
146
+
147
+ export enum DataRenderType {
148
+ Standard = "Standard",
149
+ Textfield = "Textfield",
150
+ Radio = "Radio",
151
+ HtmlEditor = "HtmlEditor",
152
+ IconList = "IconList",
153
+ CheckList = "CheckList",
154
+ UserSelection = "UserSelection",
155
+ Synchronised = "Synchronised",
156
+ IconSelector = "IconSelector",
157
+ DateTime = "DateTime",
158
+ Checkbox = "Checkbox",
159
+ Dropdown = "Dropdown",
160
+ DisplayOnly = "DisplayOnly",
161
+ Group = "Group",
162
+ NullToggle = "NullToggle",
163
+ Autocomplete = "Autocomplete",
164
+ Jsonata = "Jsonata",
165
+ Array = "Array",
166
+ ArrayElement = "ArrayElement",
167
+ ElementSelected = "ElementSelected",
168
+ }
169
+
170
+ export interface TextfieldRenderOptions extends RenderOptions {
171
+ type: DataRenderType.Textfield;
172
+ placeholder?: string | null;
173
+ multiline?: boolean | null;
174
+ }
175
+
176
+ export interface AutocompleteRenderOptions
177
+ extends RenderOptions,
178
+ AutocompleteClasses {
179
+ type: DataRenderType.Autocomplete;
180
+ }
181
+
182
+ export interface AutocompleteClasses {
183
+ listContainerClass?: string | null;
184
+ listEntryClass?: string | null;
185
+ chipContainerClass?: string | null;
186
+ chipCloseButtonClass?: string | null;
187
+ placeholder?: string | null;
188
+ }
189
+
190
+ export interface CheckEntryClasses {
191
+ entryWrapperClass?: string | null;
192
+ selectedClass?: string | null;
193
+ notSelectedClass?: string | null;
194
+ }
195
+ export interface RadioButtonRenderOptions
196
+ extends RenderOptions,
197
+ CheckEntryClasses {
198
+ type: DataRenderType.Radio;
199
+ }
200
+
201
+ export interface StandardRenderer extends RenderOptions {
202
+ type: DataRenderType.Standard;
203
+ }
204
+
205
+ export interface DataGroupRenderOptions extends RenderOptions {
206
+ type: DataRenderType.Group;
207
+ groupOptions?: GroupRenderOptions;
208
+ }
209
+
210
+ export interface HtmlEditorRenderOptions extends RenderOptions {
211
+ type: DataRenderType.HtmlEditor;
212
+ allowImages: boolean;
213
+ }
214
+
215
+ export interface DateTimeRenderOptions extends RenderOptions {
216
+ type: DataRenderType.DateTime;
217
+ format?: string | null;
218
+ forceMidnight?: boolean;
219
+ forceStandard?: boolean;
220
+ }
221
+
222
+ export interface IconListRenderOptions extends RenderOptions {
223
+ type: DataRenderType.IconList;
224
+ iconMappings: IconMapping[];
225
+ }
226
+
227
+ export interface DisplayOnlyRenderOptions extends RenderOptions {
228
+ type: DataRenderType.DisplayOnly;
229
+ emptyText?: string | null;
230
+ sampleText?: string | null;
231
+ }
232
+ export interface IconMapping {
233
+ value: string;
234
+ materialIcon?: string | null;
235
+ }
236
+
237
+ export interface JsonataRenderOptions extends RenderOptions {
238
+ type: DataRenderType.Jsonata;
239
+ expression: string;
240
+ }
241
+
242
+ export interface JsonataRenderOptions extends RenderOptions {
243
+ type: DataRenderType.Jsonata;
244
+ expression: string;
245
+ }
246
+
247
+ export interface ArrayRenderOptions extends RenderOptions {
248
+ type: DataRenderType.Array;
249
+ addText?: string | null;
250
+ addActionId?: string | null;
251
+ removeText?: string | null;
252
+ removeActionId?: string | null;
253
+ editText?: string | null;
254
+ editActionId?: string | null;
255
+ noAdd?: boolean | null;
256
+ noRemove?: boolean | null;
257
+ noReorder?: boolean | null;
258
+ editExternal?: boolean | null;
259
+ }
260
+
261
+ export interface ArrayElementRenderOptions extends RenderOptions {
262
+ type: DataRenderType.ArrayElement;
263
+ showInline?: boolean | null;
264
+ }
265
+
266
+ export interface ElementSelectedRenderOptions extends RenderOptions {
267
+ type: DataRenderType.ElementSelected;
268
+ elementExpression: EntityExpression;
269
+ }
270
+
271
+ export type ArrayActionOptions = Pick<
272
+ ArrayRenderOptions,
273
+ | "addText"
274
+ | "addActionId"
275
+ | "removeText"
276
+ | "removeActionId"
277
+ | "noAdd"
278
+ | "noRemove"
279
+ | "noReorder"
280
+ | "editExternal"
281
+ | "editActionId"
282
+ | "editText"
283
+ > & { readonly?: boolean; disabled?: boolean; designMode?: boolean };
284
+
285
+ export interface CheckListRenderOptions
286
+ extends RenderOptions,
287
+ CheckEntryClasses {
288
+ type: DataRenderType.CheckList;
289
+ }
290
+
291
+ export interface SynchronisedRenderOptions extends RenderOptions {
292
+ type: DataRenderType.Synchronised;
293
+ fieldToSync: string;
294
+ syncType: SyncTextType;
295
+ }
296
+
297
+ export enum SyncTextType {
298
+ Camel = "Camel",
299
+ Snake = "Snake",
300
+ Pascal = "Pascal",
301
+ }
302
+
303
+ export interface UserSelectionRenderOptions extends RenderOptions {
304
+ type: DataRenderType.UserSelection;
305
+ noGroups: boolean;
306
+ noUsers: boolean;
307
+ }
308
+
309
+ export interface IconSelectionRenderOptions extends RenderOptions {
310
+ type: DataRenderType.IconSelector;
311
+ }
312
+
313
+ export interface GroupedControlsDefinition extends ControlDefinition {
314
+ type: ControlDefinitionType.Group;
315
+ compoundField?: string | null;
316
+ groupOptions?: GroupRenderOptions;
317
+ }
318
+
319
+ export interface GroupRenderOptions {
320
+ type: string;
321
+ hideTitle?: boolean | null;
322
+ childStyleClass?: string | null;
323
+ childLayoutClass?: string | null;
324
+ childLabelClass?: string | null;
325
+ displayOnly?: boolean | null;
326
+ }
327
+
328
+ export interface ActionOptions {
329
+ actionId: string;
330
+ actionText?: string | null;
331
+ actionData?: string | null;
332
+ icon?: IconReference | null;
333
+ actionStyle?: ActionStyle | null;
334
+ iconPlacement?: IconPlacement | null;
335
+ }
336
+ export enum GroupRenderType {
337
+ Standard = "Standard",
338
+ Grid = "Grid",
339
+ Flex = "Flex",
340
+ Tabs = "Tabs",
341
+ GroupElement = "GroupElement",
342
+ SelectChild = "SelectChild",
343
+ Inline = "Inline",
344
+ Wizard = "Wizard",
345
+ Dialog = "Dialog",
346
+ Contents = "Contents",
347
+ }
348
+
349
+ export interface DialogRenderOptions extends GroupRenderOptions {
350
+ type: GroupRenderType.Dialog;
351
+ title?: string | null;
352
+ }
353
+
354
+ export interface StandardGroupRenderer extends GroupRenderOptions {
355
+ type: GroupRenderType.Standard;
356
+ }
357
+
358
+ export interface FlexRenderer extends GroupRenderOptions {
359
+ type: GroupRenderType.Flex;
360
+ direction?: string | null;
361
+ gap?: string | null;
362
+ }
363
+
364
+ export interface GroupElementRenderer extends GroupRenderOptions {
365
+ type: GroupRenderType.GroupElement;
366
+ value: any;
367
+ }
368
+
369
+ export interface GridRenderer extends GroupRenderOptions {
370
+ type: GroupRenderType.Grid;
371
+ columns?: number | null;
372
+ rowClass?: string | null;
373
+ }
374
+
375
+ export interface TabsRenderOptions extends GroupRenderOptions {
376
+ type: GroupRenderType.Tabs;
377
+ contentClass?: string;
378
+ }
379
+
380
+ export interface WizardRenderOptions extends GroupRenderOptions {
381
+ type: GroupRenderType.Wizard;
382
+ }
383
+
384
+ export interface SelectChildRenderer extends GroupRenderOptions {
385
+ type: GroupRenderType.SelectChild;
386
+ childIndexExpression?: EntityExpression | null;
387
+ }
388
+
389
+ export interface DisplayControlDefinition extends ControlDefinition {
390
+ type: ControlDefinitionType.Display;
391
+ displayData: DisplayData;
392
+ }
393
+
394
+ export interface DisplayData {
395
+ type: string;
396
+ }
397
+
398
+ export enum DisplayDataType {
399
+ Text = "Text",
400
+ Html = "Html",
401
+ Icon = "Icon",
402
+ Custom = "Custom",
403
+ }
404
+ export interface TextDisplay extends DisplayData {
405
+ type: DisplayDataType.Text;
406
+ text: string;
407
+ }
408
+
409
+ export interface IconDisplay extends DisplayData {
410
+ type: DisplayDataType.Icon;
411
+ iconClass: string;
412
+ icon?: IconReference | null;
413
+ }
414
+
415
+ export interface HtmlDisplay extends DisplayData {
416
+ type: DisplayDataType.Html;
417
+ html: string;
418
+ }
419
+
420
+ export interface CustomDisplay extends DisplayData {
421
+ type: DisplayDataType.Custom;
422
+ customId: string;
423
+ }
424
+
425
+ export interface ActionControlDefinition extends ControlDefinition {
426
+ type: ControlDefinitionType.Action;
427
+ actionId: string;
428
+ actionData?: string | null;
429
+ icon?: IconReference | null;
430
+ actionStyle?: ActionStyle | null;
431
+ iconPlacement?: IconPlacement | null;
432
+ }
433
+
434
+ export enum ActionStyle {
435
+ Button = "Button",
436
+ Secondary = "Secondary",
437
+ Link = "Link",
438
+ Group = "Group",
439
+ }
440
+
441
+ export enum IconPlacement {
442
+ BeforeText = "BeforeText",
443
+ AfterText = "AfterText",
444
+ ReplaceText = "ReplaceText",
445
+ }
446
+
447
+ export interface ControlVisitor<A> {
448
+ data(d: DataControlDefinition): A;
449
+ group(d: GroupedControlsDefinition): A;
450
+ display(d: DisplayControlDefinition): A;
451
+ action(d: ActionControlDefinition): A;
452
+ }
453
+
454
+ export function visitControlDefinition<A>(
455
+ x: ControlDefinition,
456
+ visitor: ControlVisitor<A>,
457
+ defaultValue: (c: ControlDefinition) => A,
458
+ ): A {
459
+ switch (x.type) {
460
+ case ControlDefinitionType.Action:
461
+ return visitor.action(x as ActionControlDefinition);
462
+ case ControlDefinitionType.Data:
463
+ return visitor.data(x as DataControlDefinition);
464
+ case ControlDefinitionType.Display:
465
+ return visitor.display(x as DisplayControlDefinition);
466
+ case ControlDefinitionType.Group:
467
+ return visitor.group(x as GroupedControlsDefinition);
468
+ default:
469
+ return defaultValue(x);
470
+ }
471
+ }
472
+ export function isGridRenderer(
473
+ options: GroupRenderOptions,
474
+ ): options is GridRenderer {
475
+ return options.type === GroupRenderType.Grid;
476
+ }
477
+
478
+ export function isWizardRenderer(
479
+ options: GroupRenderOptions,
480
+ ): options is WizardRenderOptions {
481
+ return options.type === GroupRenderType.Wizard;
482
+ }
483
+
484
+ export function isDialogRenderer(
485
+ options: GroupRenderOptions,
486
+ ): options is DialogRenderOptions {
487
+ return options.type === GroupRenderType.Dialog;
488
+ }
489
+
490
+ export function isInlineRenderer(
491
+ options: GroupRenderOptions,
492
+ ): options is GridRenderer {
493
+ return options.type === GroupRenderType.Inline;
494
+ }
495
+
496
+ export function isSelectChildRenderer(
497
+ options: GroupRenderOptions,
498
+ ): options is SelectChildRenderer {
499
+ return options.type === GroupRenderType.SelectChild;
500
+ }
501
+
502
+ export function isTabsRenderer(
503
+ options: GroupRenderOptions,
504
+ ): options is TabsRenderOptions {
505
+ return options.type === GroupRenderType.Tabs;
506
+ }
507
+
508
+ export function isFlexRenderer(
509
+ options: GroupRenderOptions,
510
+ ): options is FlexRenderer {
511
+ return options.type === GroupRenderType.Flex;
512
+ }
513
+
514
+ export function isDisplayOnlyRenderer(
515
+ options: RenderOptions,
516
+ ): options is DisplayOnlyRenderOptions {
517
+ return options.type === DataRenderType.DisplayOnly;
518
+ }
519
+
520
+ export function isTextfieldRenderer(
521
+ options: RenderOptions,
522
+ ): options is TextfieldRenderOptions {
523
+ return options.type === DataRenderType.Textfield;
524
+ }
525
+
526
+ export function isDateTimeRenderer(
527
+ options: RenderOptions,
528
+ ): options is DateTimeRenderOptions {
529
+ return options.type === DataRenderType.DateTime;
530
+ }
531
+
532
+ export function isAutocompleteRenderer(
533
+ options: RenderOptions,
534
+ ): options is AutocompleteRenderOptions {
535
+ return options.type === DataRenderType.Autocomplete;
536
+ }
537
+
538
+ export function isAutoCompleteClasses(
539
+ options?: RenderOptions | null,
540
+ ): options is AutocompleteClasses & RenderOptions {
541
+ switch (options?.type) {
542
+ case DataRenderType.Autocomplete:
543
+ return true;
544
+ default:
545
+ return false;
546
+ }
547
+ }
548
+
549
+ export function isDataGroupRenderer(
550
+ options?: RenderOptions | null,
551
+ ): options is DataGroupRenderOptions {
552
+ return options?.type === DataRenderType.Group;
553
+ }
554
+
555
+ export function isArrayRenderer(
556
+ options: RenderOptions,
557
+ ): options is ArrayRenderOptions {
558
+ return options.type === DataRenderType.Array;
559
+ }
560
+
561
+ export function isDataControl(
562
+ c: ControlDefinition,
563
+ ): c is DataControlDefinition {
564
+ return c.type === ControlDefinitionType.Data;
565
+ }
566
+
567
+ export function isGroupControl(
568
+ c: ControlDefinition,
569
+ ): c is GroupedControlsDefinition {
570
+ return c.type === ControlDefinitionType.Group;
571
+ }
572
+
573
+ export function isActionControl(
574
+ c: ControlDefinition,
575
+ ): c is ActionControlDefinition {
576
+ return c.type === ControlDefinitionType.Action;
577
+ }
578
+
579
+ export function isDisplayControl(
580
+ c: ControlDefinition,
581
+ ): c is DisplayControlDefinition {
582
+ return c.type === ControlDefinitionType.Display;
583
+ }
584
+
585
+ export function isTextDisplay(d: DisplayData): d is TextDisplay {
586
+ return d.type === DisplayDataType.Text;
587
+ }
588
+
589
+ export function isHtmlDisplay(d: DisplayData): d is HtmlDisplay {
590
+ return d.type === DisplayDataType.Html;
591
+ }
592
+
593
+ export function isCheckEntryClasses(
594
+ options?: RenderOptions | null,
595
+ ): options is CheckEntryClasses & RenderOptions {
596
+ switch (options?.type) {
597
+ case DataRenderType.Radio:
598
+ case DataRenderType.CheckList:
599
+ return true;
600
+ default:
601
+ return false;
602
+ }
603
+ }
604
+
605
+ export function traverseParents<A, B extends { parent?: B | undefined }>(
606
+ current: B | undefined,
607
+ get: (b: B) => A,
608
+ until?: (b: B) => boolean,
609
+ ): A[] {
610
+ let outArray: A[] = [];
611
+ while (current && !until?.(current)) {
612
+ outArray.push(get(current));
613
+ current = current.parent;
614
+ }
615
+ return outArray.reverse();
616
+ }
617
+
618
+ export function getRootDataNode(dataNode: SchemaDataNode) {
619
+ while (dataNode.parent) {
620
+ dataNode = dataNode.parent;
621
+ }
622
+ return dataNode;
623
+ }
624
+
625
+ export function getJsonPath(dataNode: SchemaDataNode) {
626
+ return traverseParents(
627
+ dataNode,
628
+ (d) => (d.elementIndex == null ? d.schema.field.field : d.elementIndex),
629
+ (x) => !x.parent,
630
+ );
631
+ }
632
+
633
+ export function getSchemaPath(schemaNode: SchemaNode): SchemaField[] {
634
+ return traverseParents(
635
+ schemaNode,
636
+ (d) => d.field,
637
+ (x) => !x.parent,
638
+ );
639
+ }
640
+
641
+ export function getSchemaFieldList(schema: SchemaNode): SchemaField[] {
642
+ return schema.getChildNodes().map((x) => x.field);
643
+ }
644
+
645
+ export function fontAwesomeIcon(icon: string) {
646
+ return { library: IconLibrary.FontAwesome, name: icon };
647
+ }
648
+
649
+ /**
650
+ * Checks if a control definition is readonly.
651
+ * @param c - The control definition to check.
652
+ * @returns True if the control definition is readonly, false otherwise.
653
+ */
654
+ export function isControlReadonly(c: ControlDefinition): boolean {
655
+ return isDataControl(c) && !!c.readonly;
656
+ }
657
+
658
+ /**
659
+ * Checks if a control definition is disabled.
660
+ * @param c - The control definition to check.
661
+ * @returns True if the control definition is disabled, false otherwise.
662
+ */
663
+ export function isControlDisabled(c: ControlDefinition): boolean {
664
+ return isDataControl(c) && !!c.disabled;
665
+ }
666
+
667
+ /**
668
+ * Returns the group renderer options for a control definition.
669
+ * @param {ControlDefinition} def - The control definition to get the group renderer options for.
670
+ * @returns {GroupRenderOptions | undefined} - The group renderer options, or undefined if not applicable.
671
+ */
672
+ export function getGroupRendererOptions(
673
+ def: ControlDefinition,
674
+ ): GroupRenderOptions | undefined {
675
+ return isGroupControl(def)
676
+ ? def.groupOptions
677
+ : isDataControl(def) && isDataGroupRenderer(def.renderOptions)
678
+ ? def.renderOptions.groupOptions
679
+ : undefined;
680
+ }
681
+
682
+ /**
683
+ * Checks if a control definition is display-only.
684
+ * @param {ControlDefinition} def - The control definition to check.
685
+ * @returns {boolean} - True if the control definition is display-only, false otherwise.
686
+ */
687
+ export function isControlDisplayOnly(def: ControlDefinition): boolean {
688
+ return Boolean(getGroupRendererOptions(def)?.displayOnly);
689
+ }
690
+
691
+ /**
692
+ * Returns the display-only render options for a control definition.
693
+ * @param d - The control definition to get the display-only render options for.
694
+ * @returns The display-only render options, or undefined if not applicable.
695
+ */
696
+ export function getDisplayOnlyOptions(
697
+ d: ControlDefinition,
698
+ ): DisplayOnlyRenderOptions | undefined {
699
+ return isDataControl(d) &&
700
+ d.renderOptions &&
701
+ isDisplayOnlyRenderer(d.renderOptions)
702
+ ? d.renderOptions
703
+ : undefined;
704
+ }