From dda60ed5e45a1ae405b2878e104d852337bc9465 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Thu, 23 Apr 2026 23:57:39 +0200 Subject: [PATCH] refactor(form-schema): extract schema types and schema-driven behaviors to shared package Moves formBuilder types, formValidation, useConditionalLogic, useFormSteps, and formatFieldValue from apps/portal/src to packages/form-schema/src. Adds @form-schema path alias to both apps/portal and apps/app. Vue field components remain per-app to allow independent visual evolution. Behavior-neutral: all 35 Vitest tests green. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/app/tsconfig.json | 9 ++++++++- apps/app/vite.config.ts | 3 +++ apps/portal/auto-imports.d.ts | 7 ------- .../public-form/DuplicateSubmissionHint.vue | 2 +- .../public-form/FieldAvailabilityPicker.vue | 4 ++-- .../components/public-form/FieldBoolean.vue | 2 +- .../public-form/FieldCheckboxList.vue | 4 ++-- .../src/components/public-form/FieldDate.vue | 4 ++-- .../src/components/public-form/FieldEmail.vue | 4 ++-- .../components/public-form/FieldHeading.vue | 2 +- .../public-form/FieldMultiselect.vue | 4 ++-- .../components/public-form/FieldNumber.vue | 4 ++-- .../components/public-form/FieldParagraph.vue | 2 +- .../src/components/public-form/FieldPhone.vue | 4 ++-- .../src/components/public-form/FieldRadio.vue | 4 ++-- .../components/public-form/FieldRenderer.vue | 6 +++--- .../public-form/FieldSectionPriority.vue | 4 ++-- .../components/public-form/FieldSelect.vue | 4 ++-- .../components/public-form/FieldTagPicker.vue | 4 ++-- .../src/components/public-form/FieldText.vue | 4 ++-- .../components/public-form/FieldTextarea.vue | 4 ++-- .../src/components/public-form/FieldUrl.vue | 4 ++-- .../public-form/FormConfirmation.vue | 8 ++++---- .../components/public-form/FormErrorState.vue | 2 +- .../components/public-form/FormStepper.vue | 2 +- .../src/composables/api/usePublicForm.ts | 2 +- .../composables/api/usePublicFormSections.ts | 2 +- .../composables/api/usePublicFormTimeSlots.ts | 2 +- apps/portal/src/composables/useFormDraft.ts | 2 +- .../src/pages/register/[public_token].vue | 8 ++++---- .../FieldAvailabilityPicker.spec.ts | 4 ++-- .../public-form/FieldRenderer.test.ts | 4 ++-- .../public-form/FieldSectionPriority.spec.ts | 4 ++-- .../public-form/FieldTagPicker.spec.ts | 4 ++-- .../api/usePublicFormSections.spec.ts | 2 +- .../api/usePublicFormTimeSlots.spec.ts | 2 +- .../composables/useConditionalLogic.test.ts | 4 ++-- .../unit/DuplicateSubmissionHint.spec.ts | 2 +- .../tests/unit/formatFieldValue.spec.ts | 6 +++--- apps/portal/tsconfig.json | 9 ++++++++- apps/portal/vite.config.ts | 1 + apps/portal/vitest.config.ts | 1 + packages/form-schema/README.md | 19 +++++++++++++++++++ .../src/composables/formatFieldValue.ts | 4 ++-- .../src/composables/useConditionalLogic.ts | 2 +- .../src/composables/useFormSteps.ts | 8 ++++---- .../form-schema}/src/types/formBuilder.ts | 0 .../form-schema}/src/utils/formValidation.ts | 4 ++-- 48 files changed, 114 insertions(+), 83 deletions(-) create mode 100644 packages/form-schema/README.md rename {apps/portal => packages/form-schema}/src/composables/formatFieldValue.ts (98%) rename {apps/portal => packages/form-schema}/src/composables/useConditionalLogic.ts (99%) rename {apps/portal => packages/form-schema}/src/composables/useFormSteps.ts (94%) rename {apps/portal => packages/form-schema}/src/types/formBuilder.ts (100%) rename {apps/portal => packages/form-schema}/src/utils/formValidation.ts (97%) diff --git a/apps/app/tsconfig.json b/apps/app/tsconfig.json index a0d3eaa8..3b692e40 100644 --- a/apps/app/tsconfig.json +++ b/apps/app/tsconfig.json @@ -39,6 +39,12 @@ ], "@validators": [ "./src/@core/utils/validators" + ], + "@form-schema/*": [ + "../../packages/form-schema/src/*" + ], + "vue": [ + "./node_modules/vue" ] }, "lib": [ @@ -63,7 +69,8 @@ "./src/**/*.vue", "./themeConfig.ts", "./auto-imports.d.ts", - "./components.d.ts" + "./components.d.ts", + "../../packages/form-schema/src/**/*" ], "exclude": [ "./dist", diff --git a/apps/app/vite.config.ts b/apps/app/vite.config.ts index f7057706..1f3f2ebc 100644 --- a/apps/app/vite.config.ts +++ b/apps/app/vite.config.ts @@ -110,6 +110,9 @@ export default defineConfig({ import.meta.url, ), ), + "@form-schema": fileURLToPath( + new URL("../../packages/form-schema/src", import.meta.url), + ), }, }, server: { diff --git a/apps/portal/auto-imports.d.ts b/apps/portal/auto-imports.d.ts index 300451ce..b0004a7e 100644 --- a/apps/portal/auto-imports.d.ts +++ b/apps/portal/auto-imports.d.ts @@ -434,19 +434,16 @@ declare module 'vue' { readonly eagerComputed: UnwrapRef readonly effectScope: UnwrapRef readonly emailValidator: UnwrapRef - readonly evaluateConditionalLogic: UnwrapRef readonly extendRef: UnwrapRef readonly extractErrorBody: UnwrapRef readonly extractRetryAfterSeconds: UnwrapRef readonly formatDate: UnwrapRef readonly formatDateToMonthShort: UnwrapRef - readonly formatFieldValue: UnwrapRef readonly generateDeviceFingerprint: UnwrapRef readonly getActivePinia: UnwrapRef readonly getCurrentInstance: UnwrapRef readonly getCurrentScope: UnwrapRef readonly getDeviceName: UnwrapRef - readonly getValidatorsForField: UnwrapRef readonly h: UnwrapRef readonly hexToRgb: UnwrapRef readonly ignorableWatch: UnwrapRef @@ -456,14 +453,12 @@ declare module 'vue' { readonly isDefined: UnwrapRef readonly isEmpty: UnwrapRef readonly isEmptyArray: UnwrapRef - readonly isFieldValueEmpty: UnwrapRef readonly isNullOrUndefined: UnwrapRef readonly isObject: UnwrapRef readonly isProxy: UnwrapRef readonly isReactive: UnwrapRef readonly isReadonly: UnwrapRef readonly isRef: UnwrapRef - readonly isStepValid: UnwrapRef readonly isToday: UnwrapRef readonly kFormatter: UnwrapRef readonly lengthValidator: UnwrapRef @@ -526,7 +521,6 @@ declare module 'vue' { readonly resolveUnref: UnwrapRef readonly resolveVuetifyTheme: UnwrapRef readonly rgbaToHex: UnwrapRef - readonly runValidators: UnwrapRef readonly setActivePinia: UnwrapRef readonly setMapStoreSuffix: UnwrapRef readonly shallowReactive: UnwrapRef @@ -623,7 +617,6 @@ declare module 'vue' { readonly useFocus: UnwrapRef readonly useFocusWithin: UnwrapRef readonly useFormDraft: UnwrapRef - readonly useFormSteps: UnwrapRef readonly useFps: UnwrapRef readonly useFullscreen: UnwrapRef readonly useGamepad: UnwrapRef diff --git a/apps/portal/src/components/public-form/DuplicateSubmissionHint.vue b/apps/portal/src/components/public-form/DuplicateSubmissionHint.vue index b24e8ec8..ffc41624 100644 --- a/apps/portal/src/components/public-form/DuplicateSubmissionHint.vue +++ b/apps/portal/src/components/public-form/DuplicateSubmissionHint.vue @@ -1,5 +1,5 @@