@asteby/metacore-runtime-react 28.4.1 → 28.5.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/CHANGELOG.md +10 -0
- package/dist/dialogs/dynamic-record.d.ts +7 -0
- package/dist/dialogs/dynamic-record.d.ts.map +1 -1
- package/dist/dialogs/dynamic-record.js +78 -18
- package/dist/dynamic-form.d.ts +10 -1
- package/dist/dynamic-form.d.ts.map +1 -1
- package/dist/dynamic-form.js +49 -3
- package/dist/form-layout-ui.d.ts +25 -0
- package/dist/form-layout-ui.d.ts.map +1 -0
- package/dist/form-layout-ui.js +39 -0
- package/dist/form-layout.d.ts +54 -0
- package/dist/form-layout.d.ts.map +1 -0
- package/dist/form-layout.js +81 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/dynamic-record-hidden-submit.test.tsx +78 -0
- package/src/__tests__/form-layout.test.ts +113 -0
- package/src/dialogs/dynamic-record.tsx +160 -46
- package/src/dynamic-form.tsx +110 -14
- package/src/form-layout-ui.tsx +117 -0
- package/src/form-layout.ts +116 -0
- package/src/index.ts +2 -0
- package/src/types.ts +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 28.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 47f6543: Los renderers de formulario (`DynamicForm` y `DynamicRecordDialog`) ahora consumen el primitivo `form_layout` del modelo (kernel PR #230): agrupan los campos por su `section` respetando el orden de `sections`. En `mode: "sections"` cada grupo se dibuja como una sección con `title`/`description` y soporte de `collapsed` (colapsable); en `mode: "steps"` se dibuja un wizard multi-paso con navegación Anterior/Siguiente y submit en el último paso. Los campos sin `section` (o con sección desconocida) caen en un grupo por defecto al inicio, y una sección sin campos visibles se oculta. Sin `form_layout` el comportamiento (lista plana) queda idéntico; `visible_when`, el gate de required y el strip de ocultos en el submit se respetan.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- b05aded: DynamicRecordDialog ya no envía en el submit los campos ocultos por `visible_when`, en paridad con DynamicForm.
|
|
12
|
+
|
|
3
13
|
## 28.4.1
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
|
@@ -83,6 +83,12 @@ export interface FieldDef {
|
|
|
83
83
|
visible_when?: VisibleWhen;
|
|
84
84
|
/** camelCase alias for `visible_when`. */
|
|
85
85
|
visibleWhen?: VisibleWhen;
|
|
86
|
+
/**
|
|
87
|
+
* Form-layout membership: the key of the `form_layout` section this field
|
|
88
|
+
* belongs to (kernel PR #230). Absent → the default group. See
|
|
89
|
+
* `groupFieldsBySection`.
|
|
90
|
+
*/
|
|
91
|
+
section?: string;
|
|
86
92
|
}
|
|
87
93
|
export interface DynamicRecordDialogProps {
|
|
88
94
|
open: boolean;
|
|
@@ -178,6 +184,7 @@ export declare function isLineItemsField(field: FieldDef, value: any): boolean;
|
|
|
178
184
|
export declare function fkSeedOption(field: FieldDef, value: any, record: any): ResolvedOption | null;
|
|
179
185
|
export declare function isMoneyField(field: FieldDef, value: any): boolean;
|
|
180
186
|
export declare function filterVisibleFields(fields: FieldDef[] | undefined, mode: 'view' | 'edit' | 'create', formValues?: Record<string, any>): FieldDef[];
|
|
187
|
+
export declare function stripHiddenFieldValues(values: Record<string, any>, fields: FieldDef[] | undefined, mode: 'view' | 'edit' | 'create'): Record<string, any>;
|
|
181
188
|
export declare function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId, endpoint, onSaved, onCreate, onUpdate, defaults, schema, onDelete, onEdit, onOpenFullPage, initialRecord, getImageUrl, timeZone, currency, onChange, }: DynamicRecordDialogProps): import("react").JSX.Element;
|
|
182
189
|
export declare function ReadonlyEditField({ field, value }: {
|
|
183
190
|
field: FieldDef;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-record.d.ts","sourceRoot":"","sources":["../../src/dialogs/dynamic-record.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAwC1C,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAEjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"dynamic-record.d.ts","sourceRoot":"","sources":["../../src/dialogs/dynamic-record.tsx"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,8 @@ import { DynamicSelectField, OptionLead, OptionThumb } from '../dynamic-select-f
|
|
|
24
24
|
import { DynamicRelations } from '../dynamic-relations';
|
|
25
25
|
import { useOptionsResolver } from '../use-options-resolver';
|
|
26
26
|
import { getFieldRef, getVisibleWhen, evaluateVisibleWhen } from '../dynamic-form-schema';
|
|
27
|
+
import { groupFieldsBySection } from '../form-layout';
|
|
28
|
+
import { FieldSection, WizardProgress } from '../form-layout-ui';
|
|
27
29
|
import { FieldCell } from '../field-grid';
|
|
28
30
|
import { isNilUuid, normalizeNilUuid } from '../nil-uuid';
|
|
29
31
|
import { normalizeRefFieldsForSubmit } from './normalize-submit';
|
|
@@ -257,6 +259,25 @@ export function filterVisibleFields(fields, mode, formValues) {
|
|
|
257
259
|
return true;
|
|
258
260
|
});
|
|
259
261
|
}
|
|
262
|
+
// stripHiddenFieldValues drops from a flat form-values object the keys of any
|
|
263
|
+
// declared field currently hidden by its `visible_when` predicate, so the
|
|
264
|
+
// submit never POSTs a value the form isn't showing (e.g. a DiscountRule with
|
|
265
|
+
// rule_scope=category must not send the product_id / customer_id it hides).
|
|
266
|
+
// This mirrors dynamic-form.tsx, which builds its Zod schema only over the
|
|
267
|
+
// visible fields — hidden fields are dropped from BOTH the render/required-gate
|
|
268
|
+
// AND the submitted values. Keys with no matching declared field, or whose
|
|
269
|
+
// field carries no `visible_when`, always pass through (retrocompat).
|
|
270
|
+
export function stripHiddenFieldValues(values, fields, mode) {
|
|
271
|
+
const visibleKeys = new Set(filterVisibleFields(fields, mode, values).map(f => f.key));
|
|
272
|
+
const out = {};
|
|
273
|
+
for (const [key, value] of Object.entries(values)) {
|
|
274
|
+
const field = (fields ?? []).find(f => f.key === key);
|
|
275
|
+
if (field && !visibleKeys.has(key) && getVisibleWhen(field))
|
|
276
|
+
continue;
|
|
277
|
+
out[key] = value;
|
|
278
|
+
}
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
260
281
|
export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId, endpoint, onSaved, onCreate, onUpdate, defaults, schema, onDelete, onEdit, onOpenFullPage, initialRecord, getImageUrl = identityImageUrl, timeZone, currency, onChange, }) {
|
|
261
282
|
const api = useApi();
|
|
262
283
|
const { t } = useTranslation();
|
|
@@ -271,6 +292,8 @@ export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId,
|
|
|
271
292
|
const [loading, setLoading] = useState(false);
|
|
272
293
|
const [saving, setSaving] = useState(false);
|
|
273
294
|
const [deleting, setDeleting] = useState(false);
|
|
295
|
+
// Wizard step cursor (form_layout mode:"steps" only).
|
|
296
|
+
const [stepIndex, setStepIndex] = useState(0);
|
|
274
297
|
const isCreate = mode === 'create';
|
|
275
298
|
const isView = mode === 'view';
|
|
276
299
|
const isEditable = mode === 'create' || mode === 'edit';
|
|
@@ -281,8 +304,10 @@ export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId,
|
|
|
281
304
|
return;
|
|
282
305
|
if (!isCreate && !recordId)
|
|
283
306
|
return;
|
|
284
|
-
// Fresh open → drop any validation errors from a prior submit
|
|
307
|
+
// Fresh open → drop any validation errors from a prior submit and reset
|
|
308
|
+
// the wizard to its first step.
|
|
285
309
|
setFieldErrors({});
|
|
310
|
+
setStepIndex(0);
|
|
286
311
|
let cancelled = false;
|
|
287
312
|
// Seed instantly from the row the table already has so view/edit render
|
|
288
313
|
// without a spinner. The list row carries the pro siblings (resolved
|
|
@@ -489,9 +514,15 @@ export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId,
|
|
|
489
514
|
}
|
|
490
515
|
// Required check passed → clear any prior validation errors.
|
|
491
516
|
setFieldErrors({});
|
|
517
|
+
// Fields hidden by their `visible_when` predicate must not be POSTed:
|
|
518
|
+
// the render, the required-gate and the payload all drive off the same
|
|
519
|
+
// filter, so a DiscountRule with scope=category never submits the
|
|
520
|
+
// product_id / customer_id it isn't showing. Mirrors dynamic-form.tsx,
|
|
521
|
+
// which builds its Zod only over visibleFields.
|
|
522
|
+
const submittedValues = stripHiddenFieldValues(formValues, modalMeta.fields, mode);
|
|
492
523
|
// Empty reference pickers → null (not "" / nil-UUID) so nullable FK
|
|
493
524
|
// columns accept them instead of raising a 23503 FK violation.
|
|
494
|
-
const payload = normalizeRefFieldsForSubmit(
|
|
525
|
+
const payload = normalizeRefFieldsForSubmit(submittedValues, modalMeta.fields);
|
|
495
526
|
setSaving(true);
|
|
496
527
|
try {
|
|
497
528
|
if (isCreate && onCreate) {
|
|
@@ -563,22 +594,51 @@ export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId,
|
|
|
563
594
|
};
|
|
564
595
|
const title = modalMeta ? config.getTitle(modalMeta, t) : '';
|
|
565
596
|
const visibleFields = filterVisibleFields(modalMeta?.fields, mode, formValues);
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
597
|
+
// Declarative form layout: group the (already visibility-filtered) fields by
|
|
598
|
+
// their section. Empty sections drop out for free. Steps mode only drives a
|
|
599
|
+
// wizard in editable modes — view mode always stacks the sections.
|
|
600
|
+
const formLayout = modalMeta?.form_layout ?? modalMeta?.formLayout;
|
|
601
|
+
const groups = groupFieldsBySection(visibleFields, formLayout);
|
|
602
|
+
const isSteps = isEditable && formLayout?.mode === 'steps' && groups.length > 1;
|
|
603
|
+
const clampedStep = Math.min(stepIndex, Math.max(groups.length - 1, 0));
|
|
604
|
+
const isLastStep = clampedStep === groups.length - 1;
|
|
605
|
+
// Renders a list of fields into the shared two-column grid (each FieldCell
|
|
606
|
+
// gives min-w-0 so long values can't blow the columns past the dialog).
|
|
607
|
+
const renderFields = (groupFields) => groupFields.map(field => {
|
|
608
|
+
const isFullWidth = field.type === 'textarea' ||
|
|
609
|
+
field.widget === 'textarea' ||
|
|
610
|
+
field.widget === 'richtext';
|
|
611
|
+
return (_jsx(FieldCell, { fullWidth: isFullWidth, children: _jsx(FieldRow, { field: field, record: record, value: formValues[field.key] ?? '', mode: mode, error: fieldErrors[field.key], onChange: val => {
|
|
612
|
+
setFormValues((prev) => ({ ...prev, [field.key]: val }));
|
|
613
|
+
setFieldErrors(prev => {
|
|
614
|
+
if (!prev[field.key])
|
|
615
|
+
return prev;
|
|
616
|
+
const next = { ...prev };
|
|
617
|
+
delete next[field.key];
|
|
618
|
+
return next;
|
|
619
|
+
});
|
|
620
|
+
} }) }, field.key));
|
|
621
|
+
});
|
|
622
|
+
// Wizard "Siguiente": gate only the CURRENT step's required (visible) fields,
|
|
623
|
+
// then advance. Mirrors handleSubmit's required check but scoped to the step.
|
|
624
|
+
const goNextStep = () => {
|
|
625
|
+
const step = groups[clampedStep];
|
|
626
|
+
const missing = {};
|
|
627
|
+
for (const field of step?.fields ?? []) {
|
|
628
|
+
if (field.required && !formValues[field.key] && formValues[field.key] !== 0 && formValues[field.key] !== false) {
|
|
629
|
+
missing[field.key] = localizeFieldIssue({ code: 'required' }, field.label, t);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
if (Object.keys(missing).length) {
|
|
633
|
+
setFieldErrors(missing);
|
|
634
|
+
toast.error(t('dynamic.validation_failed', { defaultValue: 'Revisa los campos marcados' }));
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
setFieldErrors({});
|
|
638
|
+
setStepIndex(Math.min(clampedStep + 1, groups.length - 1));
|
|
639
|
+
};
|
|
640
|
+
const goBackStep = () => setStepIndex(Math.max(clampedStep - 1, 0));
|
|
641
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-2xl max-h-[90vh] flex flex-col p-0 gap-0 overflow-hidden", children: [_jsxs(DialogHeader, { className: "p-6 pb-4 border-b shrink-0", children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: config.description })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-6", children: loading ? (_jsx(LoadingSkeleton, {})) : modalMeta ? (_jsx(ModelContext.Provider, { value: model, children: _jsx(ImageUrlContext.Provider, { value: getImageUrl, children: _jsx(TimeZoneContext.Provider, { value: timeZone, children: _jsxs(CurrencyContext.Provider, { value: currency, children: [_jsxs("form", { id: "dynamic-record-form", onSubmit: handleSubmit, className: "grid gap-y-4", children: [isSteps && (_jsx(WizardProgress, { groups: groups, stepIndex: clampedStep })), (isSteps ? [groups[clampedStep]] : groups).map(group => (_jsx(FieldSection, { group: group, children: _jsx("div", { className: "grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2", children: renderFields(group.fields) }) }, group.key))), record?.external_url && (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2", children: _jsx("div", { className: "sm:col-span-2 min-w-0", children: _jsxs("a", { href: record.external_url, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1.5 text-sm text-primary hover:underline mt-1", children: [_jsx(ExternalLink, { className: "h-3.5 w-3.5" }), "Ver en ", record.external_provider ?? 'proveedor externo'] }) }) }))] }), !isCreate && record && relations.length > 0 && (_jsx("div", { className: "mt-6", children: _jsx(DynamicRelations, { record: record, relations: relations, lineSubtable: true, canCreate: mode === 'edit', canEdit: mode === 'edit', canDelete: mode === 'edit', onChange: handleChildChange }) }))] }) }) }) })) : null }), _jsxs(DialogFooter, { className: "p-4 border-t shrink-0 sm:justify-between", children: [isView && onOpenFullPage ? (_jsxs(Button, { variant: "ghost", size: "sm", className: "text-muted-foreground", onClick: () => { onOpenChange(false); onOpenFullPage(); }, children: [_jsx(ExternalLink, { className: "mr-1.5 h-3.5 w-3.5" }), "Ver p\u00E1gina completa"] })) : _jsx("span", {}), _jsxs("div", { className: "flex items-center gap-2", children: [isSteps && clampedStep > 0 ? (_jsx(Button, { variant: "outline", onClick: goBackStep, disabled: saving || deleting, children: "Anterior" })) : (_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: saving || deleting, children: config.cancelLabel })), isView && onDelete && (_jsxs(Button, { variant: "destructive", onClick: handleDelete, disabled: deleting || loading, children: [deleting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), deleting ? 'Eliminando...' : 'Eliminar'] })), isView && onEdit && (_jsx(Button, { onClick: onEdit, disabled: deleting || loading, children: "Editar" })), isEditable && isSteps && !isLastStep && (_jsx(Button, { type: "button", onClick: goNextStep, disabled: saving || loading, children: "Siguiente" })), isEditable && (!isSteps || isLastStep) && (_jsxs(Button, { type: "submit", form: "dynamic-record-form", disabled: saving || loading, children: [saving && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), saving ? config.submittingLabel : config.submitLabel] }))] })] })] }) }));
|
|
582
642
|
}
|
|
583
643
|
function LoadingSkeleton() {
|
|
584
644
|
return (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-4", children: Array.from({ length: 6 }).map((_, i) => (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Skeleton, { className: "h-3.5 w-24" }), _jsx(Skeleton, { className: "h-9 w-full" })] }, i))) }));
|
package/dist/dynamic-form.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FormLayout } from './form-layout';
|
|
1
2
|
import type { ActionFieldDef } from './types';
|
|
2
3
|
import { buildZodSchema, resolveWidget } from './dynamic-form-schema';
|
|
3
4
|
export { buildZodSchema, resolveWidget };
|
|
@@ -14,6 +15,14 @@ export interface DynamicFormProps {
|
|
|
14
15
|
submitLabel?: string;
|
|
15
16
|
cancelLabel?: string;
|
|
16
17
|
disabled?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Declarative form layout served on the model metadata (kernel PR #230).
|
|
20
|
+
* When present the visible fields are grouped by their `section` respecting
|
|
21
|
+
* `sections` order: `mode:"sections"` stacks (optionally collapsible)
|
|
22
|
+
* sections; `mode:"steps"` renders a Anterior/Siguiente wizard. Absent → the
|
|
23
|
+
* legacy flat list (unchanged).
|
|
24
|
+
*/
|
|
25
|
+
formLayout?: FormLayout;
|
|
17
26
|
}
|
|
18
|
-
export declare function DynamicForm({ fields, initialValues, onSubmit, onCancel, submitLabel, cancelLabel, disabled, }: DynamicFormProps): import("react").JSX.Element;
|
|
27
|
+
export declare function DynamicForm({ fields, initialValues, onSubmit, onCancel, submitLabel, cancelLabel, disabled, formLayout, }: DynamicFormProps): import("react").JSX.Element;
|
|
19
28
|
//# sourceMappingURL=dynamic-form.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-form.d.ts","sourceRoot":"","sources":["../src/dynamic-form.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dynamic-form.d.ts","sourceRoot":"","sources":["../src/dynamic-form.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAcrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,EACH,cAAc,EACd,aAAa,EAOhB,MAAM,uBAAuB,CAAA;AAQ9B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,CAAA;CAC1B;AAED,wBAAgB,WAAW,CAAC,EACxB,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,WAAuB,EACvB,WAAwB,EACxB,QAAgB,EAChB,UAAU,GACb,EAAE,gBAAgB,+BA8LlB"}
|
package/dist/dynamic-form.js
CHANGED
|
@@ -3,6 +3,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
// pattern + ActionFieldDef renderer so callers can reuse the form layout
|
|
4
4
|
// outside the full record-edit modal.
|
|
5
5
|
import { useEffect, useMemo, useState } from 'react';
|
|
6
|
+
import { groupFieldsBySection } from './form-layout';
|
|
7
|
+
import { FieldSection, WizardProgress } from './form-layout-ui';
|
|
6
8
|
import { Input, Textarea, Label, Switch, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@asteby/metacore-ui/primitives';
|
|
7
9
|
import { buildZodSchema, resolveWidget, isLineItemsField, evaluateBalance, applyOptionWhen, getDependsOn, getVisibleWhen, evaluateVisibleWhen, } from './dynamic-form-schema';
|
|
8
10
|
import { useOptionsResolver } from './use-options-resolver';
|
|
@@ -17,7 +19,7 @@ export { DynamicSelectField } from './dynamic-select-field';
|
|
|
17
19
|
export { DynamicDateField } from './dynamic-date-field';
|
|
18
20
|
export { UploadField } from './upload-field';
|
|
19
21
|
export { IconPickerField } from './icon-picker-field';
|
|
20
|
-
export function DynamicForm({ fields, initialValues, onSubmit, onCancel, submitLabel = 'Guardar', cancelLabel = 'Cancelar', disabled = false, }) {
|
|
22
|
+
export function DynamicForm({ fields, initialValues, onSubmit, onCancel, submitLabel = 'Guardar', cancelLabel = 'Cancelar', disabled = false, formLayout, }) {
|
|
21
23
|
const [values, setValues] = useState({});
|
|
22
24
|
const [errors, setErrors] = useState({});
|
|
23
25
|
const [submitting, setSubmitting] = useState(false);
|
|
@@ -47,6 +49,18 @@ export function DynamicForm({ fields, initialValues, onSubmit, onCancel, submitL
|
|
|
47
49
|
}
|
|
48
50
|
return false;
|
|
49
51
|
}, [visibleFields, values]);
|
|
52
|
+
// Group visible fields by their form_layout section (empty sections drop out
|
|
53
|
+
// because visibleFields is already visibility-filtered). Without a layout
|
|
54
|
+
// this is a single default group → the render below collapses to the legacy
|
|
55
|
+
// flat grid, byte-for-byte.
|
|
56
|
+
const groups = useMemo(() => groupFieldsBySection(visibleFields, formLayout), [visibleFields, formLayout]);
|
|
57
|
+
const isSteps = formLayout?.mode === 'steps' && groups.length > 1;
|
|
58
|
+
// Wizard step cursor (steps mode only). Clamped whenever the group count
|
|
59
|
+
// shrinks (a visible_when flip can empty a trailing step's section).
|
|
60
|
+
const [stepIndex, setStepIndex] = useState(0);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
setStepIndex((i) => Math.min(i, Math.max(groups.length - 1, 0)));
|
|
63
|
+
}, [groups.length]);
|
|
50
64
|
useEffect(() => {
|
|
51
65
|
const defaults = {};
|
|
52
66
|
for (const f of editableFields) {
|
|
@@ -84,11 +98,43 @@ export function DynamicForm({ fields, initialValues, onSubmit, onCancel, submitL
|
|
|
84
98
|
setSubmitting(false);
|
|
85
99
|
}
|
|
86
100
|
};
|
|
101
|
+
// Renders one group's fields into the responsive 2-column grid: scalar
|
|
102
|
+
// header fields flow through it; line-items grids (and textareas) span full
|
|
103
|
+
// width so the row table / memo gets room. Shared by every layout mode.
|
|
104
|
+
const renderGrid = (groupFields) => (_jsx("div", { className: "grid gap-4 sm:grid-cols-2", children: groupFields.map((field) => (_jsx(FieldRow, { field: field, value: values[field.key], onChange: (v) => update(field.key, v), values: values, error: errors[field.key], initialValues: initialValues }, field.key))) }));
|
|
105
|
+
// ── Steps (wizard) mode ────────────────────────────────────────────────
|
|
106
|
+
// One step per section; Anterior/Siguiente navigate, submit only on the
|
|
107
|
+
// last step. Advancing validates just the current step's fields so a later
|
|
108
|
+
// step can't be blocked by an earlier untouched one and vice-versa.
|
|
109
|
+
if (isSteps) {
|
|
110
|
+
const step = groups[stepIndex];
|
|
111
|
+
const isLast = stepIndex === groups.length - 1;
|
|
112
|
+
const goNext = () => {
|
|
113
|
+
const stepSchema = buildZodSchema(step.fields);
|
|
114
|
+
const result = stepSchema.safeParse(values);
|
|
115
|
+
if (!result.success) {
|
|
116
|
+
const next = {};
|
|
117
|
+
for (const issue of result.error.issues) {
|
|
118
|
+
const key = issue.path[0];
|
|
119
|
+
if (typeof key === 'string' && !next[key])
|
|
120
|
+
next[key] = issue.message;
|
|
121
|
+
}
|
|
122
|
+
setErrors(next);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
setErrors({});
|
|
126
|
+
setStepIndex((i) => Math.min(i + 1, groups.length - 1));
|
|
127
|
+
};
|
|
128
|
+
const goBack = () => setStepIndex((i) => Math.max(i - 1, 0));
|
|
129
|
+
return (_jsxs("form", { onSubmit: handleSubmit, className: "grid gap-4", children: [_jsx(WizardProgress, { groups: groups, stepIndex: stepIndex }), renderGrid(step.fields), _jsxs("div", { className: "flex justify-between gap-2 pt-2", children: [stepIndex > 0 ? (_jsx(Button, { type: "button", variant: "outline", onClick: goBack, disabled: submitting || disabled, children: "Anterior" })) : onCancel ? (_jsx(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: submitting || disabled, children: cancelLabel })) : (_jsx("span", {})), isLast ? (_jsx(Button, { type: "submit", disabled: submitting || disabled || balanceBlocked, children: submitLabel })) : (_jsx(Button, { type: "button", onClick: goNext, disabled: submitting || disabled, children: "Siguiente" }))] })] }));
|
|
130
|
+
}
|
|
131
|
+
// ── Sections / flat mode ───────────────────────────────────────────────
|
|
87
132
|
// Layout: scalar header fields flow through a responsive 2-column grid;
|
|
88
133
|
// line-items grids (and textareas) span the full width so the row table /
|
|
89
134
|
// memo gets room. Mirrors the pro look of the federated journal modal but
|
|
90
|
-
// stays fully declarative — driven only by field shape.
|
|
91
|
-
|
|
135
|
+
// stays fully declarative — driven only by field shape. With no layout this
|
|
136
|
+
// is a single default group rendered without section chrome (unchanged).
|
|
137
|
+
return (_jsxs("form", { onSubmit: handleSubmit, className: "grid gap-4", children: [groups.map((group) => (_jsx(FieldSection, { group: group, children: renderGrid(group.fields) }, group.key))), _jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [onCancel && (_jsx(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: submitting || disabled, children: cancelLabel })), _jsx(Button, { type: "submit", disabled: submitting || disabled || balanceBlocked, children: submitLabel })] })] }));
|
|
92
138
|
}
|
|
93
139
|
// One form field row: label + renderer + inline error. Encapsulated as its own
|
|
94
140
|
// component so a STATIC enum select whose options are all gated out by a sibling
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FieldGroup } from './form-layout';
|
|
2
|
+
/**
|
|
3
|
+
* Section chrome for `mode: "sections"`. Wraps a group's (already gridded)
|
|
4
|
+
* fields in a titled block.
|
|
5
|
+
* - The default/orphan group renders with NO chrome, so a layout-less form (one
|
|
6
|
+
* default group) is visually identical to the legacy flat list.
|
|
7
|
+
* - A section whose `collapsed` is defined (true/false) is rendered COLLAPSIBLE,
|
|
8
|
+
* starting collapsed when `collapsed === true`. A section with no `collapsed`
|
|
9
|
+
* flag renders as a plain, always-open titled block.
|
|
10
|
+
*/
|
|
11
|
+
export declare function FieldSection({ group, children, }: {
|
|
12
|
+
group: FieldGroup<unknown>;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}): import("react").JSX.Element;
|
|
15
|
+
/**
|
|
16
|
+
* Progress bar for `mode: "steps"`: one filled segment per completed/current
|
|
17
|
+
* step plus a "Paso i/n · <title>" caption. Mirrors the WizardActionModal look
|
|
18
|
+
* so a model wizard and an action wizard read the same.
|
|
19
|
+
*/
|
|
20
|
+
export declare function WizardProgress({ groups, stepIndex, stepLabel, }: {
|
|
21
|
+
groups: FieldGroup<unknown>[];
|
|
22
|
+
stepIndex: number;
|
|
23
|
+
stepLabel?: string;
|
|
24
|
+
}): import("react").JSX.Element;
|
|
25
|
+
//# sourceMappingURL=form-layout-ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-layout-ui.d.ts","sourceRoot":"","sources":["../src/form-layout-ui.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,GACX,EAAE;IACC,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC5B,+BA6CA;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,SAAkB,GACrB,EAAE;IACC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB,+BA2BA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Presentational chrome for declarative form layouts (see `form-layout.ts`).
|
|
3
|
+
// Kept apart from the grouping logic so the pure helper stays React-free and the
|
|
4
|
+
// two renderers (`dynamic-form.tsx`, `dialogs/dynamic-record.tsx`) share one
|
|
5
|
+
// look for sections and the wizard progress bar.
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger, Button, } from '@asteby/metacore-ui/primitives';
|
|
8
|
+
import { ChevronDown } from 'lucide-react';
|
|
9
|
+
/**
|
|
10
|
+
* Section chrome for `mode: "sections"`. Wraps a group's (already gridded)
|
|
11
|
+
* fields in a titled block.
|
|
12
|
+
* - The default/orphan group renders with NO chrome, so a layout-less form (one
|
|
13
|
+
* default group) is visually identical to the legacy flat list.
|
|
14
|
+
* - A section whose `collapsed` is defined (true/false) is rendered COLLAPSIBLE,
|
|
15
|
+
* starting collapsed when `collapsed === true`. A section with no `collapsed`
|
|
16
|
+
* flag renders as a plain, always-open titled block.
|
|
17
|
+
*/
|
|
18
|
+
export function FieldSection({ group, children, }) {
|
|
19
|
+
const collapsible = group.collapsed !== undefined;
|
|
20
|
+
const [open, setOpen] = useState(!group.collapsed);
|
|
21
|
+
if (group.isDefault)
|
|
22
|
+
return _jsx(_Fragment, { children: children });
|
|
23
|
+
const header = (_jsxs("div", { className: "min-w-0 text-left", children: [group.title && (_jsx("h3", { className: "text-sm font-semibold leading-none", children: group.title })), group.description && (_jsx("p", { className: "pt-1 text-sm text-muted-foreground", children: group.description }))] }));
|
|
24
|
+
if (!collapsible) {
|
|
25
|
+
return (_jsxs("section", { className: "grid gap-3", children: [(group.title || group.description) && header, children] }));
|
|
26
|
+
}
|
|
27
|
+
return (_jsxs(Collapsible, { open: open, onOpenChange: setOpen, className: "grid gap-3", children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "ghost", className: "h-auto w-full justify-between px-0 py-1 hover:bg-transparent", children: [header, _jsx(ChevronDown, { className: 'h-4 w-4 shrink-0 transition-transform ' + (open ? 'rotate-180' : '') })] }) }), _jsx(CollapsibleContent, { className: "grid gap-3", children: children })] }));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Progress bar for `mode: "steps"`: one filled segment per completed/current
|
|
31
|
+
* step plus a "Paso i/n · <title>" caption. Mirrors the WizardActionModal look
|
|
32
|
+
* so a model wizard and an action wizard read the same.
|
|
33
|
+
*/
|
|
34
|
+
export function WizardProgress({ groups, stepIndex, stepLabel = 'Paso', }) {
|
|
35
|
+
const current = groups[stepIndex];
|
|
36
|
+
return (_jsxs("div", { className: "pt-2", children: [_jsx("div", { className: "flex items-center gap-1.5", role: "list", "aria-label": "progress", children: groups.map((g, i) => (_jsx("div", { role: "listitem", "aria-current": i === stepIndex ? 'step' : undefined, className: "h-1.5 flex-1 rounded-full", style: {
|
|
37
|
+
backgroundColor: i <= stepIndex ? 'hsl(var(--primary))' : 'hsl(var(--muted))',
|
|
38
|
+
} }, g.key))) }), _jsxs("p", { className: "pt-2 text-sm text-muted-foreground", children: [stepLabel, " ", stepIndex + 1, "/", groups.length, current?.title ? ` · ${current.title}` : ''] }), current?.description && (_jsx("p", { className: "pt-1 text-sm text-muted-foreground", children: current.description }))] }));
|
|
39
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** One declared section of a model form. `title`/`description` arrive already
|
|
2
|
+
* localized from the kernel and are rendered verbatim. */
|
|
3
|
+
export interface FormSection {
|
|
4
|
+
key: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
/** Sections mode only: render this section collapsed on first paint. */
|
|
8
|
+
collapsed?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** Model-level layout directive. `mode` defaults to `"sections"`. */
|
|
11
|
+
export interface FormLayout {
|
|
12
|
+
mode?: 'sections' | 'steps';
|
|
13
|
+
sections?: FormSection[];
|
|
14
|
+
}
|
|
15
|
+
/** A resolved group of fields ready to render: a section plus the (already
|
|
16
|
+
* visibility-filtered) fields that belong to it. */
|
|
17
|
+
export interface FieldGroup<F> {
|
|
18
|
+
/** Section key, or `__default__` for the orphan group. */
|
|
19
|
+
key: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
collapsed?: boolean;
|
|
23
|
+
/** True for the synthetic group holding section-less / unknown-section fields. */
|
|
24
|
+
isDefault: boolean;
|
|
25
|
+
fields: F[];
|
|
26
|
+
}
|
|
27
|
+
/** The synthetic key of the orphan group (fields with no / unknown `section`). */
|
|
28
|
+
export declare const DEFAULT_SECTION_KEY = "__default__";
|
|
29
|
+
/** Reads a field's `section` reference, tolerating a camelCase alias. */
|
|
30
|
+
export declare function getFieldSection(field: {
|
|
31
|
+
section?: string;
|
|
32
|
+
Section?: string;
|
|
33
|
+
} | null | undefined): string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Groups already-filtered (visible) fields by their `section`, honoring the
|
|
36
|
+
* order of `layout.sections`.
|
|
37
|
+
*
|
|
38
|
+
* Contract:
|
|
39
|
+
* - No `layout` (or no `sections`) → a single default group carrying every
|
|
40
|
+
* field in its original order. Callers render this exactly like the legacy
|
|
41
|
+
* flat list, so the layout-less path is byte-for-byte the current behaviour.
|
|
42
|
+
* - Fields whose `section` is empty or references an UNKNOWN section key are
|
|
43
|
+
* collected into ONE default group placed FIRST (before any declared
|
|
44
|
+
* section) — the consistent, documented choice: general/uncategorized fields
|
|
45
|
+
* lead, declared sections follow in their authored order.
|
|
46
|
+
* - A declared section with zero visible fields is OMITTED entirely, so a
|
|
47
|
+
* section whose only members are hidden by `visible_when` never renders an
|
|
48
|
+
* empty shell (and never yields an empty wizard step). Because the caller
|
|
49
|
+
* passes the already visibility-filtered list, this falls out for free.
|
|
50
|
+
*/
|
|
51
|
+
export declare function groupFieldsBySection<F extends {
|
|
52
|
+
section?: string;
|
|
53
|
+
}>(fields: F[], layout: FormLayout | undefined): FieldGroup<F>[];
|
|
54
|
+
//# sourceMappingURL=form-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-layout.d.ts","sourceRoot":"","sources":["../src/form-layout.ts"],"names":[],"mappings":"AAgBA;0DAC0D;AAC1D,MAAM,WAAW,WAAW;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,qEAAqE;AACrE,MAAM,WAAW,UAAU;IACvB,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAA;IAC3B,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;CAC3B;AAED;oDACoD;AACpD,MAAM,WAAW,UAAU,CAAC,CAAC;IACzB,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,kFAAkF;IAClF,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,CAAC,EAAE,CAAA;CACd;AAED,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,gBAAgB,CAAA;AAEhD,yEAAyE;AACzE,wBAAgB,eAAe,CAC3B,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GACjE,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/D,MAAM,EAAE,CAAC,EAAE,EACX,MAAM,EAAE,UAAU,GAAG,SAAS,GAC/B,UAAU,CAAC,CAAC,CAAC,EAAE,CAsCjB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Declarative form layout (kernel PR #230): a model's create/edit form can
|
|
2
|
+
// declare `form_layout` to group its fields into named sections, rendered either
|
|
3
|
+
// as stacked (optionally collapsible) SECTIONS or as a multi-step WIZARD.
|
|
4
|
+
//
|
|
5
|
+
// Wire shape served on the table/modal metadata:
|
|
6
|
+
// form_layout: {
|
|
7
|
+
// mode: "sections" | "steps", // default "sections"
|
|
8
|
+
// sections: [{ key, title?, description?, collapsed? }]
|
|
9
|
+
// }
|
|
10
|
+
// and, per field/column: `section: "<key>"` referencing a section key.
|
|
11
|
+
//
|
|
12
|
+
// This module owns the PURE grouping logic (no React), so the two renderers
|
|
13
|
+
// (`dynamic-form.tsx`, `dialogs/dynamic-record.tsx`) share one tested
|
|
14
|
+
// implementation and the modal-render machinery never has to be booted under
|
|
15
|
+
// happy-dom just to assert the grouping (same approach as PR #673).
|
|
16
|
+
/** The synthetic key of the orphan group (fields with no / unknown `section`). */
|
|
17
|
+
export const DEFAULT_SECTION_KEY = '__default__';
|
|
18
|
+
/** Reads a field's `section` reference, tolerating a camelCase alias. */
|
|
19
|
+
export function getFieldSection(field) {
|
|
20
|
+
if (!field)
|
|
21
|
+
return undefined;
|
|
22
|
+
const s = field.section ?? field.Section;
|
|
23
|
+
return typeof s === 'string' && s !== '' ? s : undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Groups already-filtered (visible) fields by their `section`, honoring the
|
|
27
|
+
* order of `layout.sections`.
|
|
28
|
+
*
|
|
29
|
+
* Contract:
|
|
30
|
+
* - No `layout` (or no `sections`) → a single default group carrying every
|
|
31
|
+
* field in its original order. Callers render this exactly like the legacy
|
|
32
|
+
* flat list, so the layout-less path is byte-for-byte the current behaviour.
|
|
33
|
+
* - Fields whose `section` is empty or references an UNKNOWN section key are
|
|
34
|
+
* collected into ONE default group placed FIRST (before any declared
|
|
35
|
+
* section) — the consistent, documented choice: general/uncategorized fields
|
|
36
|
+
* lead, declared sections follow in their authored order.
|
|
37
|
+
* - A declared section with zero visible fields is OMITTED entirely, so a
|
|
38
|
+
* section whose only members are hidden by `visible_when` never renders an
|
|
39
|
+
* empty shell (and never yields an empty wizard step). Because the caller
|
|
40
|
+
* passes the already visibility-filtered list, this falls out for free.
|
|
41
|
+
*/
|
|
42
|
+
export function groupFieldsBySection(fields, layout) {
|
|
43
|
+
if (!layout?.sections?.length) {
|
|
44
|
+
return [{ key: DEFAULT_SECTION_KEY, isDefault: true, fields }];
|
|
45
|
+
}
|
|
46
|
+
const known = new Set(layout.sections.map((s) => s.key));
|
|
47
|
+
const bySection = new Map();
|
|
48
|
+
const orphans = [];
|
|
49
|
+
for (const f of fields) {
|
|
50
|
+
const sec = getFieldSection(f);
|
|
51
|
+
if (sec && known.has(sec)) {
|
|
52
|
+
const arr = bySection.get(sec);
|
|
53
|
+
if (arr)
|
|
54
|
+
arr.push(f);
|
|
55
|
+
else
|
|
56
|
+
bySection.set(sec, [f]);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
orphans.push(f);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const groups = [];
|
|
63
|
+
// Orphan/default group leads (fields with no / unknown section).
|
|
64
|
+
if (orphans.length) {
|
|
65
|
+
groups.push({ key: DEFAULT_SECTION_KEY, isDefault: true, fields: orphans });
|
|
66
|
+
}
|
|
67
|
+
for (const s of layout.sections) {
|
|
68
|
+
const secFields = bySection.get(s.key);
|
|
69
|
+
if (!secFields || secFields.length === 0)
|
|
70
|
+
continue; // hide empty section
|
|
71
|
+
groups.push({
|
|
72
|
+
key: s.key,
|
|
73
|
+
title: s.title,
|
|
74
|
+
description: s.description,
|
|
75
|
+
collapsed: s.collapsed,
|
|
76
|
+
isDefault: false,
|
|
77
|
+
fields: secFields,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return groups;
|
|
81
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export { useStageOverrides, type StageOverridePatch, type UseStageOverridesResul
|
|
|
11
11
|
export { DynamicView, resolveViewRenderer, readViewFromSearch, resolveActiveView, type DynamicViewProps, } from './dynamic-view';
|
|
12
12
|
export { useDynamicFilters, type UseDynamicFiltersOptions, type UseDynamicFiltersResult, } from './use-dynamic-filters';
|
|
13
13
|
export * from './dynamic-form';
|
|
14
|
+
export * from './form-layout';
|
|
15
|
+
export * from './form-layout-ui';
|
|
14
16
|
export { FieldGrid, FieldCell, FieldLabel } from './field-grid';
|
|
15
17
|
export { ActionModalDispatcher, type ActionModalProps, } from './action-modal-dispatcher';
|
|
16
18
|
export { ModelActionToolbar, useModelActions, type ModelActionToolbarProps, type ActionPlacement, } from './model-action-toolbar';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,8 @@ export { useStageOverrides, } from './stage-overrides';
|
|
|
16
16
|
export { DynamicView, resolveViewRenderer, readViewFromSearch, resolveActiveView, } from './dynamic-view';
|
|
17
17
|
export { useDynamicFilters, } from './use-dynamic-filters';
|
|
18
18
|
export * from './dynamic-form';
|
|
19
|
+
export * from './form-layout';
|
|
20
|
+
export * from './form-layout-ui';
|
|
19
21
|
export { FieldGrid, FieldCell, FieldLabel } from './field-grid';
|
|
20
22
|
export { ActionModalDispatcher, } from './action-modal-dispatcher';
|
|
21
23
|
export { ModelActionToolbar, useModelActions, } from './model-action-toolbar';
|