@duffcloudservices/site-forms 0.1.1 → 0.1.3

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 (41) hide show
  1. package/README.md +274 -260
  2. package/dist/composables/useFormSubmission.d.ts +1 -1
  3. package/dist/index.d.ts +3 -1
  4. package/dist/index.js +554 -398
  5. package/dist/index.js.map +1 -1
  6. package/dist/presets.d.ts +13 -0
  7. package/dist/site-forms.css +1 -0
  8. package/dist/types.d.ts +12 -2
  9. package/package.json +72 -73
  10. package/src/DcsForm.vue +295 -303
  11. package/src/__tests__/fields.test.ts +81 -82
  12. package/src/__tests__/multi-step.test.ts +45 -46
  13. package/src/__tests__/presets.test.ts +64 -0
  14. package/src/__tests__/schema.test.ts +41 -42
  15. package/src/__tests__/style-import.test.ts +9 -0
  16. package/src/__tests__/submission.test.ts +115 -77
  17. package/src/__tests__/validation.test.ts +29 -0
  18. package/src/__tests__/visible-if.test.ts +110 -111
  19. package/src/composables/useDcsForm.ts +201 -201
  20. package/src/composables/useFormSubmission.ts +113 -113
  21. package/src/composables/useFormValidation.ts +128 -127
  22. package/src/fields/DcsFormCheckbox.vue +35 -35
  23. package/src/fields/DcsFormCheckboxGroup.vue +52 -52
  24. package/src/fields/DcsFormDate.vue +34 -34
  25. package/src/fields/DcsFormFieldWrapper.vue +39 -39
  26. package/src/fields/DcsFormFile.vue +38 -38
  27. package/src/fields/DcsFormHidden.vue +17 -17
  28. package/src/fields/DcsFormHtmlBlock.vue +19 -19
  29. package/src/fields/DcsFormRadio.vue +45 -45
  30. package/src/fields/DcsFormSection.vue +19 -19
  31. package/src/fields/DcsFormSelect.vue +62 -62
  32. package/src/fields/DcsFormText.vue +54 -54
  33. package/src/fields/DcsFormTextarea.vue +43 -43
  34. package/src/index.ts +64 -51
  35. package/src/loaders/yaml.ts +51 -51
  36. package/src/presets.ts +192 -0
  37. package/src/schema/form-definition.schema.json +410 -45
  38. package/src/schema/validate.ts +58 -58
  39. package/src/shims.d.ts +10 -10
  40. package/src/style.css +256 -0
  41. package/src/types.ts +164 -140
@@ -1,111 +1,110 @@
1
- import { describe, it, expect, vi } from 'vitest'
2
- import { mount, flushPromises } from '@vue/test-utils'
3
- import DcsForm from '../DcsForm.vue'
4
- import type { PortalFormDefinition } from '../types'
5
-
6
- const def: PortalFormDefinition = {
7
- formId: 'gated',
8
- title: 'Gated',
9
- submission: { kind: 'lead' },
10
- fields: [
11
- {
12
- id: 'kind',
13
- type: 'radio',
14
- label: 'Kind',
15
- required: true,
16
- options: [
17
- { value: 'a', label: 'A' },
18
- { value: 'b', label: 'B' },
19
- ],
20
- },
21
- {
22
- id: 'detail',
23
- type: 'text',
24
- label: 'Detail',
25
- required: true,
26
- visibleIf: { fieldId: 'kind', equals: 'b' },
27
- },
28
- ],
29
- }
30
-
31
- describe('visibleIf', () => {
32
- it('skips validation and submission for hidden gated fields', async () => {
33
- const fetchMock = vi.fn().mockResolvedValue({
34
- ok: true,
35
- status: 200,
36
- json: async () => ({ id: '1' }),
37
- })
38
- // Stub global fetch
39
- const originalFetch = globalThis.fetch
40
- ;(globalThis as unknown as { fetch: typeof fetch }).fetch =
41
- fetchMock as unknown as typeof fetch
42
-
43
- const wrapper = mount(DcsForm, {
44
- props: {
45
- formId: 'gated',
46
- siteSlug: 'site-x',
47
- definitionOverride: def,
48
- apiBase: 'https://api.test',
49
- },
50
- })
51
-
52
- // detail field is hidden initially
53
- expect(wrapper.find('[data-form-field-key="detail"]').exists()).toBe(false)
54
-
55
- // Choose kind=a (does not reveal detail)
56
- await wrapper.find('input[type="radio"][value="a"]').setChecked(true)
57
- await wrapper.find('form').trigger('submit')
58
- await flushPromises()
59
-
60
- expect(fetchMock).toHaveBeenCalledTimes(1)
61
- const [, init] = fetchMock.mock.calls[0]
62
- const body = JSON.parse((init as RequestInit).body as string)
63
- expect(body.values).toEqual({ kind: 'a' })
64
- expect('detail' in body.values).toBe(false)
65
-
66
- ;(globalThis as unknown as { fetch: typeof fetch }).fetch = originalFetch
67
- })
68
-
69
- it('validates and submits the gated field once visible', async () => {
70
- const fetchMock = vi.fn().mockResolvedValue({
71
- ok: true,
72
- status: 200,
73
- json: async () => ({}),
74
- })
75
- const originalFetch = globalThis.fetch
76
- ;(globalThis as unknown as { fetch: typeof fetch }).fetch =
77
- fetchMock as unknown as typeof fetch
78
-
79
- const wrapper = mount(DcsForm, {
80
- props: {
81
- formId: 'gated',
82
- siteSlug: 'site-x',
83
- definitionOverride: def,
84
- apiBase: 'https://api.test',
85
- },
86
- })
87
- await wrapper.find('input[type="radio"][value="b"]').setChecked(true)
88
- // detail should now be visible and required
89
- expect(wrapper.find('[data-form-field-key="detail"]').exists()).toBe(true)
90
-
91
- await wrapper.find('form').trigger('submit')
92
- await flushPromises()
93
- expect(fetchMock).not.toHaveBeenCalled()
94
- expect(wrapper.text()).toContain('Detail is required')
95
-
96
- await wrapper.find('[data-form-field-key="detail"] input').setValue('xyz')
97
- await wrapper.find('form').trigger('submit')
98
- await flushPromises()
99
- expect(fetchMock).toHaveBeenCalledTimes(1)
100
- const [url, init] = fetchMock.mock.calls[0]
101
- expect(url).toBe('https://api.test/public/sites/site-x/form-submissions')
102
- const body = JSON.parse((init as RequestInit).body as string)
103
- expect(body).toEqual({
104
- formId: 'gated',
105
- values: { kind: 'b', detail: 'xyz' },
106
- captchaToken: undefined,
107
- })
108
-
109
- ;(globalThis as unknown as { fetch: typeof fetch }).fetch = originalFetch
110
- })
111
- })
1
+ import { describe, it, expect, vi } from 'vitest'
2
+ import { mount, flushPromises } from '@vue/test-utils'
3
+ import DcsForm from '../DcsForm.vue'
4
+ import type { PortalFormDefinition } from '../types'
5
+
6
+ const def: PortalFormDefinition = {
7
+ formId: 'gated',
8
+ submission: { kind: 'lead' },
9
+ fields: [
10
+ {
11
+ id: 'kind',
12
+ type: 'radio',
13
+ label: 'Kind',
14
+ required: true,
15
+ options: [
16
+ { value: 'a', label: 'A' },
17
+ { value: 'b', label: 'B' },
18
+ ],
19
+ },
20
+ {
21
+ id: 'detail',
22
+ type: 'text',
23
+ label: 'Detail',
24
+ required: true,
25
+ visibleIf: { fieldId: 'kind', equals: 'b' },
26
+ },
27
+ ],
28
+ }
29
+
30
+ describe('visibleIf', () => {
31
+ it('skips validation and submission for hidden gated fields', async () => {
32
+ const fetchMock = vi.fn().mockResolvedValue({
33
+ ok: true,
34
+ status: 200,
35
+ json: async () => ({ id: '1' }),
36
+ })
37
+ // Stub global fetch
38
+ const originalFetch = globalThis.fetch
39
+ ;(globalThis as unknown as { fetch: typeof fetch }).fetch =
40
+ fetchMock as unknown as typeof fetch
41
+
42
+ const wrapper = mount(DcsForm, {
43
+ props: {
44
+ formId: 'gated',
45
+ siteSlug: 'site-x',
46
+ definitionOverride: def,
47
+ apiBase: 'https://api.test',
48
+ },
49
+ })
50
+
51
+ // detail field is hidden initially
52
+ expect(wrapper.find('[data-form-field-key="detail"]').exists()).toBe(false)
53
+
54
+ // Choose kind=a (does not reveal detail)
55
+ await wrapper.find('input[type="radio"][value="a"]').setChecked(true)
56
+ await wrapper.find('form').trigger('submit')
57
+ await flushPromises()
58
+
59
+ expect(fetchMock).toHaveBeenCalledTimes(1)
60
+ const [, init] = fetchMock.mock.calls[0]
61
+ const body = JSON.parse((init as RequestInit).body as string)
62
+ expect(body.values).toEqual({ kind: 'a' })
63
+ expect('detail' in body.values).toBe(false)
64
+
65
+ ;(globalThis as unknown as { fetch: typeof fetch }).fetch = originalFetch
66
+ })
67
+
68
+ it('validates and submits the gated field once visible', async () => {
69
+ const fetchMock = vi.fn().mockResolvedValue({
70
+ ok: true,
71
+ status: 200,
72
+ json: async () => ({}),
73
+ })
74
+ const originalFetch = globalThis.fetch
75
+ ;(globalThis as unknown as { fetch: typeof fetch }).fetch =
76
+ fetchMock as unknown as typeof fetch
77
+
78
+ const wrapper = mount(DcsForm, {
79
+ props: {
80
+ formId: 'gated',
81
+ siteSlug: 'site-x',
82
+ definitionOverride: def,
83
+ apiBase: 'https://api.test',
84
+ },
85
+ })
86
+ await wrapper.find('input[type="radio"][value="b"]').setChecked(true)
87
+ // detail should now be visible and required
88
+ expect(wrapper.find('[data-form-field-key="detail"]').exists()).toBe(true)
89
+
90
+ await wrapper.find('form').trigger('submit')
91
+ await flushPromises()
92
+ expect(fetchMock).not.toHaveBeenCalled()
93
+ expect(wrapper.text()).toContain('Detail is required')
94
+
95
+ await wrapper.find('[data-form-field-key="detail"] input').setValue('xyz')
96
+ await wrapper.find('form').trigger('submit')
97
+ await flushPromises()
98
+ expect(fetchMock).toHaveBeenCalledTimes(1)
99
+ const [url, init] = fetchMock.mock.calls[0]
100
+ expect(url).toBe('https://api.test/sites/site-x/forms/gated/submissions')
101
+ const body = JSON.parse((init as RequestInit).body as string)
102
+ expect(body).toEqual({
103
+ formId: 'gated',
104
+ values: { kind: 'b', detail: 'xyz' },
105
+ captchaToken: undefined,
106
+ })
107
+
108
+ ;(globalThis as unknown as { fetch: typeof fetch }).fetch = originalFetch
109
+ })
110
+ })
@@ -1,201 +1,201 @@
1
- import { computed, reactive, ref, type ComputedRef, type Ref } from 'vue'
2
- import type {
3
- PortalFormDefinition,
4
- PortalFormField,
5
- PortalFormStep,
6
- FormErrors,
7
- FormValues,
8
- } from '../types'
9
- import {
10
- hasErrors,
11
- isFieldVisible,
12
- validateForm,
13
- } from './useFormValidation'
14
-
15
- export interface UseDcsFormOptions {
16
- definition: PortalFormDefinition
17
- }
18
-
19
- export interface UseDcsFormReturn {
20
- values: FormValues
21
- errors: Ref<FormErrors>
22
- touched: Ref<Record<string, boolean>>
23
- submitting: Ref<boolean>
24
- submitted: Ref<boolean>
25
- submitError: Ref<string | null>
26
- /** All fields, with layout-only types preserved. */
27
- fields: ComputedRef<PortalFormField[]>
28
- /** Steps if multi-step, else null. */
29
- steps: ComputedRef<PortalFormStep[] | null>
30
- currentStepIndex: Ref<number>
31
- currentStep: ComputedRef<PortalFormStep | null>
32
- currentStepFields: ComputedRef<PortalFormField[]>
33
- isFirstStep: ComputedRef<boolean>
34
- isLastStep: ComputedRef<boolean>
35
- visibleFields: ComputedRef<PortalFormField[]>
36
- /** Sets a field value and clears that field's error. */
37
- setValue: (id: string, value: unknown) => void
38
- /** Marks a field as touched + revalidates only that field's row. */
39
- touch: (id: string) => void
40
- /** Validates the current step (multi-step) or the entire form. */
41
- validateCurrentScope: () => boolean
42
- validateAll: () => boolean
43
- next: () => boolean
44
- prev: () => void
45
- reset: () => void
46
- /** Returns the values that should actually be submitted (visible only). */
47
- collectSubmissionValues: () => FormValues
48
- }
49
-
50
- function defaultsFor(def: PortalFormDefinition): FormValues {
51
- const out: FormValues = {}
52
- for (const f of def.fields) {
53
- if (f.defaultValue !== undefined) {
54
- out[f.id] = f.defaultValue as unknown
55
- } else if (f.type === 'checkbox') {
56
- out[f.id] = false
57
- } else if (f.type === 'multiselect' || f.type === 'checkbox-group') {
58
- out[f.id] = [] as string[]
59
- } else {
60
- out[f.id] = ''
61
- }
62
- }
63
- return out
64
- }
65
-
66
- export function useDcsForm(opts: UseDcsFormOptions): UseDcsFormReturn {
67
- const { definition } = opts
68
- const values = reactive<FormValues>(defaultsFor(definition))
69
- const errors = ref<FormErrors>({})
70
- const touched = ref<Record<string, boolean>>({})
71
- const submitting = ref(false)
72
- const submitted = ref(false)
73
- const submitError = ref<string | null>(null)
74
- const currentStepIndex = ref(0)
75
-
76
- const fields = computed(() => definition.fields)
77
- const steps = computed<PortalFormStep[] | null>(() =>
78
- definition.steps && definition.steps.length > 0 ? definition.steps : null,
79
- )
80
- const currentStep = computed<PortalFormStep | null>(() => {
81
- const s = steps.value
82
- return s ? (s[currentStepIndex.value] ?? null) : null
83
- })
84
- const currentStepFields = computed<PortalFormField[]>(() => {
85
- const step = currentStep.value
86
- if (!step) return definition.fields
87
- const ids = new Set(step.fieldIds)
88
- return definition.fields.filter((f) => ids.has(f.id))
89
- })
90
- const isFirstStep = computed(() => currentStepIndex.value === 0)
91
- const isLastStep = computed(() => {
92
- const s = steps.value
93
- return !s || currentStepIndex.value >= s.length - 1
94
- })
95
- const visibleFields = computed(() =>
96
- currentStepFields.value.filter((f) => isFieldVisible(f, values as FormValues)),
97
- )
98
-
99
- function setValue(id: string, value: unknown): void {
100
- ;(values as FormValues)[id] = value
101
- if (errors.value[id]) {
102
- errors.value = { ...errors.value, [id]: undefined }
103
- }
104
- }
105
-
106
- function touch(id: string): void {
107
- touched.value = { ...touched.value, [id]: true }
108
- }
109
-
110
- function validateScope(scopeFieldIds?: string[]): boolean {
111
- const next = validateForm(definition, values as FormValues, scopeFieldIds)
112
- // Merge with existing errors but only for the validated scope so we
113
- // don't wipe out errors from other steps.
114
- if (scopeFieldIds) {
115
- const merged = { ...errors.value }
116
- for (const id of scopeFieldIds) {
117
- merged[id] = next[id]
118
- }
119
- errors.value = merged
120
- } else {
121
- errors.value = next
122
- }
123
- return !hasErrors(errors.value)
124
- }
125
-
126
- function validateCurrentScope(): boolean {
127
- const scope = currentStep.value?.fieldIds
128
- return validateScope(scope)
129
- }
130
-
131
- function validateAll(): boolean {
132
- return validateScope()
133
- }
134
-
135
- function next(): boolean {
136
- if (!steps.value) return false
137
- if (!validateCurrentScope()) return false
138
- if (currentStepIndex.value < steps.value.length - 1) {
139
- currentStepIndex.value++
140
- return true
141
- }
142
- return false
143
- }
144
-
145
- function prev(): void {
146
- if (currentStepIndex.value > 0) currentStepIndex.value--
147
- }
148
-
149
- function reset(): void {
150
- const fresh = defaultsFor(definition)
151
- for (const k of Object.keys(values as object)) {
152
- delete (values as FormValues)[k]
153
- }
154
- Object.assign(values as FormValues, fresh)
155
- errors.value = {}
156
- touched.value = {}
157
- submitting.value = false
158
- submitted.value = false
159
- submitError.value = null
160
- currentStepIndex.value = 0
161
- }
162
-
163
- function collectSubmissionValues(): FormValues {
164
- const out: FormValues = {}
165
- for (const f of definition.fields) {
166
- if (
167
- f.type === 'section-heading' ||
168
- f.type === 'html-block'
169
- )
170
- continue
171
- if (!isFieldVisible(f, values as FormValues)) continue
172
- out[f.id] = (values as FormValues)[f.id]
173
- }
174
- return out
175
- }
176
-
177
- return {
178
- values: values as FormValues,
179
- errors,
180
- touched,
181
- submitting,
182
- submitted,
183
- submitError,
184
- fields,
185
- steps,
186
- currentStepIndex,
187
- currentStep,
188
- currentStepFields,
189
- isFirstStep,
190
- isLastStep,
191
- visibleFields,
192
- setValue,
193
- touch,
194
- validateCurrentScope,
195
- validateAll,
196
- next,
197
- prev,
198
- reset,
199
- collectSubmissionValues,
200
- }
201
- }
1
+ import { computed, reactive, ref, type ComputedRef, type Ref } from 'vue'
2
+ import type {
3
+ PortalFormDefinition,
4
+ PortalFormField,
5
+ PortalFormStep,
6
+ FormErrors,
7
+ FormValues,
8
+ } from '../types'
9
+ import {
10
+ hasErrors,
11
+ isFieldVisible,
12
+ validateForm,
13
+ } from './useFormValidation'
14
+
15
+ export interface UseDcsFormOptions {
16
+ definition: PortalFormDefinition
17
+ }
18
+
19
+ export interface UseDcsFormReturn {
20
+ values: FormValues
21
+ errors: Ref<FormErrors>
22
+ touched: Ref<Record<string, boolean>>
23
+ submitting: Ref<boolean>
24
+ submitted: Ref<boolean>
25
+ submitError: Ref<string | null>
26
+ /** All fields, with layout-only types preserved. */
27
+ fields: ComputedRef<PortalFormField[]>
28
+ /** Steps if multi-step, else null. */
29
+ steps: ComputedRef<PortalFormStep[] | null>
30
+ currentStepIndex: Ref<number>
31
+ currentStep: ComputedRef<PortalFormStep | null>
32
+ currentStepFields: ComputedRef<PortalFormField[]>
33
+ isFirstStep: ComputedRef<boolean>
34
+ isLastStep: ComputedRef<boolean>
35
+ visibleFields: ComputedRef<PortalFormField[]>
36
+ /** Sets a field value and clears that field's error. */
37
+ setValue: (id: string, value: unknown) => void
38
+ /** Marks a field as touched + revalidates only that field's row. */
39
+ touch: (id: string) => void
40
+ /** Validates the current step (multi-step) or the entire form. */
41
+ validateCurrentScope: () => boolean
42
+ validateAll: () => boolean
43
+ next: () => boolean
44
+ prev: () => void
45
+ reset: () => void
46
+ /** Returns the values that should actually be submitted (visible only). */
47
+ collectSubmissionValues: () => FormValues
48
+ }
49
+
50
+ function defaultsFor(def: PortalFormDefinition): FormValues {
51
+ const out: FormValues = {}
52
+ for (const f of def.fields) {
53
+ if (f.defaultValue !== undefined) {
54
+ out[f.id] = f.defaultValue as unknown
55
+ } else if (f.type === 'checkbox') {
56
+ out[f.id] = false
57
+ } else if (f.type === 'multiselect' || f.type === 'checkbox-group') {
58
+ out[f.id] = [] as string[]
59
+ } else {
60
+ out[f.id] = ''
61
+ }
62
+ }
63
+ return out
64
+ }
65
+
66
+ export function useDcsForm(opts: UseDcsFormOptions): UseDcsFormReturn {
67
+ const { definition } = opts
68
+ const values = reactive<FormValues>(defaultsFor(definition))
69
+ const errors = ref<FormErrors>({})
70
+ const touched = ref<Record<string, boolean>>({})
71
+ const submitting = ref(false)
72
+ const submitted = ref(false)
73
+ const submitError = ref<string | null>(null)
74
+ const currentStepIndex = ref(0)
75
+
76
+ const fields = computed(() => definition.fields)
77
+ const steps = computed<PortalFormStep[] | null>(() =>
78
+ definition.steps && definition.steps.length > 0 ? definition.steps : null,
79
+ )
80
+ const currentStep = computed<PortalFormStep | null>(() => {
81
+ const s = steps.value
82
+ return s ? (s[currentStepIndex.value] ?? null) : null
83
+ })
84
+ const currentStepFields = computed<PortalFormField[]>(() => {
85
+ const step = currentStep.value
86
+ if (!step) return definition.fields
87
+ const ids = new Set(step.fieldIds)
88
+ return definition.fields.filter((f) => ids.has(f.id))
89
+ })
90
+ const isFirstStep = computed(() => currentStepIndex.value === 0)
91
+ const isLastStep = computed(() => {
92
+ const s = steps.value
93
+ return !s || currentStepIndex.value >= s.length - 1
94
+ })
95
+ const visibleFields = computed(() =>
96
+ currentStepFields.value.filter((f) => isFieldVisible(f, values as FormValues)),
97
+ )
98
+
99
+ function setValue(id: string, value: unknown): void {
100
+ ;(values as FormValues)[id] = value
101
+ if (errors.value[id]) {
102
+ errors.value = { ...errors.value, [id]: undefined }
103
+ }
104
+ }
105
+
106
+ function touch(id: string): void {
107
+ touched.value = { ...touched.value, [id]: true }
108
+ }
109
+
110
+ function validateScope(scopeFieldIds?: string[]): boolean {
111
+ const next = validateForm(definition, values as FormValues, scopeFieldIds)
112
+ // Merge with existing errors but only for the validated scope so we
113
+ // don't wipe out errors from other steps.
114
+ if (scopeFieldIds) {
115
+ const merged = { ...errors.value }
116
+ for (const id of scopeFieldIds) {
117
+ merged[id] = next[id]
118
+ }
119
+ errors.value = merged
120
+ } else {
121
+ errors.value = next
122
+ }
123
+ return !hasErrors(errors.value)
124
+ }
125
+
126
+ function validateCurrentScope(): boolean {
127
+ const scope = currentStep.value?.fieldIds
128
+ return validateScope(scope)
129
+ }
130
+
131
+ function validateAll(): boolean {
132
+ return validateScope()
133
+ }
134
+
135
+ function next(): boolean {
136
+ if (!steps.value) return false
137
+ if (!validateCurrentScope()) return false
138
+ if (currentStepIndex.value < steps.value.length - 1) {
139
+ currentStepIndex.value++
140
+ return true
141
+ }
142
+ return false
143
+ }
144
+
145
+ function prev(): void {
146
+ if (currentStepIndex.value > 0) currentStepIndex.value--
147
+ }
148
+
149
+ function reset(): void {
150
+ const fresh = defaultsFor(definition)
151
+ for (const k of Object.keys(values as object)) {
152
+ delete (values as FormValues)[k]
153
+ }
154
+ Object.assign(values as FormValues, fresh)
155
+ errors.value = {}
156
+ touched.value = {}
157
+ submitting.value = false
158
+ submitted.value = false
159
+ submitError.value = null
160
+ currentStepIndex.value = 0
161
+ }
162
+
163
+ function collectSubmissionValues(): FormValues {
164
+ const out: FormValues = {}
165
+ for (const f of definition.fields) {
166
+ if (
167
+ f.type === 'section-heading' ||
168
+ f.type === 'html-block'
169
+ )
170
+ continue
171
+ if (!isFieldVisible(f, values as FormValues)) continue
172
+ out[f.id] = (values as FormValues)[f.id]
173
+ }
174
+ return out
175
+ }
176
+
177
+ return {
178
+ values: values as FormValues,
179
+ errors,
180
+ touched,
181
+ submitting,
182
+ submitted,
183
+ submitError,
184
+ fields,
185
+ steps,
186
+ currentStepIndex,
187
+ currentStep,
188
+ currentStepFields,
189
+ isFirstStep,
190
+ isLastStep,
191
+ visibleFields,
192
+ setValue,
193
+ touch,
194
+ validateCurrentScope,
195
+ validateAll,
196
+ next,
197
+ prev,
198
+ reset,
199
+ collectSubmissionValues,
200
+ }
201
+ }