@morscherlab/mld-sdk 0.6.5 → 0.7.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.
Files changed (63) hide show
  1. package/dist/__tests__/composables/formBuilderRegistry.test.d.ts +1 -0
  2. package/dist/__tests__/composables/useFormBuilder.test.d.ts +1 -0
  3. package/dist/components/BaseButton.vue.d.ts +1 -1
  4. package/dist/components/BasePill.vue.d.ts +1 -1
  5. package/dist/components/DropdownButton.vue.d.ts +1 -1
  6. package/dist/components/FormActions.vue.d.ts +33 -0
  7. package/dist/components/FormActions.vue.js +76 -0
  8. package/dist/components/FormActions.vue.js.map +1 -0
  9. package/dist/components/FormActions.vue3.js +6 -0
  10. package/dist/components/FormActions.vue3.js.map +1 -0
  11. package/dist/components/FormBuilder.vue.js +205 -0
  12. package/dist/components/FormBuilder.vue.js.map +1 -0
  13. package/dist/components/FormBuilder.vue3.js +6 -0
  14. package/dist/components/FormBuilder.vue3.js.map +1 -0
  15. package/dist/components/FormFieldRenderer.vue.d.ts +31 -0
  16. package/dist/components/FormFieldRenderer.vue.js +48 -0
  17. package/dist/components/FormFieldRenderer.vue.js.map +1 -0
  18. package/dist/components/FormFieldRenderer.vue2.js +5 -0
  19. package/dist/components/FormFieldRenderer.vue2.js.map +1 -0
  20. package/dist/components/FormSection.vue.d.ts +43 -0
  21. package/dist/components/FormSection.vue.js +117 -0
  22. package/dist/components/FormSection.vue.js.map +1 -0
  23. package/dist/components/FormSection.vue3.js +6 -0
  24. package/dist/components/FormSection.vue3.js.map +1 -0
  25. package/dist/components/IconButton.vue.d.ts +1 -1
  26. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  27. package/dist/components/ProgressBar.vue.d.ts +1 -1
  28. package/dist/components/ReagentList.vue.d.ts +2 -2
  29. package/dist/components/ResourceCard.vue.d.ts +1 -1
  30. package/dist/components/SegmentedControl.vue.d.ts +1 -1
  31. package/dist/components/WellEditPopup.vue.d.ts +2 -2
  32. package/dist/components/index.d.ts +4 -0
  33. package/dist/components/index.js +19 -8
  34. package/dist/components/index.js.map +1 -1
  35. package/dist/composables/formBuilderRegistry.d.ts +13 -0
  36. package/dist/composables/formBuilderRegistry.js +87 -0
  37. package/dist/composables/formBuilderRegistry.js.map +1 -0
  38. package/dist/composables/index.d.ts +2 -0
  39. package/dist/composables/index.js +6 -0
  40. package/dist/composables/index.js.map +1 -1
  41. package/dist/composables/useFormBuilder.d.ts +23 -0
  42. package/dist/composables/useFormBuilder.js +264 -0
  43. package/dist/composables/useFormBuilder.js.map +1 -0
  44. package/dist/styles.css +239 -4
  45. package/dist/types/form-builder.d.ts +167 -0
  46. package/dist/types/index.d.ts +1 -0
  47. package/package.json +1 -1
  48. package/src/__tests__/composables/formBuilderRegistry.test.ts +187 -0
  49. package/src/__tests__/composables/useFormBuilder.test.ts +917 -0
  50. package/src/components/FormActions.vue +92 -0
  51. package/src/components/FormBuilder.vue +214 -0
  52. package/src/components/FormFieldRenderer.vue +58 -0
  53. package/src/components/FormSection.vue +90 -0
  54. package/src/components/index.ts +6 -0
  55. package/src/composables/formBuilderRegistry.ts +79 -0
  56. package/src/composables/index.ts +6 -0
  57. package/src/composables/useFormBuilder.ts +382 -0
  58. package/src/styles/components/app-container.css +1 -0
  59. package/src/styles/components/app-layout.css +1 -2
  60. package/src/styles/components/form-builder.css +69 -0
  61. package/src/styles/index.css +1 -0
  62. package/src/types/form-builder.ts +197 -0
  63. package/src/types/index.ts +14 -0
@@ -0,0 +1,117 @@
1
+ import { defineComponent, computed, openBlock, createElementBlock, renderSlot, createBlock, withCtx, createElementVNode, normalizeStyle, Fragment, renderList, createVNode, toDisplayString, createCommentVNode } from "vue";
2
+ import _sfc_main$1 from "./CollapsibleCard.vue.js";
3
+ /* empty css */
4
+ import _sfc_main$2 from "./FormFieldRenderer.vue.js";
5
+ const _hoisted_1 = {
6
+ key: 0,
7
+ class: "mld-form-section"
8
+ };
9
+ const _hoisted_2 = {
10
+ key: 1,
11
+ class: "mld-form-section--static"
12
+ };
13
+ const _hoisted_3 = {
14
+ key: 0,
15
+ class: "mld-form-section__header"
16
+ };
17
+ const _hoisted_4 = {
18
+ key: 0,
19
+ class: "mld-form-section__title"
20
+ };
21
+ const _hoisted_5 = {
22
+ key: 1,
23
+ class: "mld-form-section__description"
24
+ };
25
+ const _sfc_main = /* @__PURE__ */ defineComponent({
26
+ __name: "FormSection",
27
+ props: {
28
+ section: {},
29
+ builder: {}
30
+ },
31
+ setup(__props) {
32
+ const props = __props;
33
+ const visibleFields = computed(
34
+ () => props.section.fields.filter((f) => props.builder.isFieldVisible(f.name))
35
+ );
36
+ const gridStyle = computed(() => ({
37
+ gridTemplateColumns: `repeat(${props.section.columns ?? 1}, 1fr)`
38
+ }));
39
+ return (_ctx, _cache) => {
40
+ return visibleFields.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_1, [
41
+ renderSlot(_ctx.$slots, `section:${__props.section.id}`, {
42
+ section: __props.section,
43
+ form: __props.builder.form
44
+ }, () => [
45
+ __props.section.collapsible ? (openBlock(), createBlock(_sfc_main$1, {
46
+ key: 0,
47
+ title: __props.section.title,
48
+ subtitle: __props.section.description,
49
+ "default-open": __props.section.defaultOpen ?? true
50
+ }, {
51
+ default: withCtx(() => [
52
+ createElementVNode("div", {
53
+ class: "mld-form-section__grid",
54
+ style: normalizeStyle(gridStyle.value)
55
+ }, [
56
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visibleFields.value, (field) => {
57
+ return openBlock(), createElementBlock("div", {
58
+ key: field.name,
59
+ style: normalizeStyle(field.colSpan ? { gridColumn: `span ${field.colSpan}` } : void 0)
60
+ }, [
61
+ renderSlot(_ctx.$slots, `field:${field.name}`, {
62
+ field,
63
+ form: __props.builder.form,
64
+ fieldProps: __props.builder.form.getFieldProps(field.name)
65
+ }, () => [
66
+ createVNode(_sfc_main$2, {
67
+ field,
68
+ "resolved-props": __props.builder.getResolvedFieldProps(field),
69
+ form: __props.builder.form
70
+ }, null, 8, ["field", "resolved-props", "form"])
71
+ ])
72
+ ], 4);
73
+ }), 128))
74
+ ], 4)
75
+ ]),
76
+ _: 3
77
+ }, 8, ["title", "subtitle", "default-open"])) : (openBlock(), createElementBlock("div", _hoisted_2, [
78
+ __props.section.title || __props.section.description ? (openBlock(), createElementBlock("div", _hoisted_3, [
79
+ __props.section.title ? (openBlock(), createElementBlock("h3", _hoisted_4, toDisplayString(__props.section.title), 1)) : createCommentVNode("", true),
80
+ __props.section.description ? (openBlock(), createElementBlock("p", _hoisted_5, toDisplayString(__props.section.description), 1)) : createCommentVNode("", true)
81
+ ])) : createCommentVNode("", true),
82
+ createElementVNode("div", {
83
+ class: "mld-form-section__grid",
84
+ style: normalizeStyle(gridStyle.value)
85
+ }, [
86
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visibleFields.value, (field) => {
87
+ return openBlock(), createElementBlock("div", {
88
+ key: field.name,
89
+ style: normalizeStyle(field.colSpan ? { gridColumn: `span ${field.colSpan}` } : void 0)
90
+ }, [
91
+ renderSlot(_ctx.$slots, `field:${field.name}`, {
92
+ field,
93
+ form: __props.builder.form,
94
+ fieldProps: __props.builder.form.getFieldProps(field.name)
95
+ }, () => [
96
+ createVNode(_sfc_main$2, {
97
+ field,
98
+ "resolved-props": __props.builder.getResolvedFieldProps(field),
99
+ form: __props.builder.form
100
+ }, null, 8, ["field", "resolved-props", "form"])
101
+ ])
102
+ ], 4);
103
+ }), 128))
104
+ ], 4)
105
+ ]))
106
+ ]),
107
+ renderSlot(_ctx.$slots, `section:${__props.section.id}:after`, {
108
+ form: __props.builder.form
109
+ })
110
+ ])) : createCommentVNode("", true);
111
+ };
112
+ }
113
+ });
114
+ export {
115
+ _sfc_main as default
116
+ };
117
+ //# sourceMappingURL=FormSection.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormSection.vue.js","sources":["../../src/components/FormSection.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Renders a single `FormSectionSchema` inside a FormBuilder.\n *\n * Filters out hidden fields before rendering, applies the section's column\n * grid and per-field `colSpan`, and switches between a collapsible\n * (`CollapsibleCard`) and a static layout based on `section.collapsible`.\n * The entire section is hidden when all its fields are hidden. Consumers can\n * replace the section body via `section:<id>` or inject content after it via\n * `section:<id>:after`, and override individual fields via `field:<name>`.\n */\nimport { computed } from 'vue'\nimport type { FormSectionSchema, UseFormBuilderReturn } from '../types/form-builder'\nimport CollapsibleCard from './CollapsibleCard.vue'\nimport FormFieldRenderer from './FormFieldRenderer.vue'\n\ninterface Props {\n section: FormSectionSchema\n builder: UseFormBuilderReturn<Record<string, unknown>>\n}\n\nconst props = defineProps<Props>()\n\nconst visibleFields = computed(() =>\n props.section.fields.filter((f) => props.builder.isFieldVisible(f.name)),\n)\n\nconst gridStyle = computed(() => ({\n gridTemplateColumns: `repeat(${props.section.columns ?? 1}, 1fr)`,\n}))\n</script>\n\n<template>\n <div v-if=\"visibleFields.length > 0\" class=\"mld-form-section\">\n <slot :name=\"`section:${section.id}`\" :section=\"section\" :form=\"builder.form\">\n <!-- Collapsible variant -->\n <CollapsibleCard\n v-if=\"section.collapsible\"\n :title=\"section.title\"\n :subtitle=\"section.description\"\n :default-open=\"section.defaultOpen ?? true\"\n >\n <div class=\"mld-form-section__grid\" :style=\"gridStyle\">\n <div\n v-for=\"field in visibleFields\"\n :key=\"field.name\"\n :style=\"field.colSpan ? { gridColumn: `span ${field.colSpan}` } : undefined\"\n >\n <slot :name=\"`field:${field.name}`\" :field=\"field\" :form=\"builder.form\" :field-props=\"builder.form.getFieldProps(field.name)\">\n <FormFieldRenderer\n :field=\"field\"\n :resolved-props=\"builder.getResolvedFieldProps(field)\"\n :form=\"builder.form\"\n />\n </slot>\n </div>\n </div>\n </CollapsibleCard>\n\n <!-- Static variant -->\n <div v-else class=\"mld-form-section--static\">\n <div v-if=\"section.title || section.description\" class=\"mld-form-section__header\">\n <h3 v-if=\"section.title\" class=\"mld-form-section__title\">{{ section.title }}</h3>\n <p v-if=\"section.description\" class=\"mld-form-section__description\">{{ section.description }}</p>\n </div>\n <div class=\"mld-form-section__grid\" :style=\"gridStyle\">\n <div\n v-for=\"field in visibleFields\"\n :key=\"field.name\"\n :style=\"field.colSpan ? { gridColumn: `span ${field.colSpan}` } : undefined\"\n >\n <slot :name=\"`field:${field.name}`\" :field=\"field\" :form=\"builder.form\" :field-props=\"builder.form.getFieldProps(field.name)\">\n <FormFieldRenderer\n :field=\"field\"\n :resolved-props=\"builder.getResolvedFieldProps(field)\"\n :form=\"builder.form\"\n />\n </slot>\n </div>\n </div>\n </div>\n </slot>\n\n <slot :name=\"`section:${section.id}:after`\" :form=\"builder.form\" />\n </div>\n</template>\n\n<style>\n@import '../styles/components/form-builder.css';\n</style>\n"],"names":["_openBlock","_createElementBlock","_renderSlot","_createBlock","CollapsibleCard","_createElementVNode","_Fragment","_renderList","_normalizeStyle","_createVNode","FormFieldRenderer","_toDisplayString"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,UAAM,QAAQ;AAEd,UAAM,gBAAgB;AAAA,MAAS,MAC7B,MAAM,QAAQ,OAAO,OAAO,CAAC,MAAM,MAAM,QAAQ,eAAe,EAAE,IAAI,CAAC;AAAA,IAAA;AAGzE,UAAM,YAAY,SAAS,OAAO;AAAA,MAChC,qBAAqB,UAAU,MAAM,QAAQ,WAAW,CAAC;AAAA,IAAA,EACzD;;AAIW,aAAA,cAAA,MAAc,SAAM,KAA/BA,aAAAC,mBAmDM,OAnDN,YAmDM;AAAA,QAlDJC,WA+CO,KAAA,QAAA,WA/CiB,QAAA,QAAQ,EAAE,IAAA;AAAA,UAAK,SAAS,QAAA;AAAA,UAAU,MAAM,QAAA,QAAQ;AAAA,QAAA,GAAxE,MA+CO;AAAA,UA5CG,QAAA,QAAQ,4BADhBC,YAqBkBC,aAAA;AAAA;YAnBf,OAAO,QAAA,QAAQ;AAAA,YACf,UAAU,QAAA,QAAQ;AAAA,YAClB,gBAAc,QAAA,QAAQ,eAAW;AAAA,UAAA;6BAElC,MAcM;AAAA,cAdNC,mBAcM,OAAA;AAAA,gBAdD,OAAM;AAAA,gBAA0B,sBAAO,UAAA,KAAS;AAAA,cAAA;kCACnDJ,mBAYMK,UAAA,MAAAC,WAXY,cAAA,OAAa,CAAtB,UAAK;sCADdN,mBAYM,OAAA;AAAA,oBAVH,KAAK,MAAM;AAAA,oBACX,OAAKO,eAAE,MAAM,gCAAgC,MAAM,OAAO,GAAA,IAAO,MAAS;AAAA,kBAAA;oBAE3EN,WAMO,KAAA,QAAA,SANe,MAAM,IAAI,IAAA;AAAA,sBAAK;AAAA,sBAAe,MAAM,QAAA,QAAQ;AAAA,sBAAO,YAAa,gBAAQ,KAAK,cAAc,MAAM,IAAI;AAAA,oBAAA,GAA3H,MAMO;AAAA,sBALLO,YAIEC,aAAA;AAAA,wBAHC;AAAA,wBACA,kBAAgB,QAAA,QAAQ,sBAAsB,KAAK;AAAA,wBACnD,MAAM,QAAA,QAAQ;AAAA,sBAAA;;;;;;;2DAQzBV,aAAAC,mBAoBM,OApBN,YAoBM;AAAA,YAnBO,QAAA,QAAQ,SAAS,QAAA,QAAQ,eAApCD,aAAAC,mBAGM,OAHN,YAGM;AAAA,cAFM,QAAA,QAAQ,SAAlBD,UAAA,GAAAC,mBAAiF,MAAjF,YAAiFU,gBAArB,QAAA,QAAQ,KAAK,GAAA,CAAA;cAChE,QAAA,QAAQ,eAAjBX,UAAA,GAAAC,mBAAiG,KAAjG,YAAiGU,gBAA1B,QAAA,QAAQ,WAAW,GAAA,CAAA;;YAE5FN,mBAcM,OAAA;AAAA,cAdD,OAAM;AAAA,cAA0B,sBAAO,UAAA,KAAS;AAAA,YAAA;gCACnDJ,mBAYMK,UAAA,MAAAC,WAXY,cAAA,OAAa,CAAtB,UAAK;oCADdN,mBAYM,OAAA;AAAA,kBAVH,KAAK,MAAM;AAAA,kBACX,OAAKO,eAAE,MAAM,gCAAgC,MAAM,OAAO,GAAA,IAAO,MAAS;AAAA,gBAAA;kBAE3EN,WAMO,KAAA,QAAA,SANe,MAAM,IAAI,IAAA;AAAA,oBAAK;AAAA,oBAAe,MAAM,QAAA,QAAQ;AAAA,oBAAO,YAAa,gBAAQ,KAAK,cAAc,MAAM,IAAI;AAAA,kBAAA,GAA3H,MAMO;AAAA,oBALLO,YAIEC,aAAA;AAAA,sBAHC;AAAA,sBACA,kBAAgB,QAAA,QAAQ,sBAAsB,KAAK;AAAA,sBACnD,MAAM,QAAA,QAAQ;AAAA,oBAAA;;;;;;;QAQ3BR,WAAmE,KAAA,QAAA,WAA3C,QAAA,QAAQ,EAAE,UAAA;AAAA,UAAW,MAAM,QAAA,QAAQ;AAAA,QAAA;;;;;"}
@@ -0,0 +1,6 @@
1
+ import _sfc_main from "./FormSection.vue.js";
2
+ /* empty css */
3
+ export {
4
+ _sfc_main as default
5
+ };
6
+ //# sourceMappingURL=FormSection.vue3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormSection.vue3.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -21,8 +21,8 @@ declare const __VLS_component: import('vue').DefineComponent<Props, {}, {}, {},
21
21
  onClick?: ((event: MouseEvent) => any) | undefined;
22
22
  }>, {
23
23
  disabled: boolean;
24
- variant: ButtonVariant;
25
24
  size: ButtonSize;
25
+ variant: ButtonVariant;
26
26
  loading: boolean;
27
27
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLButtonElement>;
28
28
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
@@ -5,7 +5,7 @@ interface Props {
5
5
  }
6
6
  declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
7
7
  label: string;
8
- variant: "primary" | "cta" | "muted";
9
8
  size: "xs" | "sm" | "md" | "lg";
9
+ variant: "primary" | "cta" | "muted";
10
10
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
11
11
  export default _default;
@@ -8,8 +8,8 @@ interface Props {
8
8
  }
9
9
  declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
10
10
  label: string;
11
- variant: "primary" | "success" | "warning" | "error" | "info";
12
11
  size: "sm" | "md" | "lg";
12
+ variant: "primary" | "success" | "warning" | "error" | "info";
13
13
  value: number;
14
14
  showValue: boolean;
15
15
  indeterminate: boolean;
@@ -9,15 +9,15 @@ interface Props {
9
9
  searchable?: boolean;
10
10
  }
11
11
  declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
12
+ add: () => any;
12
13
  "update:modelValue": (reagents: Reagent[]) => any;
13
14
  remove: (reagentId: string) => any;
14
- add: () => any;
15
15
  edit: (reagent: Reagent) => any;
16
16
  reorder: (reagentId: string, fromIndex: number, toIndex: number) => any;
17
17
  }, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
18
+ onAdd?: (() => any) | undefined;
18
19
  "onUpdate:modelValue"?: ((reagents: Reagent[]) => any) | undefined;
19
20
  onRemove?: ((reagentId: string) => any) | undefined;
20
- onAdd?: (() => any) | undefined;
21
21
  onEdit?: ((reagent: Reagent) => any) | undefined;
22
22
  onReorder?: ((reagentId: string, fromIndex: number, toIndex: number) => any) | undefined;
23
23
  }>, {
@@ -36,9 +36,9 @@ declare const __VLS_component: import('vue').DefineComponent<Props, {}, {}, {},
36
36
  }>, {
37
37
  compact: boolean;
38
38
  size: "sm" | "md" | "lg";
39
+ tags: string[];
39
40
  status: ResourceStatus;
40
41
  specs: ResourceSpec[];
41
- tags: string[];
42
42
  showBookAction: boolean;
43
43
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
44
44
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
@@ -13,8 +13,8 @@ declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, imp
13
13
  "onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
14
14
  }>, {
15
15
  disabled: boolean;
16
- variant: SegmentedControlVariant;
17
16
  size: SegmentedControlSize;
17
+ variant: SegmentedControlVariant;
18
18
  fullWidth: boolean;
19
19
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
20
20
  export default _default;
@@ -10,12 +10,12 @@ interface Props {
10
10
  };
11
11
  }
12
12
  declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
13
- close: () => any;
14
13
  clear: () => any;
14
+ close: () => any;
15
15
  save: (data: WellEditData) => any;
16
16
  }, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
17
- onClose?: (() => any) | undefined;
18
17
  onClear?: (() => any) | undefined;
18
+ onClose?: (() => any) | undefined;
19
19
  onSave?: ((data: WellEditData) => any) | undefined;
20
20
  }>, {
21
21
  wellData: Partial<Well>;
@@ -65,6 +65,10 @@ export { default as UnitInput } from './UnitInput.vue';
65
65
  export { default as StepWizard } from './StepWizard.vue';
66
66
  export { default as AuditTrail } from './AuditTrail.vue';
67
67
  export { default as BatchProgressList } from './BatchProgressList.vue';
68
+ export { default as FormBuilder } from './FormBuilder.vue';
69
+ export { default as FormSection } from './FormSection.vue';
70
+ export { default as FormActions } from './FormActions.vue';
71
+ export { default as FormFieldRenderer } from './FormFieldRenderer.vue';
68
72
  export { default as DateTimePicker } from './DateTimePicker.vue';
69
73
  export { default as TimeRangeInput } from './TimeRangeInput.vue';
70
74
  export { default as ScheduleCalendar } from './ScheduleCalendar.vue';
@@ -131,13 +131,20 @@ import { default as default67 } from "./AuditTrail.vue.js";
131
131
  /* empty css */
132
132
  import { default as default68 } from "./BatchProgressList.vue.js";
133
133
  /* empty css */
134
- import { default as default69 } from "./DateTimePicker.vue.js";
134
+ import { default as default69 } from "./FormBuilder.vue.js";
135
+ /* empty css */
136
+ import { default as default70 } from "./FormSection.vue.js";
137
+ /* empty css */
138
+ import { default as default71 } from "./FormActions.vue.js";
139
+ /* empty css */
140
+ import { default as default72 } from "./FormFieldRenderer.vue.js";
141
+ import { default as default73 } from "./DateTimePicker.vue.js";
135
142
  /* empty css */
136
- import { default as default70 } from "./TimeRangeInput.vue.js";
143
+ import { default as default74 } from "./TimeRangeInput.vue.js";
137
144
  /* empty css */
138
- import { default as default71 } from "./ScheduleCalendar.vue.js";
145
+ import { default as default75 } from "./ScheduleCalendar.vue.js";
139
146
  /* empty css */
140
- import { default as default72 } from "./ResourceCard.vue.js";
147
+ import { default as default76 } from "./ResourceCard.vue.js";
141
148
  /* empty css */
142
149
  export {
143
150
  default25 as AlertBox,
@@ -169,14 +176,18 @@ export {
169
176
  default44 as ConfirmDialog,
170
177
  default18 as DataFrame,
171
178
  default20 as DatePicker,
172
- default69 as DateTimePicker,
179
+ default73 as DateTimePicker,
173
180
  default37 as Divider,
174
181
  default57 as DoseCalculator,
175
182
  default16 as DropdownButton,
176
183
  default41 as EmptyState,
177
184
  default51 as ExperimentTimeline,
178
185
  default24 as FileUploader,
186
+ default71 as FormActions,
187
+ default69 as FormBuilder,
179
188
  default19 as FormField,
189
+ default72 as FormFieldRenderer,
190
+ default70 as FormSection,
180
191
  default63 as FormulaInput,
181
192
  default54 as GroupAssigner,
182
193
  default53 as GroupingModal,
@@ -190,11 +201,11 @@ export {
190
201
  default60 as ProtocolStepEditor,
191
202
  default48 as RackEditor,
192
203
  default58 as ReagentList,
193
- default72 as ResourceCard,
204
+ default76 as ResourceCard,
194
205
  default59 as SampleHierarchyTree,
195
206
  default49 as SampleLegend,
196
207
  default52 as SampleSelector,
197
- default71 as ScheduleCalendar,
208
+ default75 as ScheduleCalendar,
198
209
  default61 as ScientificNumber,
199
210
  default13 as SegmentedControl,
200
211
  default64 as SequenceInput,
@@ -206,7 +217,7 @@ export {
206
217
  default22 as TagsInput,
207
218
  default28 as ThemeToggle,
208
219
  default21 as TimePicker,
209
- default70 as TimeRangeInput,
220
+ default74 as TimeRangeInput,
210
221
  default26 as ToastNotification,
211
222
  default43 as Tooltip,
212
223
  default65 as UnitInput,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,13 @@
1
+ import { Component } from 'vue';
2
+ import { FormFieldType } from '../types/form-builder';
3
+ export interface RegistryEntry {
4
+ component: Component;
5
+ /** Default props applied to the component. */
6
+ defaults: Record<string, unknown>;
7
+ /** Whether the component uses v-model (false for event-only components like FileUploader). */
8
+ vModel: boolean;
9
+ }
10
+ /** Return the registry entry for a given field type. Throws if the type is unregistered. */
11
+ export declare function getFieldRegistryEntry(type: FormFieldType): RegistryEntry;
12
+ /** Get the default empty value for a given field type. */
13
+ export declare function getTypeDefault(type: FormFieldType): unknown;
@@ -0,0 +1,87 @@
1
+ import _sfc_main$i from "../components/BaseInput.vue.js";
2
+ /* empty css */
3
+ import _sfc_main$g from "../components/BaseTextarea.vue.js";
4
+ /* empty css */
5
+ import _sfc_main$f from "../components/BaseSelect.vue.js";
6
+ /* empty css */
7
+ import _sfc_main$e from "../components/MultiSelect.vue.js";
8
+ /* empty css */
9
+ import _sfc_main$d from "../components/BaseCheckbox.vue.js";
10
+ /* empty css */
11
+ import _sfc_main$c from "../components/BaseToggle.vue.js";
12
+ /* empty css */
13
+ import _sfc_main$b from "../components/BaseRadioGroup.vue.js";
14
+ /* empty css */
15
+ import _sfc_main$a from "../components/BaseSlider.vue.js";
16
+ /* empty css */
17
+ import _sfc_main$9 from "../components/TagsInput.vue.js";
18
+ /* empty css */
19
+ import _sfc_main$h from "../components/NumberInput.vue.js";
20
+ /* empty css */
21
+ import _sfc_main$8 from "../components/DatePicker.vue.js";
22
+ /* empty css */
23
+ import _sfc_main$7 from "../components/TimePicker.vue.js";
24
+ /* empty css */
25
+ import _sfc_main$6 from "../components/DateTimePicker.vue.js";
26
+ /* empty css */
27
+ import _sfc_main$5 from "../components/FileUploader.vue.js";
28
+ /* empty css */
29
+ import _sfc_main$4 from "../components/FormulaInput.vue.js";
30
+ /* empty css */
31
+ import _sfc_main$3 from "../components/SequenceInput.vue.js";
32
+ /* empty css */
33
+ import _sfc_main$2 from "../components/MoleculeInput.vue.js";
34
+ /* empty css */
35
+ import _sfc_main$1 from "../components/ConcentrationInput.vue.js";
36
+ /* empty css */
37
+ import _sfc_main from "../components/UnitInput.vue.js";
38
+ /* empty css */
39
+ const registry = {
40
+ text: { component: _sfc_main$i, defaults: { type: "text" }, vModel: true },
41
+ email: { component: _sfc_main$i, defaults: { type: "email" }, vModel: true },
42
+ password: { component: _sfc_main$i, defaults: { type: "password" }, vModel: true },
43
+ tel: { component: _sfc_main$i, defaults: { type: "tel" }, vModel: true },
44
+ url: { component: _sfc_main$i, defaults: { type: "url" }, vModel: true },
45
+ search: { component: _sfc_main$i, defaults: { type: "search" }, vModel: true },
46
+ number: { component: _sfc_main$h, defaults: {}, vModel: true },
47
+ textarea: { component: _sfc_main$g, defaults: {}, vModel: true },
48
+ select: { component: _sfc_main$f, defaults: {}, vModel: true },
49
+ multiselect: { component: _sfc_main$e, defaults: {}, vModel: true },
50
+ checkbox: { component: _sfc_main$d, defaults: {}, vModel: true },
51
+ toggle: { component: _sfc_main$c, defaults: {}, vModel: true },
52
+ radio: { component: _sfc_main$b, defaults: {}, vModel: true },
53
+ slider: { component: _sfc_main$a, defaults: {}, vModel: true },
54
+ tags: { component: _sfc_main$9, defaults: {}, vModel: true },
55
+ date: { component: _sfc_main$8, defaults: {}, vModel: true },
56
+ time: { component: _sfc_main$7, defaults: {}, vModel: true },
57
+ datetime: { component: _sfc_main$6, defaults: {}, vModel: true },
58
+ file: { component: _sfc_main$5, defaults: {}, vModel: false },
59
+ formula: { component: _sfc_main$4, defaults: {}, vModel: true },
60
+ sequence: { component: _sfc_main$3, defaults: {}, vModel: true },
61
+ molecule: { component: _sfc_main$2, defaults: {}, vModel: true },
62
+ concentration: { component: _sfc_main$1, defaults: {}, vModel: true },
63
+ unit: { component: _sfc_main, defaults: {}, vModel: true }
64
+ };
65
+ function getFieldRegistryEntry(type) {
66
+ return registry[type];
67
+ }
68
+ function getTypeDefault(type) {
69
+ switch (type) {
70
+ case "checkbox":
71
+ case "toggle":
72
+ return false;
73
+ case "number":
74
+ case "slider":
75
+ return void 0;
76
+ case "multiselect":
77
+ case "tags":
78
+ return [];
79
+ default:
80
+ return "";
81
+ }
82
+ }
83
+ export {
84
+ getFieldRegistryEntry,
85
+ getTypeDefault
86
+ };
87
+ //# sourceMappingURL=formBuilderRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formBuilderRegistry.js","sources":["../../src/composables/formBuilderRegistry.ts"],"sourcesContent":["import type { Component } from 'vue'\nimport type { FormFieldType } from '../types/form-builder'\n\nimport BaseInput from '../components/BaseInput.vue'\nimport BaseTextarea from '../components/BaseTextarea.vue'\nimport BaseSelect from '../components/BaseSelect.vue'\nimport MultiSelect from '../components/MultiSelect.vue'\nimport BaseCheckbox from '../components/BaseCheckbox.vue'\nimport BaseToggle from '../components/BaseToggle.vue'\nimport BaseRadioGroup from '../components/BaseRadioGroup.vue'\nimport BaseSlider from '../components/BaseSlider.vue'\nimport TagsInput from '../components/TagsInput.vue'\nimport NumberInput from '../components/NumberInput.vue'\nimport DatePicker from '../components/DatePicker.vue'\nimport TimePicker from '../components/TimePicker.vue'\nimport DateTimePicker from '../components/DateTimePicker.vue'\nimport FileUploader from '../components/FileUploader.vue'\nimport FormulaInput from '../components/FormulaInput.vue'\nimport SequenceInput from '../components/SequenceInput.vue'\nimport MoleculeInput from '../components/MoleculeInput.vue'\nimport ConcentrationInput from '../components/ConcentrationInput.vue'\nimport UnitInput from '../components/UnitInput.vue'\n\nexport interface RegistryEntry {\n component: Component\n /** Default props applied to the component. */\n defaults: Record<string, unknown>\n /** Whether the component uses v-model (false for event-only components like FileUploader). */\n vModel: boolean\n}\n\nconst registry: Record<FormFieldType, RegistryEntry> = {\n text: { component: BaseInput, defaults: { type: 'text' }, vModel: true },\n email: { component: BaseInput, defaults: { type: 'email' }, vModel: true },\n password: { component: BaseInput, defaults: { type: 'password' }, vModel: true },\n tel: { component: BaseInput, defaults: { type: 'tel' }, vModel: true },\n url: { component: BaseInput, defaults: { type: 'url' }, vModel: true },\n search: { component: BaseInput, defaults: { type: 'search' }, vModel: true },\n number: { component: NumberInput, defaults: {}, vModel: true },\n textarea: { component: BaseTextarea, defaults: {}, vModel: true },\n select: { component: BaseSelect, defaults: {}, vModel: true },\n multiselect: { component: MultiSelect, defaults: {}, vModel: true },\n checkbox: { component: BaseCheckbox, defaults: {}, vModel: true },\n toggle: { component: BaseToggle, defaults: {}, vModel: true },\n radio: { component: BaseRadioGroup, defaults: {}, vModel: true },\n slider: { component: BaseSlider, defaults: {}, vModel: true },\n tags: { component: TagsInput, defaults: {}, vModel: true },\n date: { component: DatePicker, defaults: {}, vModel: true },\n time: { component: TimePicker, defaults: {}, vModel: true },\n datetime: { component: DateTimePicker, defaults: {}, vModel: true },\n file: { component: FileUploader, defaults: {}, vModel: false },\n formula: { component: FormulaInput, defaults: {}, vModel: true },\n sequence: { component: SequenceInput, defaults: {}, vModel: true },\n molecule: { component: MoleculeInput, defaults: {}, vModel: true },\n concentration: { component: ConcentrationInput, defaults: {}, vModel: true },\n unit: { component: UnitInput, defaults: {}, vModel: true },\n}\n\n/** Return the registry entry for a given field type. Throws if the type is unregistered. */\nexport function getFieldRegistryEntry(type: FormFieldType): RegistryEntry {\n return registry[type]\n}\n\n/** Get the default empty value for a given field type. */\nexport function getTypeDefault(type: FormFieldType): unknown {\n switch (type) {\n case 'checkbox':\n case 'toggle':\n return false\n case 'number':\n case 'slider':\n return undefined\n case 'multiselect':\n case 'tags':\n return []\n default:\n return ''\n }\n}\n"],"names":["BaseInput","NumberInput","BaseTextarea","BaseSelect","MultiSelect","BaseCheckbox","BaseToggle","BaseRadioGroup","BaseSlider","TagsInput","DatePicker","TimePicker","DateTimePicker","FileUploader","FormulaInput","SequenceInput","MoleculeInput","ConcentrationInput","UnitInput"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAM,WAAiD;AAAA,EACrD,MAAM,EAAE,WAAWA,aAAW,UAAU,EAAE,MAAM,OAAA,GAAU,QAAQ,KAAA;AAAA,EAClE,OAAO,EAAE,WAAWA,aAAW,UAAU,EAAE,MAAM,QAAA,GAAW,QAAQ,KAAA;AAAA,EACpE,UAAU,EAAE,WAAWA,aAAW,UAAU,EAAE,MAAM,WAAA,GAAc,QAAQ,KAAA;AAAA,EAC1E,KAAK,EAAE,WAAWA,aAAW,UAAU,EAAE,MAAM,MAAA,GAAS,QAAQ,KAAA;AAAA,EAChE,KAAK,EAAE,WAAWA,aAAW,UAAU,EAAE,MAAM,MAAA,GAAS,QAAQ,KAAA;AAAA,EAChE,QAAQ,EAAE,WAAWA,aAAW,UAAU,EAAE,MAAM,SAAA,GAAY,QAAQ,KAAA;AAAA,EACtE,QAAQ,EAAE,WAAWC,aAAa,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EACxD,UAAU,EAAE,WAAWC,aAAc,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EAC3D,QAAQ,EAAE,WAAWC,aAAY,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EACvD,aAAa,EAAE,WAAWC,aAAa,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EAC7D,UAAU,EAAE,WAAWC,aAAc,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EAC3D,QAAQ,EAAE,WAAWC,aAAY,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EACvD,OAAO,EAAE,WAAWC,aAAgB,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EAC1D,QAAQ,EAAE,WAAWC,aAAY,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EACvD,MAAM,EAAE,WAAWC,aAAW,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EACpD,MAAM,EAAE,WAAWC,aAAY,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EACrD,MAAM,EAAE,WAAWC,aAAY,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EACrD,UAAU,EAAE,WAAWC,aAAgB,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EAC7D,MAAM,EAAE,WAAWC,aAAc,UAAU,CAAA,GAAI,QAAQ,MAAA;AAAA,EACvD,SAAS,EAAE,WAAWC,aAAc,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EAC1D,UAAU,EAAE,WAAWC,aAAe,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EAC5D,UAAU,EAAE,WAAWC,aAAe,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EAC5D,eAAe,EAAE,WAAWC,aAAoB,UAAU,CAAA,GAAI,QAAQ,KAAA;AAAA,EACtE,MAAM,EAAE,WAAWC,WAAW,UAAU,CAAA,GAAI,QAAQ,KAAA;AACtD;AAGO,SAAS,sBAAsB,MAAoC;AACxE,SAAO,SAAS,IAAI;AACtB;AAGO,SAAS,eAAe,MAA8B;AAC3D,UAAQ,MAAA;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO,CAAA;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;"}
@@ -15,3 +15,5 @@ export { useChemicalFormula, ATOMIC_WEIGHTS, type ParsedElement, type FormulaPar
15
15
  export { useSequenceUtils, type SequenceType, type SequenceStats, } from './useSequenceUtils';
16
16
  export { parseTime, formatTime, generateTimeSlots, rangesOverlap, durationMinutes, formatDuration, isTimeInRange, findAvailableSlots, snapToSlot, addMinutes, compareTime, } from './useTimeUtils';
17
17
  export { useScheduleDrag } from './useScheduleDrag';
18
+ export { useFormBuilder, evaluateCondition } from './useFormBuilder';
19
+ export { getFieldRegistryEntry, getTypeDefault, type RegistryEntry, } from './formBuilderRegistry';
@@ -15,15 +15,20 @@ import { ATOMIC_WEIGHTS, useChemicalFormula } from "./useChemicalFormula.js";
15
15
  import { useSequenceUtils } from "./useSequenceUtils.js";
16
16
  import { addMinutes, compareTime, durationMinutes, findAvailableSlots, formatDuration, formatTime, generateTimeSlots, isTimeInRange, parseTime, rangesOverlap, snapToSlot } from "./useTimeUtils.js";
17
17
  import { useScheduleDrag } from "./useScheduleDrag.js";
18
+ import { evaluateCondition, useFormBuilder } from "./useFormBuilder.js";
19
+ import { getFieldRegistryEntry, getTypeDefault } from "./formBuilderRegistry.js";
18
20
  export {
19
21
  ATOMIC_WEIGHTS,
20
22
  addMinutes,
21
23
  compareTime,
22
24
  durationMinutes,
25
+ evaluateCondition,
23
26
  findAvailableSlots,
24
27
  formatDuration,
25
28
  formatTime,
26
29
  generateTimeSlots,
30
+ getFieldRegistryEntry,
31
+ getTypeDefault,
27
32
  isTimeInRange,
28
33
  parseTime,
29
34
  rangesOverlap,
@@ -36,6 +41,7 @@ export {
36
41
  useConcentrationUnits,
37
42
  useDoseCalculator,
38
43
  useForm,
44
+ useFormBuilder,
39
45
  usePasskey,
40
46
  usePlatformContext,
41
47
  useProtocolTemplates,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,23 @@
1
+ import { FormSchema, FieldCondition, FormEnhancements, UseFormBuilderReturn } from '../types/form-builder';
2
+ /**
3
+ * Evaluate a JSON-serializable field condition against the current form data.
4
+ *
5
+ * Supports logical operators (`and`, `or`, `not`) and comparison operators
6
+ * (`eq`, `neq`, `gt`, `lt`, `gte`, `lte`, `in`, `notIn`, `truthy`, `falsy`,
7
+ * `contains`). Returns `true` if the condition passes.
8
+ */
9
+ export declare function evaluateCondition(condition: FieldCondition, data: Record<string, unknown>): boolean;
10
+ /**
11
+ * Drive a `FormSchema` as reactive form state.
12
+ *
13
+ * Builds initial values from schema defaults and `initialData`, derives
14
+ * validation rules from `FieldValidation` descriptors and enhancement
15
+ * validators, evaluates `FieldCondition` expressions for field/section
16
+ * visibility, and wires wizard step navigation when `schema.steps` is set.
17
+ *
18
+ * @param schema - Declarative form or wizard schema.
19
+ * @param initialData - Values that override schema defaults.
20
+ * @param enhancements - TypeScript-only callbacks (dynamic options, validators,
21
+ * submit handler, transform, field-change watcher).
22
+ */
23
+ export declare function useFormBuilder<T extends Record<string, unknown> = Record<string, unknown>>(schema: FormSchema, initialData?: Partial<T>, enhancements?: FormEnhancements<T>): UseFormBuilderReturn<T>;