@react-typed-forms/schemas 6.0.0 → 7.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.
@@ -25,7 +25,7 @@ export interface DataRendererRegistration {
25
25
  options?: boolean;
26
26
  collection?: boolean;
27
27
  match?: (props: DataRendererProps) => boolean;
28
- render: (props: DataRendererProps, asArray: (() => ReactNode) | undefined, renderers: FormRenderer) => ReactNode | ((layout: ControlLayoutProps) => ControlLayoutProps);
28
+ render: (props: DataRendererProps, renderers: FormRenderer) => ReactNode | ((layout: ControlLayoutProps) => ControlLayoutProps);
29
29
  }
30
30
  export interface LabelRendererRegistration {
31
31
  type: "label";
package/lib/types.d.ts CHANGED
@@ -72,7 +72,8 @@ export declare enum DynamicPropertyType {
72
72
  Disabled = "Disabled",
73
73
  Display = "Display",
74
74
  Style = "Style",
75
- LayoutStyle = "LayoutStyle"
75
+ LayoutStyle = "LayoutStyle",
76
+ AllowedOptions = "AllowedOptions"
76
77
  }
77
78
  export interface EntityExpression {
78
79
  type: string;
@@ -143,6 +144,7 @@ export interface DataControlDefinition extends ControlDefinition {
143
144
  readonly?: boolean | null;
144
145
  validators?: SchemaValidator[] | null;
145
146
  hideTitle?: boolean | null;
147
+ dontClearHidden?: boolean | null;
146
148
  }
147
149
  export interface RenderOptions {
148
150
  type: string;
package/lib/util.d.ts CHANGED
@@ -25,7 +25,7 @@ export declare function fieldDisplayName(field: SchemaField): string;
25
25
  export declare function hasOptions(o: {
26
26
  options: FieldOption[] | undefined | null;
27
27
  }): boolean;
28
- export declare function defaultControlForField(sf: SchemaField): DataControlDefinition | GroupedControlsDefinition;
28
+ export declare function defaultControlForField(sf: SchemaField): DataControlDefinition;
29
29
  export declare function addMissingControls(fields: SchemaField[], controls: ControlDefinition[]): ControlDefinition[];
30
30
  export declare function useUpdatedRef<A>(a: A): MutableRefObject<A>;
31
31
  export declare function isControlReadonly(c: ControlDefinition): boolean;
@@ -36,3 +36,4 @@ export declare function visitControlData<A>(definition: ControlDefinition, ctx:
36
36
  export declare function cleanDataForSchema(v: {
37
37
  [k: string]: any;
38
38
  } | undefined, fields: SchemaField[]): any;
39
+ export declare function getAllReferencedClasses(c: ControlDefinition): string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-typed-forms/schemas",
3
- "version": "6.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -1,4 +1,5 @@
1
1
  import React, {
2
+ CSSProperties,
2
3
  FC,
3
4
  Fragment,
4
5
  Key,
@@ -43,6 +44,7 @@ import {
43
44
  import { dataControl } from "./controlBuilder";
44
45
  import {
45
46
  defaultUseEvalExpressionHook,
47
+ useEvalAllowedOptionsHook,
46
48
  useEvalDefaultValueHook,
47
49
  useEvalDisabledHook,
48
50
  useEvalDisplayHook,
@@ -58,7 +60,6 @@ import { defaultSchemaInterface } from "./schemaInterface";
58
60
  export interface FormRenderer {
59
61
  renderData: (
60
62
  props: DataRendererProps,
61
- asArray: (() => ReactNode) | undefined,
62
63
  ) => (layout: ControlLayoutProps) => ControlLayoutProps;
63
64
  renderGroup: (
64
65
  props: GroupRendererProps,
@@ -92,10 +93,10 @@ export interface AdornmentRenderer {
92
93
  export interface ArrayRendererProps {
93
94
  addAction?: ActionRendererProps;
94
95
  required: boolean;
95
- removeAction?: (childIndex: number) => ActionRendererProps;
96
- childCount: number;
97
- renderChild: (childIndex: number) => ReactNode;
98
- childKey: (childIndex: number) => Key;
96
+ removeAction?: (elemIndex: number) => ActionRendererProps;
97
+ elementCount: number;
98
+ renderElement: (elemIndex: number) => ReactNode;
99
+ elementKey: (elemIndex: number) => Key;
99
100
  arrayControl?: Control<any[] | undefined | null>;
100
101
  className?: string;
101
102
  style?: React.CSSProperties;
@@ -176,6 +177,9 @@ export interface DataRendererProps {
176
177
  className?: string;
177
178
  style?: React.CSSProperties;
178
179
  dataContext: ControlDataContext;
180
+ childCount: number;
181
+ renderChild: ChildRenderer;
182
+ toArrayProps?: () => ArrayRendererProps;
179
183
  }
180
184
 
181
185
  export interface ActionRendererProps {
@@ -203,6 +207,10 @@ export interface DataControlProps {
203
207
  control: Control<any>;
204
208
  options: FormContextOptions;
205
209
  style: React.CSSProperties | undefined;
210
+ childCount: number;
211
+ renderChild: ChildRenderer;
212
+ allowedOptions?: Control<any[] | undefined>;
213
+ elementRenderer?: (elemProps: Control<any>) => ReactNode;
206
214
  }
207
215
  export type CreateDataProps = (
208
216
  controlProps: DataControlProps,
@@ -233,6 +241,7 @@ export function useControlRenderer(
233
241
  const useIsVisible = useEvalVisibilityHook(useExpr, definition, schemaField);
234
242
  const useIsReadonly = useEvalReadonlyHook(useExpr, definition);
235
243
  const useIsDisabled = useEvalDisabledHook(useExpr, definition);
244
+ const useAllowedOptions = useEvalAllowedOptionsHook(useExpr, definition);
236
245
  const useCustomStyle = useEvalStyleHook(
237
246
  useExpr,
238
247
  DynamicPropertyType.Style,
@@ -283,6 +292,7 @@ export function useControlRenderer(
283
292
  },
284
293
  );
285
294
 
295
+ const allowedOptions = useAllowedOptions(dataContext);
286
296
  const defaultValueControl = useDefaultValue(dataContext);
287
297
  const [control, childContext] = getControlData(
288
298
  schemaField,
@@ -294,14 +304,15 @@ export function useControlRenderer(
294
304
  defaultValueControl.value,
295
305
  control,
296
306
  parentControl.isNull,
307
+ isDataControlDefinition(definition) && definition.dontClearHidden,
297
308
  ],
298
- ([vc, dv, cd, pn]) => {
309
+ ([vc, dv, cd, pn, dontClear]) => {
299
310
  if (pn) {
300
311
  parentControl.value = {};
301
312
  }
302
313
  if (vc && cd && vc.visible === vc.showing) {
303
314
  if (!vc.visible) {
304
- if (options.clearHidden) cd.value = undefined;
315
+ if (options.clearHidden && !dontClear) cd.value = undefined;
305
316
  } else if (cd.value == null) {
306
317
  cd.value = dv;
307
318
  }
@@ -346,6 +357,7 @@ export function useControlRenderer(
346
357
  schemaField,
347
358
  displayControl,
348
359
  style: customStyle,
360
+ allowedOptions,
349
361
  });
350
362
  const renderedControl = renderer.renderLayout({
351
363
  ...labelAndChildren,
@@ -367,6 +379,7 @@ export function useControlRenderer(
367
379
  useIsDisabled,
368
380
  useCustomStyle,
369
381
  useLayoutStyle,
382
+ useAllowedOptions,
370
383
  useDynamicDisplay,
371
384
  useValidation,
372
385
  renderer,
@@ -406,37 +419,6 @@ export function getControlData(
406
419
  ];
407
420
  }
408
421
 
409
- function renderArray(
410
- renderer: FormRenderer,
411
- noun: string,
412
- field: SchemaField,
413
- required: boolean,
414
- arrayControl: Control<any[] | undefined | null>,
415
- renderChild: (elemIndex: number, control: Control<any>) => ReactNode,
416
- className: string | null | undefined,
417
- style: React.CSSProperties | undefined,
418
- ) {
419
- const elems = arrayControl.elements ?? [];
420
- return renderer.renderArray({
421
- arrayControl,
422
- childCount: elems.length,
423
- required,
424
- addAction: {
425
- actionId: "add",
426
- actionText: "Add " + noun,
427
- onClick: () => addElement(arrayControl, elementValueForField(field)),
428
- },
429
- childKey: (i) => elems[i].uniqueId,
430
- removeAction: (i: number) => ({
431
- actionId: "",
432
- actionText: "Remove",
433
- onClick: () => removeElement(arrayControl, i),
434
- }),
435
- renderChild: (i) => renderChild(i, elems[i]),
436
- className: cc(className),
437
- style,
438
- });
439
- }
440
422
  function groupProps(
441
423
  renderOptions: GroupRenderOptions = { type: "Standard" },
442
424
  childCount: number,
@@ -457,23 +439,75 @@ function groupProps(
457
439
  export function defaultDataProps({
458
440
  definition,
459
441
  field,
460
- dataContext,
461
442
  control,
462
443
  options,
444
+ elementRenderer,
463
445
  style,
446
+ allowedOptions,
447
+ ...props
464
448
  }: DataControlProps): DataRendererProps {
449
+ const className = cc(definition.styleClass);
450
+ const required = !!definition.required;
451
+ const fieldOptions =
452
+ (field.options?.length ?? 0) === 0 ? null : field.options;
453
+ const allowed = allowedOptions?.value ?? [];
465
454
  return {
466
455
  control,
467
456
  field,
468
457
  id: "c" + control.uniqueId,
469
- options: (field.options?.length ?? 0) === 0 ? null : field.options,
458
+ options:
459
+ fieldOptions && allowed.length > 0
460
+ ? fieldOptions.filter((x) => allowed.includes(x.value))
461
+ : fieldOptions,
470
462
  readonly: !!options.readonly,
471
463
  renderOptions: definition.renderOptions ?? { type: "Standard" },
472
- required: !!definition.required,
464
+ required,
473
465
  hidden: !!options.hidden,
474
- className: cc(definition.styleClass),
466
+ className,
467
+ style,
468
+ ...props,
469
+ toArrayProps: elementRenderer
470
+ ? () =>
471
+ defaultArrayProps(
472
+ control,
473
+ field,
474
+ required,
475
+ style,
476
+ className,
477
+ elementRenderer,
478
+ )
479
+ : undefined,
480
+ };
481
+ }
482
+
483
+ export function defaultArrayProps(
484
+ arrayControl: Control<any[] | undefined | null>,
485
+ field: SchemaField,
486
+ required: boolean,
487
+ style: CSSProperties | undefined,
488
+ className: string | undefined,
489
+ renderElement: (elemProps: Control<any>) => ReactNode,
490
+ ): ArrayRendererProps {
491
+ const noun = field.displayName ?? field.field;
492
+ const elems = arrayControl.elements ?? [];
493
+ return {
494
+ arrayControl,
495
+ elementCount: elems.length,
496
+ required,
497
+ addAction: {
498
+ actionId: "add",
499
+ actionText: "Add " + noun,
500
+ onClick: () => addElement(arrayControl, elementValueForField(field)),
501
+ },
502
+ elementKey: (i) => elems[i].uniqueId,
503
+ removeAction: (i: number) => ({
504
+ actionId: "",
505
+ actionText: "Remove",
506
+ onClick: () => removeElement(arrayControl, i),
507
+ }),
508
+ renderElement: (i) => renderElement(elems[i]),
509
+ className: cc(className),
475
510
  style,
476
- dataContext,
477
511
  };
478
512
  }
479
513
 
@@ -495,6 +529,7 @@ export interface RenderControlProps {
495
529
  schemaField?: SchemaField;
496
530
  displayControl?: Control<string | undefined>;
497
531
  style?: React.CSSProperties;
532
+ allowedOptions?: Control<any[] | undefined>;
498
533
  }
499
534
  export function renderControlLayout({
500
535
  definition: c,
@@ -508,6 +543,7 @@ export function renderControlLayout({
508
543
  createDataProps: dataProps,
509
544
  displayControl,
510
545
  style,
546
+ allowedOptions,
511
547
  }: RenderControlProps): ControlLayoutProps {
512
548
  if (isDataControlDefinition(c)) {
513
549
  return renderData(c);
@@ -562,74 +598,30 @@ export function renderControlLayout({
562
598
  }
563
599
  return {};
564
600
 
565
- function renderData(c: DataControlDefinition) {
601
+ function renderData(c: DataControlDefinition, elementControl?: Control<any>) {
566
602
  if (!schemaField) return { children: "No schema field for: " + c.field };
567
- if (isCompoundField(schemaField)) {
568
- const label: LabelRendererProps = {
569
- hide: c.hideTitle,
570
- label: controlTitle(c.title, schemaField),
571
- type: schemaField.collection ? LabelType.Control : LabelType.Group,
572
- };
573
-
574
- if (schemaField.collection) {
575
- return {
576
- label,
577
- children: renderArray(
578
- renderer,
579
- controlTitle(c.title, schemaField),
580
- schemaField,
581
- !!c.required,
582
- childControl!,
583
- compoundRenderer,
584
- c.styleClass,
585
- style,
586
- ),
587
- errorControl: childControl,
588
- };
589
- }
590
- return {
591
- processLayout: renderer.renderGroup(
592
- groupProps(
593
- { type: "Standard" },
594
- childCount,
595
- childRenderer,
596
- childControl!,
597
- c.styleClass,
598
- style,
599
- ),
600
- ),
601
- label,
602
- errorControl: childControl,
603
- };
604
- }
605
603
  const props = dataProps({
606
604
  definition: c,
607
605
  field: schemaField,
608
606
  dataContext,
609
- control: childControl!,
607
+ control: elementControl ?? childControl!,
610
608
  options: dataOptions,
611
609
  style,
610
+ childCount,
611
+ allowedOptions,
612
+ renderChild: childRenderer,
613
+ elementRenderer:
614
+ elementControl == null && schemaField.collection
615
+ ? (element) =>
616
+ renderLayoutParts(renderData(c, element), renderer).children
617
+ : undefined,
612
618
  });
619
+
613
620
  const labelText = !c.hideTitle
614
621
  ? controlTitle(c.title, schemaField)
615
622
  : undefined;
616
623
  return {
617
- processLayout: renderer.renderData(
618
- props,
619
- schemaField.collection
620
- ? () =>
621
- renderArray(
622
- renderer,
623
- controlTitle(c.title, schemaField),
624
- schemaField,
625
- !!c.required,
626
- childControl!,
627
- scalarRenderer(props),
628
- c.styleClass,
629
- style,
630
- )
631
- : undefined,
632
- ),
624
+ processLayout: renderer.renderData(props),
633
625
  label: {
634
626
  type: LabelType.Control,
635
627
  label: labelText,
@@ -661,10 +653,7 @@ export function renderControlLayout({
661
653
  return (i, control) => {
662
654
  return (
663
655
  <Fragment key={control.uniqueId}>
664
- {
665
- renderer.renderData({ ...dataProps, control }, undefined)({})
666
- .children
667
- }
656
+ {renderer.renderData({ ...dataProps, control })({}).children}
668
657
  </Fragment>
669
658
  );
670
659
  };
package/src/hooks.tsx CHANGED
@@ -105,6 +105,24 @@ export function useEvalStyleHook(
105
105
  );
106
106
  }
107
107
 
108
+ export function useEvalAllowedOptionsHook(
109
+ useEvalExpressionHook: UseEvalExpressionHook,
110
+ definition: ControlDefinition,
111
+ ): EvalExpressionHook<any[]> {
112
+ const dynamicAllowed = useEvalDynamicHook(
113
+ definition,
114
+ DynamicPropertyType.AllowedOptions,
115
+ useEvalExpressionHook,
116
+ );
117
+ return useCallback(
118
+ (ctx) => {
119
+ if (dynamicAllowed) return dynamicAllowed(ctx);
120
+ return useControl([]);
121
+ },
122
+ [dynamicAllowed],
123
+ );
124
+ }
125
+
108
126
  export function useEvalDisabledHook(
109
127
  useEvalExpressionHook: UseEvalExpressionHook,
110
128
  definition: ControlDefinition,
package/src/renderers.tsx CHANGED
@@ -78,7 +78,6 @@ export interface DataRendererRegistration {
78
78
  match?: (props: DataRendererProps) => boolean;
79
79
  render: (
80
80
  props: DataRendererProps,
81
- asArray: (() => ReactNode) | undefined,
82
81
  renderers: FormRenderer,
83
82
  ) => ReactNode | ((layout: ControlLayoutProps) => ControlLayoutProps);
84
83
  }
@@ -210,7 +209,6 @@ export function createFormRenderer(
210
209
 
211
210
  function renderData(
212
211
  props: DataRendererProps,
213
- asArray: (() => ReactNode) | undefined,
214
212
  ): (layout: ControlLayoutProps) => ControlLayoutProps {
215
213
  const {
216
214
  renderOptions: { type: renderType },
@@ -228,7 +226,7 @@ export function createFormRenderer(
228
226
  (!x.match || x.match(props)),
229
227
  ) ?? defaultRenderers.data;
230
228
 
231
- const result = renderer.render(props, asArray, formRenderers);
229
+ const result = renderer.render(props, formRenderers);
232
230
  if (typeof result === "function") return result;
233
231
  return (l) => ({ ...l, children: result });
234
232
  }
@@ -332,32 +330,32 @@ export function createDefaultArrayRenderer(
332
330
  } = options ?? {};
333
331
  function render(
334
332
  {
335
- childCount,
336
- renderChild,
333
+ elementCount,
334
+ renderElement,
337
335
  addAction,
338
336
  removeAction,
339
- childKey,
337
+ elementKey,
340
338
  required,
341
339
  }: ArrayRendererProps,
342
340
  { renderAction }: FormRenderer,
343
341
  ) {
344
- const showRemove = !required || childCount > 1;
342
+ const showRemove = !required || elementCount > 1;
345
343
  return (
346
344
  <div>
347
345
  <div className={clsx(className, removeAction && removableClass)}>
348
- {Array.from({ length: childCount }, (_, x) =>
346
+ {Array.from({ length: elementCount }, (_, x) =>
349
347
  removeAction ? (
350
- <Fragment key={childKey(x)}>
348
+ <Fragment key={elementKey(x)}>
351
349
  <div className={clsx(childClass, removableChildClass)}>
352
- {renderChild(x)}
350
+ {renderElement(x)}
353
351
  </div>
354
352
  <div className={removeActionClass}>
355
353
  {showRemove && renderAction(removeAction(x))}
356
354
  </div>
357
355
  </Fragment>
358
356
  ) : (
359
- <div key={childKey(x)} className={childClass}>
360
- {renderChild(x)}
357
+ <div key={elementKey(x)} className={childClass}>
358
+ {renderElement(x)}
361
359
  </div>
362
360
  ),
363
361
  )}
@@ -430,8 +428,8 @@ export function createDefaultGroupRenderer(
430
428
  const { style, className: gcn } = isGridRenderer(renderOptions)
431
429
  ? gridStyles(renderOptions)
432
430
  : isFlexRenderer(renderOptions)
433
- ? flexStyles(renderOptions)
434
- : ({ className: standardClassName } as StyleProps);
431
+ ? flexStyles(renderOptions)
432
+ : ({ className: standardClassName } as StyleProps);
435
433
 
436
434
  return (cp: ControlLayoutProps) => {
437
435
  return {
@@ -520,13 +518,25 @@ export function createDefaultDataRenderer(
520
518
  booleanOptions: DefaultBoolOptions,
521
519
  ...options,
522
520
  };
523
- return createDataRenderer((props, asArray, renderers) => {
524
- if (asArray) {
525
- return asArray();
521
+ return createDataRenderer((props, renderers) => {
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
+ });
526
537
  }
527
538
  const renderOptions = props.renderOptions;
528
539
  let renderType = renderOptions.type;
529
- const fieldType = props.field.type;
530
540
  if (fieldType == FieldType.Any) return <>No control for Any</>;
531
541
  if (isDisplayOnlyRenderer(renderOptions))
532
542
  return (p) => ({
@@ -545,17 +555,14 @@ export function createDefaultDataRenderer(
545
555
  });
546
556
  const isBool = fieldType === FieldType.Bool;
547
557
  if (booleanOptions != null && isBool && props.options == null) {
548
- return renderers.renderData(
549
- { ...props, options: booleanOptions },
550
- undefined,
551
- );
558
+ return renderers.renderData({ ...props, options: booleanOptions });
552
559
  }
553
560
  if (renderType === DataRenderType.Standard && hasOptions(props)) {
554
- return optionRenderer.render(props, undefined, renderers);
561
+ return optionRenderer.render(props, renderers);
555
562
  }
556
563
  switch (renderType) {
557
564
  case DataRenderType.Dropdown:
558
- return selectRenderer.render(props, undefined, renderers);
565
+ return selectRenderer.render(props, renderers);
559
566
  }
560
567
  return renderType === DataRenderType.Checkbox ? (
561
568
  <Fcheckbox
package/src/types.ts CHANGED
@@ -90,6 +90,7 @@ export enum DynamicPropertyType {
90
90
  Display = "Display",
91
91
  Style = "Style",
92
92
  LayoutStyle = "LayoutStyle",
93
+ AllowedOptions = "AllowedOptions"
93
94
  }
94
95
 
95
96
  export interface EntityExpression {
@@ -174,6 +175,7 @@ export interface DataControlDefinition extends ControlDefinition {
174
175
  readonly?: boolean | null;
175
176
  validators?: SchemaValidator[] | null;
176
177
  hideTitle?: boolean | null;
178
+ dontClearHidden?: boolean | null;
177
179
  }
178
180
 
179
181
  export interface RenderOptions {
package/src/util.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  } from "./types";
19
19
  import { MutableRefObject, useRef } from "react";
20
20
  import { Control } from "@react-typed-forms/core";
21
+ import clsx from "clsx";
21
22
 
22
23
  export interface ControlDataContext {
23
24
  groupControl: Control<any>;
@@ -146,20 +147,15 @@ export function hasOptions(o: { options: FieldOption[] | undefined | null }) {
146
147
  return (o.options?.length ?? 0) > 0;
147
148
  }
148
149
 
149
- export function defaultControlForField(
150
- sf: SchemaField,
151
- ): DataControlDefinition | GroupedControlsDefinition {
150
+ export function defaultControlForField(sf: SchemaField): DataControlDefinition {
152
151
  if (isCompoundField(sf)) {
153
152
  return {
154
- type: ControlDefinitionType.Group,
153
+ type: ControlDefinitionType.Data,
155
154
  title: sf.displayName,
156
- compoundField: sf.field,
157
- groupOptions: {
158
- type: GroupRenderType.Grid,
159
- hideTitle: false,
160
- } as GridRenderer,
155
+ field: sf.field,
156
+ required: sf.required,
161
157
  children: sf.children.map(defaultControlForField),
162
- } satisfies GroupedControlsDefinition;
158
+ };
163
159
  } else if (isScalarField(sf)) {
164
160
  const htmlEditor = sf.tags?.includes("_HtmlEditor");
165
161
  return {
@@ -170,7 +166,7 @@ export function defaultControlForField(
170
166
  renderOptions: {
171
167
  type: htmlEditor ? DataRenderType.HtmlEditor : DataRenderType.Standard,
172
168
  },
173
- } satisfies DataControlDefinition;
169
+ };
174
170
  }
175
171
  throw "Unknown schema field";
176
172
  }
@@ -378,3 +374,12 @@ export function cleanDataForSchema(
378
374
  });
379
375
  return out;
380
376
  }
377
+
378
+ export function getAllReferencedClasses(c: ControlDefinition): string[] {
379
+ const childClasses = c.children?.flatMap(getAllReferencedClasses);
380
+ const tc = clsx(c.styleClass, c.layoutClass);
381
+ if (childClasses && !tc) return childClasses;
382
+ if (!tc) return [];
383
+ if (childClasses) return [tc, ...childClasses];
384
+ return [tc];
385
+ }