@btst/plugin-form-builder 1.0.0-beta.0 → 1.2.0-beta.1
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/dist/api/index.cjs +1 -0
- package/dist/api/index.d.cts +1 -1
- package/dist/api/index.d.mts +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.mjs +1 -1
- package/dist/api/operations.cjs +64 -4
- package/dist/api/operations.mjs +64 -5
- package/dist/api/plugin.cjs +8 -0
- package/dist/api/plugin.mjs +8 -0
- package/dist/api/submissions-csv.cjs +69 -0
- package/dist/api/submissions-csv.mjs +64 -0
- package/dist/client/components/forms/form-renderer.cjs +31 -2
- package/dist/client/components/forms/form-renderer.mjs +31 -2
- package/dist/client/components/forms/media-file-field.cjs +48 -0
- package/dist/client/components/forms/media-file-field.mjs +46 -0
- package/dist/client/components/index.d.cts +4 -2
- package/dist/client/components/index.d.mts +4 -2
- package/dist/client/components/index.d.ts +4 -2
- package/dist/client/components/pages/ai-schema.cjs +120 -0
- package/dist/client/components/pages/ai-schema.mjs +118 -0
- package/dist/client/components/pages/form-builder-page.internal.cjs +40 -1
- package/dist/client/components/pages/form-builder-page.internal.mjs +41 -2
- package/dist/client/components/pages/form-list-page.internal.cjs +1 -0
- package/dist/client/components/pages/form-list-page.internal.mjs +1 -0
- package/dist/client/components/pages/submissions-page.internal.cjs +40 -0
- package/dist/client/components/pages/submissions-page.internal.mjs +41 -1
- package/dist/client/components/shared/pagination.cjs +19 -0
- package/dist/client/components/shared/pagination.mjs +20 -1
- package/dist/client/hooks/form-builder-hooks.cjs +4 -0
- package/dist/client/hooks/form-builder-hooks.mjs +4 -1
- package/dist/client/hooks/index.cjs +1 -0
- package/dist/client/hooks/index.d.cts +7 -2
- package/dist/client/hooks/index.d.mts +7 -2
- package/dist/client/hooks/index.d.ts +7 -2
- package/dist/client/hooks/index.mjs +1 -1
- package/dist/client/index.d.cts +42 -3
- package/dist/client/index.d.mts +42 -3
- package/dist/client/index.d.ts +42 -3
- package/dist/permissions.cjs +8 -0
- package/dist/permissions.d.cts +6 -0
- package/dist/permissions.d.mts +6 -0
- package/dist/permissions.d.ts +6 -0
- package/dist/permissions.mjs +8 -0
- package/dist/query-keys.cjs +7 -0
- package/dist/query-keys.d.cts +29 -1
- package/dist/query-keys.d.mts +29 -1
- package/dist/query-keys.d.ts +29 -1
- package/dist/query-keys.mjs +7 -0
- package/dist/shared/{plugin-form-builder.CSP5HR2O.d.ts → plugin-form-builder.65tLgfcd.d.ts} +46 -29
- package/dist/shared/{plugin-form-builder.Bbl9NufB.d.cts → plugin-form-builder.DXdOj9vM.d.cts} +46 -29
- package/dist/shared/{plugin-form-builder.lp98rFNl.d.mts → plugin-form-builder.PWs25HN1.d.mts} +46 -29
- package/dist/shared/{plugin-form-builder.DWrQ3lRX.d.ts → plugin-form-builder.sdjcoJcH.d.cts} +15 -1
- package/dist/shared/{plugin-form-builder.DWrQ3lRX.d.cts → plugin-form-builder.sdjcoJcH.d.mts} +15 -1
- package/dist/shared/{plugin-form-builder.DWrQ3lRX.d.mts → plugin-form-builder.sdjcoJcH.d.ts} +15 -1
- package/dist/ui/src/components/auto-form/config.cjs +2 -0
- package/dist/ui/src/components/auto-form/config.mjs +2 -0
- package/dist/ui/src/components/auto-form/fields/file.cjs +68 -0
- package/dist/ui/src/components/auto-form/fields/file.mjs +63 -0
- package/dist/ui/src/components/auto-form/fields/object.cjs +9 -2
- package/dist/ui/src/components/auto-form/fields/object.mjs +9 -2
- package/dist/ui/src/components/auto-form/helpers.cjs +9 -0
- package/dist/ui/src/components/auto-form/helpers.mjs +9 -0
- package/dist/ui/src/components/auto-form/index.cjs +29 -4
- package/dist/ui/src/components/auto-form/index.mjs +31 -6
- package/dist/ui/src/components/auto-form/stepped-auto-form.cjs +34 -29
- package/dist/ui/src/components/auto-form/stepped-auto-form.mjs +35 -30
- package/dist/ui/src/components/form-builder/canvas.cjs +9 -0
- package/dist/ui/src/components/form-builder/canvas.mjs +9 -0
- package/dist/ui/src/components/form-builder/components/index.cjs +12 -0
- package/dist/ui/src/components/form-builder/components/index.mjs +12 -1
- package/dist/ui/src/components/form-builder/condition-editor.cjs +73 -0
- package/dist/ui/src/components/form-builder/condition-editor.mjs +71 -0
- package/dist/ui/src/components/form-builder/edit-field-dialog.cjs +6 -2
- package/dist/ui/src/components/form-builder/edit-field-dialog.mjs +6 -2
- package/dist/ui/src/components/form-builder/index.cjs +6 -1
- package/dist/ui/src/components/form-builder/index.mjs +6 -1
- package/dist/ui/src/components/form-builder/schema-utils.cjs +2 -0
- package/dist/ui/src/components/form-builder/schema-utils.mjs +2 -0
- package/dist/ui/src/components/form.mjs +1 -1
- package/dist/ui/src/lib/form-visibility.cjs +20 -0
- package/dist/ui/src/lib/form-visibility.mjs +18 -0
- package/dist/ui/src/lib/schema-converter.cjs +101 -0
- package/dist/ui/src/lib/schema-converter.mjs +100 -1
- package/package.json +4 -4
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
-
import React__default, { useMemo, useState,
|
|
3
|
+
import React__default, { useMemo, useState, useEffect, useRef, useCallback } from 'react';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import AutoForm from './index.mjs';
|
|
6
|
+
import { getDefaultValues, getObjectFormSchema } from './helpers.mjs';
|
|
7
|
+
import { resolveVisibleSchema, formSchemaToZod } from '../../lib/schema-converter.mjs';
|
|
8
|
+
import { matchesShowIf } from '../../lib/form-visibility.mjs';
|
|
6
9
|
import { Button } from '../button.mjs';
|
|
7
10
|
import { Separator } from '../separator.mjs';
|
|
8
11
|
import { cn } from '../../lib/utils.mjs';
|
|
9
12
|
|
|
10
13
|
function extractStepsFromSchema(schema) {
|
|
11
14
|
try {
|
|
12
|
-
const jsonSchema = schema.toJSONSchema();
|
|
15
|
+
const jsonSchema = schema.meta()?.steps ? schema.meta() : schema.toJSONSchema();
|
|
13
16
|
if (jsonSchema.steps && Array.isArray(jsonSchema.steps)) {
|
|
14
17
|
return jsonSchema.steps;
|
|
15
18
|
}
|
|
@@ -20,7 +23,7 @@ function extractStepsFromSchema(schema) {
|
|
|
20
23
|
function getFieldStepAssignments(schema) {
|
|
21
24
|
const assignments = /* @__PURE__ */ new Map();
|
|
22
25
|
try {
|
|
23
|
-
const jsonSchema = schema.toJSONSchema();
|
|
26
|
+
const jsonSchema = schema.meta()?.steps ? schema.meta() : schema.toJSONSchema();
|
|
24
27
|
const stepGroupMap = jsonSchema.stepGroupMap;
|
|
25
28
|
if (stepGroupMap) {
|
|
26
29
|
for (const [fieldName, stepGroup] of Object.entries(stepGroupMap)) {
|
|
@@ -54,21 +57,6 @@ function createStepSchema(fullSchema, stepIndex, fieldAssignments) {
|
|
|
54
57
|
}
|
|
55
58
|
return fullSchema.pick(pickObject);
|
|
56
59
|
}
|
|
57
|
-
function getObjectSchema(schema) {
|
|
58
|
-
if (schema instanceof z.ZodObject) {
|
|
59
|
-
return schema;
|
|
60
|
-
}
|
|
61
|
-
const schemaDef = schema._zod?.def ?? schema._def;
|
|
62
|
-
if (schemaDef) {
|
|
63
|
-
if (schemaDef.schema) {
|
|
64
|
-
return getObjectSchema(schemaDef.schema);
|
|
65
|
-
}
|
|
66
|
-
if (schemaDef.innerType) {
|
|
67
|
-
return getObjectSchema(schemaDef.innerType);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
60
|
function DefaultStepper({
|
|
73
61
|
steps,
|
|
74
62
|
currentStepIndex,
|
|
@@ -116,16 +104,25 @@ function SteppedAutoForm({
|
|
|
116
104
|
StepperComponent = DefaultStepper,
|
|
117
105
|
isSubmitting = false
|
|
118
106
|
}) {
|
|
119
|
-
const
|
|
120
|
-
const hasMultipleSteps =
|
|
121
|
-
const
|
|
107
|
+
const allSteps = useMemo(() => extractStepsFromSchema(formSchema), [formSchema]);
|
|
108
|
+
const hasMultipleSteps = allSteps.length > 1;
|
|
109
|
+
const originalFieldAssignments = useMemo(
|
|
122
110
|
() => getFieldStepAssignments(formSchema),
|
|
123
111
|
[formSchema]
|
|
124
112
|
);
|
|
125
113
|
const [currentStepIndex, setCurrentStepIndex] = useState(0);
|
|
126
114
|
const [accumulatedValues, setAccumulatedValues] = useState(
|
|
127
|
-
initialValues ?? {}
|
|
115
|
+
() => ({ ...getDefaultValues(getObjectFormSchema(formSchema), fieldConfig) ?? {}, ...initialValues ?? {} })
|
|
128
116
|
);
|
|
117
|
+
const steps = useMemo(() => {
|
|
118
|
+
const metadata = formSchema.meta();
|
|
119
|
+
const visibleValues = metadata?.properties ? resolveVisibleSchema(metadata, accumulatedValues).data : accumulatedValues;
|
|
120
|
+
return allSteps.map((step, originalIndex) => ({ ...step, originalIndex })).filter((step) => matchesShowIf(step.showIf, visibleValues));
|
|
121
|
+
}, [allSteps, accumulatedValues, formSchema]);
|
|
122
|
+
const fieldAssignments = useMemo(() => new Map(Array.from(originalFieldAssignments).map(([key, originalIndex]) => [key, steps.findIndex((step) => step.originalIndex === originalIndex)])), [originalFieldAssignments, steps]);
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
setCurrentStepIndex((index) => Math.min(index, Math.max(0, steps.length - 1)));
|
|
125
|
+
}, [steps.length]);
|
|
129
126
|
const [completedSteps, setCompletedSteps] = useState(/* @__PURE__ */ new Set());
|
|
130
127
|
const [schemaErrors, setSchemaErrors] = useState(null);
|
|
131
128
|
const accumulatedValuesRef = useRef(accumulatedValues);
|
|
@@ -146,13 +143,19 @@ function SteppedAutoForm({
|
|
|
146
143
|
setAccumulatedValues(newValues);
|
|
147
144
|
}
|
|
148
145
|
}, [initialValues]);
|
|
149
|
-
const objectSchema = useMemo(() =>
|
|
146
|
+
const objectSchema = useMemo(() => getObjectFormSchema(formSchema), [formSchema]);
|
|
150
147
|
const stepSchemas = useMemo(() => {
|
|
151
148
|
if (!hasMultipleSteps || !objectSchema) return [];
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
149
|
+
const metadata = formSchema.meta();
|
|
150
|
+
if (metadata?.properties) {
|
|
151
|
+
const visible = resolveVisibleSchema(metadata, accumulatedValues).schema;
|
|
152
|
+
return steps.map((_, index) => {
|
|
153
|
+
const properties = Object.fromEntries(Object.entries(visible.properties ?? {}).filter(([key]) => fieldAssignments.get(key) === index));
|
|
154
|
+
return formSchemaToZod({ ...visible, properties, required: visible.required?.filter((key) => key in properties), steps: void 0 });
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return steps.map((_, index) => createStepSchema(objectSchema, index, fieldAssignments));
|
|
158
|
+
}, [hasMultipleSteps, objectSchema, steps, fieldAssignments, accumulatedValues, formSchema]);
|
|
156
159
|
const currentStep = steps[currentStepIndex];
|
|
157
160
|
const currentStepSchema = stepSchemas[currentStepIndex];
|
|
158
161
|
const isFirst = currentStepIndex === 0;
|
|
@@ -160,14 +163,16 @@ function SteppedAutoForm({
|
|
|
160
163
|
const currentStepFieldConfig = useMemo(() => {
|
|
161
164
|
if (!fieldConfig) return void 0;
|
|
162
165
|
const stepFields = Array.from(fieldAssignments.entries()).filter(([, step]) => step === currentStepIndex).map(([field]) => field);
|
|
166
|
+
const properties = formSchema.meta()?.properties;
|
|
163
167
|
const filtered = {};
|
|
164
168
|
for (const field of stepFields) {
|
|
165
169
|
if (field in fieldConfig) {
|
|
166
|
-
|
|
170
|
+
const config = fieldConfig[field];
|
|
171
|
+
filtered[field] = properties?.[field]?.showIf ? { ...config, showIf: void 0 } : config;
|
|
167
172
|
}
|
|
168
173
|
}
|
|
169
174
|
return filtered;
|
|
170
|
-
}, [fieldConfig, fieldAssignments, currentStepIndex]);
|
|
175
|
+
}, [fieldConfig, fieldAssignments, currentStepIndex, formSchema]);
|
|
171
176
|
const currentStepValues = useMemo(() => {
|
|
172
177
|
const stepFields = Array.from(fieldAssignments.entries()).filter(([, step]) => step === currentStepIndex).map(([field]) => field);
|
|
173
178
|
const values = {};
|
|
@@ -245,7 +250,7 @@ function SteppedAutoForm({
|
|
|
245
250
|
setSchemaErrors(null);
|
|
246
251
|
}
|
|
247
252
|
}, [isFirst]);
|
|
248
|
-
if (!hasMultipleSteps) {
|
|
253
|
+
if (!hasMultipleSteps || steps.length === 0) {
|
|
249
254
|
return /* @__PURE__ */ jsxs(
|
|
250
255
|
AutoForm,
|
|
251
256
|
{
|
|
@@ -7,6 +7,7 @@ const core = require('@dnd-kit/core');
|
|
|
7
7
|
const sortable = require('@dnd-kit/sortable');
|
|
8
8
|
const utils = require('../../lib/utils.cjs');
|
|
9
9
|
const sortableField = require('./sortable-field.cjs');
|
|
10
|
+
const conditionEditor = require('./condition-editor.cjs');
|
|
10
11
|
const stepTabs = require('./step-tabs.cjs');
|
|
11
12
|
|
|
12
13
|
function DropZone({ id, isDraggingFromPalette }) {
|
|
@@ -41,6 +42,7 @@ function Canvas({
|
|
|
41
42
|
onAddStep,
|
|
42
43
|
onDeleteStep,
|
|
43
44
|
onRenameStep,
|
|
45
|
+
onStepConditionChange,
|
|
44
46
|
hideStepControls
|
|
45
47
|
}) {
|
|
46
48
|
const { setNodeRef, isOver } = core.useDroppable({
|
|
@@ -67,6 +69,13 @@ function Canvas({
|
|
|
67
69
|
hideStepControls
|
|
68
70
|
}
|
|
69
71
|
),
|
|
72
|
+
!hideStepControls && steps.length > 1 && onStepConditionChange && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
|
|
73
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mb-2 text-sm font-medium", children: [
|
|
74
|
+
steps[activeStepIndex]?.title,
|
|
75
|
+
" visibility"
|
|
76
|
+
] }),
|
|
77
|
+
/* @__PURE__ */ jsxRuntime.jsx(conditionEditor.ConditionEditor, { value: steps[activeStepIndex]?.showIf, onChange: (condition) => onStepConditionChange(activeStepIndex, condition), fieldIds: fields.filter((field) => (field.stepGroup ?? 0) < activeStepIndex).map((field) => field.id) })
|
|
78
|
+
] }),
|
|
70
79
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
71
80
|
"div",
|
|
72
81
|
{
|
|
@@ -5,6 +5,7 @@ import { useDroppable } from '@dnd-kit/core';
|
|
|
5
5
|
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
6
6
|
import { cn } from '../../lib/utils.mjs';
|
|
7
7
|
import { SortableField } from './sortable-field.mjs';
|
|
8
|
+
import { ConditionEditor } from './condition-editor.mjs';
|
|
8
9
|
import { StepTabs } from './step-tabs.mjs';
|
|
9
10
|
|
|
10
11
|
function DropZone({ id, isDraggingFromPalette }) {
|
|
@@ -39,6 +40,7 @@ function Canvas({
|
|
|
39
40
|
onAddStep,
|
|
40
41
|
onDeleteStep,
|
|
41
42
|
onRenameStep,
|
|
43
|
+
onStepConditionChange,
|
|
42
44
|
hideStepControls
|
|
43
45
|
}) {
|
|
44
46
|
const { setNodeRef, isOver } = useDroppable({
|
|
@@ -65,6 +67,13 @@ function Canvas({
|
|
|
65
67
|
hideStepControls
|
|
66
68
|
}
|
|
67
69
|
),
|
|
70
|
+
!hideStepControls && steps.length > 1 && onStepConditionChange && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
71
|
+
/* @__PURE__ */ jsxs("p", { className: "mb-2 text-sm font-medium", children: [
|
|
72
|
+
steps[activeStepIndex]?.title,
|
|
73
|
+
" visibility"
|
|
74
|
+
] }),
|
|
75
|
+
/* @__PURE__ */ jsx(ConditionEditor, { value: steps[activeStepIndex]?.showIf, onChange: (condition) => onStepConditionChange(activeStepIndex, condition), fieldIds: fields.filter((field) => (field.stepGroup ?? 0) < activeStepIndex).map((field) => field.id) })
|
|
76
|
+
] }),
|
|
68
77
|
/* @__PURE__ */ jsx(
|
|
69
78
|
"div",
|
|
70
79
|
{
|
|
@@ -23,6 +23,16 @@ function getPlaceholder(prop) {
|
|
|
23
23
|
function getLabel(prop, key) {
|
|
24
24
|
return prop.label || prop.title || helpers.beautifyObjectName(key);
|
|
25
25
|
}
|
|
26
|
+
const fileFieldDefinition = types.defineComponent({
|
|
27
|
+
type: "file",
|
|
28
|
+
backingType: "string",
|
|
29
|
+
label: "File Upload",
|
|
30
|
+
icon: lucideReact.FolderOpen,
|
|
31
|
+
defaultProps: { label: "File", required: false },
|
|
32
|
+
propertiesSchema: validationSchemas.baseMetaSchema,
|
|
33
|
+
toJSONSchema: (props) => ({ type: "string", minLength: 1, fieldType: "file", label: props.label, description: props.description }),
|
|
34
|
+
fromJSONSchema: (prop, key, isRequired) => prop.fieldType === "file" ? { id: key, type: "file", props: { label: getLabel(prop, key), description: prop.description, required: isRequired } } : null
|
|
35
|
+
});
|
|
26
36
|
const textFieldDefinition = types.defineComponent({
|
|
27
37
|
type: "text",
|
|
28
38
|
backingType: "string",
|
|
@@ -531,6 +541,7 @@ const arrayFieldDefinition = {
|
|
|
531
541
|
}
|
|
532
542
|
};
|
|
533
543
|
const defaultComponents = [
|
|
544
|
+
fileFieldDefinition,
|
|
534
545
|
// Container types (must be before primitives to match object/array JSON Schema)
|
|
535
546
|
objectFieldDefinition,
|
|
536
547
|
arrayFieldDefinition,
|
|
@@ -558,6 +569,7 @@ exports.checkboxFieldDefinition = checkboxFieldDefinition;
|
|
|
558
569
|
exports.dateFieldDefinition = dateFieldDefinition;
|
|
559
570
|
exports.defaultComponents = defaultComponents;
|
|
560
571
|
exports.emailFieldDefinition = emailFieldDefinition;
|
|
572
|
+
exports.fileFieldDefinition = fileFieldDefinition;
|
|
561
573
|
exports.getComponentByType = getComponentByType;
|
|
562
574
|
exports.numberFieldDefinition = numberFieldDefinition;
|
|
563
575
|
exports.objectFieldDefinition = objectFieldDefinition;
|
|
@@ -21,6 +21,16 @@ function getPlaceholder(prop) {
|
|
|
21
21
|
function getLabel(prop, key) {
|
|
22
22
|
return prop.label || prop.title || beautifyObjectName(key);
|
|
23
23
|
}
|
|
24
|
+
const fileFieldDefinition = defineComponent({
|
|
25
|
+
type: "file",
|
|
26
|
+
backingType: "string",
|
|
27
|
+
label: "File Upload",
|
|
28
|
+
icon: FolderOpen,
|
|
29
|
+
defaultProps: { label: "File", required: false },
|
|
30
|
+
propertiesSchema: baseMetaSchema,
|
|
31
|
+
toJSONSchema: (props) => ({ type: "string", minLength: 1, fieldType: "file", label: props.label, description: props.description }),
|
|
32
|
+
fromJSONSchema: (prop, key, isRequired) => prop.fieldType === "file" ? { id: key, type: "file", props: { label: getLabel(prop, key), description: prop.description, required: isRequired } } : null
|
|
33
|
+
});
|
|
24
34
|
const textFieldDefinition = defineComponent({
|
|
25
35
|
type: "text",
|
|
26
36
|
backingType: "string",
|
|
@@ -529,6 +539,7 @@ const arrayFieldDefinition = {
|
|
|
529
539
|
}
|
|
530
540
|
};
|
|
531
541
|
const defaultComponents = [
|
|
542
|
+
fileFieldDefinition,
|
|
532
543
|
// Container types (must be before primitives to match object/array JSON Schema)
|
|
533
544
|
objectFieldDefinition,
|
|
534
545
|
arrayFieldDefinition,
|
|
@@ -551,4 +562,4 @@ function getComponentByType(type, components = defaultComponents) {
|
|
|
551
562
|
return components.find((c) => c.type === type);
|
|
552
563
|
}
|
|
553
564
|
|
|
554
|
-
export { arrayFieldDefinition, checkboxFieldDefinition, dateFieldDefinition, defaultComponents, emailFieldDefinition, getComponentByType, numberFieldDefinition, objectFieldDefinition, passwordFieldDefinition, phoneFieldDefinition, radioFieldDefinition, selectFieldDefinition, switchFieldDefinition, textFieldDefinition, textareaFieldDefinition, urlFieldDefinition };
|
|
565
|
+
export { arrayFieldDefinition, checkboxFieldDefinition, dateFieldDefinition, defaultComponents, emailFieldDefinition, fileFieldDefinition, getComponentByType, numberFieldDefinition, objectFieldDefinition, passwordFieldDefinition, phoneFieldDefinition, radioFieldDefinition, selectFieldDefinition, switchFieldDefinition, textFieldDefinition, textareaFieldDefinition, urlFieldDefinition };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
const React = require('react');
|
|
6
|
+
const textarea = require('../textarea.cjs');
|
|
7
|
+
const input = require('../input.cjs');
|
|
8
|
+
const label = require('../label.cjs');
|
|
9
|
+
const select = require('../select.cjs');
|
|
10
|
+
|
|
11
|
+
function ConditionEditor({ value, onChange, fieldIds }) {
|
|
12
|
+
const id = React.useId();
|
|
13
|
+
const [draft, setDraft] = React.useState();
|
|
14
|
+
const editingValue = draft?.condition === value;
|
|
15
|
+
const ValueInput = value?.operator === "in" ? textarea.Textarea : input.Input;
|
|
16
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "flex flex-col gap-3 rounded-md border p-3", children: [
|
|
17
|
+
/* @__PURE__ */ jsxRuntime.jsx("legend", { className: "px-1 text-sm font-medium", children: "Visibility" }),
|
|
18
|
+
/* @__PURE__ */ jsxRuntime.jsx(label.Label, { htmlFor: `${id}-field`, children: "Show if field" }),
|
|
19
|
+
/* @__PURE__ */ jsxRuntime.jsxs(select.Select, { value: value?.field ?? "__always", onValueChange: (field) => {
|
|
20
|
+
setDraft(void 0);
|
|
21
|
+
onChange(field === "__always" ? void 0 : { field, operator: "isTruthy" });
|
|
22
|
+
}, children: [
|
|
23
|
+
/* @__PURE__ */ jsxRuntime.jsx(select.SelectTrigger, { id: `${id}-field`, children: /* @__PURE__ */ jsxRuntime.jsx(select.SelectValue, {}) }),
|
|
24
|
+
/* @__PURE__ */ jsxRuntime.jsxs(select.SelectContent, { children: [
|
|
25
|
+
/* @__PURE__ */ jsxRuntime.jsx(select.SelectItem, { value: "__always", children: "Always show" }),
|
|
26
|
+
fieldIds.map((field) => /* @__PURE__ */ jsxRuntime.jsx(select.SelectItem, { value: field, children: field }, field))
|
|
27
|
+
] })
|
|
28
|
+
] }),
|
|
29
|
+
value && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
30
|
+
/* @__PURE__ */ jsxRuntime.jsx(label.Label, { htmlFor: `${id}-operator`, children: "Condition" }),
|
|
31
|
+
/* @__PURE__ */ jsxRuntime.jsxs(select.Select, { value: value.operator, onValueChange: (operator) => {
|
|
32
|
+
setDraft(void 0);
|
|
33
|
+
onChange({ ...value, operator, value: operator === "in" ? [] : "" });
|
|
34
|
+
}, children: [
|
|
35
|
+
/* @__PURE__ */ jsxRuntime.jsx(select.SelectTrigger, { id: `${id}-operator`, children: /* @__PURE__ */ jsxRuntime.jsx(select.SelectValue, {}) }),
|
|
36
|
+
/* @__PURE__ */ jsxRuntime.jsxs(select.SelectContent, { children: [
|
|
37
|
+
/* @__PURE__ */ jsxRuntime.jsx(select.SelectItem, { value: "equals", children: "Equals" }),
|
|
38
|
+
/* @__PURE__ */ jsxRuntime.jsx(select.SelectItem, { value: "notEquals", children: "Does not equal" }),
|
|
39
|
+
/* @__PURE__ */ jsxRuntime.jsx(select.SelectItem, { value: "in", children: "Is one of" }),
|
|
40
|
+
/* @__PURE__ */ jsxRuntime.jsx(select.SelectItem, { value: "isTruthy", children: "Has a truthy value" })
|
|
41
|
+
] })
|
|
42
|
+
] }),
|
|
43
|
+
value.operator !== "isTruthy" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
44
|
+
/* @__PURE__ */ jsxRuntime.jsx(label.Label, { htmlFor: `${id}-value`, children: value.operator === "in" ? "Values (one per line)" : "Value" }),
|
|
45
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
46
|
+
ValueInput,
|
|
47
|
+
{
|
|
48
|
+
id: `${id}-value`,
|
|
49
|
+
value: editingValue ? draft.text : value.operator === "in" ? Array.isArray(value.value) ? value.value.map((item) => typeof item === "string" ? JSON.stringify(item) : String(item)).join("\n") : "" : typeof value.value === "string" ? value.value : JSON.stringify(value.value) ?? "",
|
|
50
|
+
onChange: (event) => {
|
|
51
|
+
const parse = (text) => {
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(text);
|
|
54
|
+
} catch {
|
|
55
|
+
return text;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const next = { ...value, value: value.operator === "in" ? event.target.value.split("\n").map((text) => parse(text.trim())) : parse(event.target.value) };
|
|
59
|
+
setDraft({ condition: next, text: event.target.value });
|
|
60
|
+
onChange(next);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
),
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
65
|
+
value.operator === "in" ? "Enter one value per line. " : "",
|
|
66
|
+
"Numbers, true and false are compared as typed values. Quote them to compare text."
|
|
67
|
+
] })
|
|
68
|
+
] })
|
|
69
|
+
] })
|
|
70
|
+
] });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
exports.ConditionEditor = ConditionEditor;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { useId, useState } from 'react';
|
|
4
|
+
import { Textarea } from '../textarea.mjs';
|
|
5
|
+
import { Input } from '../input.mjs';
|
|
6
|
+
import { Label } from '../label.mjs';
|
|
7
|
+
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../select.mjs';
|
|
8
|
+
|
|
9
|
+
function ConditionEditor({ value, onChange, fieldIds }) {
|
|
10
|
+
const id = useId();
|
|
11
|
+
const [draft, setDraft] = useState();
|
|
12
|
+
const editingValue = draft?.condition === value;
|
|
13
|
+
const ValueInput = value?.operator === "in" ? Textarea : Input;
|
|
14
|
+
return /* @__PURE__ */ jsxs("fieldset", { className: "flex flex-col gap-3 rounded-md border p-3", children: [
|
|
15
|
+
/* @__PURE__ */ jsx("legend", { className: "px-1 text-sm font-medium", children: "Visibility" }),
|
|
16
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `${id}-field`, children: "Show if field" }),
|
|
17
|
+
/* @__PURE__ */ jsxs(Select, { value: value?.field ?? "__always", onValueChange: (field) => {
|
|
18
|
+
setDraft(void 0);
|
|
19
|
+
onChange(field === "__always" ? void 0 : { field, operator: "isTruthy" });
|
|
20
|
+
}, children: [
|
|
21
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id: `${id}-field`, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
22
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
23
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "__always", children: "Always show" }),
|
|
24
|
+
fieldIds.map((field) => /* @__PURE__ */ jsx(SelectItem, { value: field, children: field }, field))
|
|
25
|
+
] })
|
|
26
|
+
] }),
|
|
27
|
+
value && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
28
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `${id}-operator`, children: "Condition" }),
|
|
29
|
+
/* @__PURE__ */ jsxs(Select, { value: value.operator, onValueChange: (operator) => {
|
|
30
|
+
setDraft(void 0);
|
|
31
|
+
onChange({ ...value, operator, value: operator === "in" ? [] : "" });
|
|
32
|
+
}, children: [
|
|
33
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id: `${id}-operator`, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
34
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
35
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "equals", children: "Equals" }),
|
|
36
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "notEquals", children: "Does not equal" }),
|
|
37
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "in", children: "Is one of" }),
|
|
38
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "isTruthy", children: "Has a truthy value" })
|
|
39
|
+
] })
|
|
40
|
+
] }),
|
|
41
|
+
value.operator !== "isTruthy" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `${id}-value`, children: value.operator === "in" ? "Values (one per line)" : "Value" }),
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
ValueInput,
|
|
45
|
+
{
|
|
46
|
+
id: `${id}-value`,
|
|
47
|
+
value: editingValue ? draft.text : value.operator === "in" ? Array.isArray(value.value) ? value.value.map((item) => typeof item === "string" ? JSON.stringify(item) : String(item)).join("\n") : "" : typeof value.value === "string" ? value.value : JSON.stringify(value.value) ?? "",
|
|
48
|
+
onChange: (event) => {
|
|
49
|
+
const parse = (text) => {
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(text);
|
|
52
|
+
} catch {
|
|
53
|
+
return text;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const next = { ...value, value: value.operator === "in" ? event.target.value.split("\n").map((text) => parse(text.trim())) : parse(event.target.value) };
|
|
57
|
+
setDraft({ condition: next, text: event.target.value });
|
|
58
|
+
onChange(next);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
63
|
+
value.operator === "in" ? "Enter one value per line. " : "",
|
|
64
|
+
"Numbers, true and false are compared as typed values. Quote them to compare text."
|
|
65
|
+
] })
|
|
66
|
+
] })
|
|
67
|
+
] })
|
|
68
|
+
] });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { ConditionEditor };
|
|
@@ -5,6 +5,7 @@ const jsxRuntime = require('react/jsx-runtime');
|
|
|
5
5
|
const React = require('react');
|
|
6
6
|
const index = require('../auto-form/index.cjs');
|
|
7
7
|
const helpers = require('../auto-form/helpers.cjs');
|
|
8
|
+
const conditionEditor = require('./condition-editor.cjs');
|
|
8
9
|
const input = require('../input.cjs');
|
|
9
10
|
const label = require('../label.cjs');
|
|
10
11
|
const button = require('../button.cjs');
|
|
@@ -30,6 +31,7 @@ function EditFieldDialog({
|
|
|
30
31
|
}, [field, open]);
|
|
31
32
|
const [fieldNameOverride, setFieldNameOverride] = React.useState(null);
|
|
32
33
|
const [localPropsOverride, setLocalPropsOverride] = React.useState(null);
|
|
34
|
+
const [conditionOverride, setConditionOverride] = React.useState(null);
|
|
33
35
|
const [stepGroupOverride, setStepGroupOverride] = React.useState(null);
|
|
34
36
|
const fieldName = fieldNameOverride ?? initialValues.fieldName;
|
|
35
37
|
const localProps = localPropsOverride ?? initialValues.props;
|
|
@@ -44,6 +46,7 @@ function EditFieldDialog({
|
|
|
44
46
|
setFieldNameOverride(null);
|
|
45
47
|
setLocalPropsOverride(null);
|
|
46
48
|
setStepGroupOverride(null);
|
|
49
|
+
setConditionOverride(null);
|
|
47
50
|
}
|
|
48
51
|
const formKey = initialValues.key;
|
|
49
52
|
const handleValuesChange = React.useCallback(
|
|
@@ -54,7 +57,7 @@ function EditFieldDialog({
|
|
|
54
57
|
);
|
|
55
58
|
const handleSave = React.useCallback(() => {
|
|
56
59
|
if (!field) return;
|
|
57
|
-
const props = { ...localProps };
|
|
60
|
+
const props = { ...localProps, showIf: conditionOverride ? conditionOverride.value : field.props.showIf };
|
|
58
61
|
if (typeof props.options === "string") {
|
|
59
62
|
props.options = props.options.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
60
63
|
}
|
|
@@ -62,7 +65,7 @@ function EditFieldDialog({
|
|
|
62
65
|
const stepGroup = stepGroupOverride !== null && stepGroupOverride !== field.stepGroup ? stepGroupOverride : void 0;
|
|
63
66
|
onUpdate(field.id, props, newId, stepGroup);
|
|
64
67
|
onOpenChange(false);
|
|
65
|
-
}, [field, localProps, fieldName, onUpdate, onOpenChange, stepGroupOverride]);
|
|
68
|
+
}, [field, localProps, fieldName, onUpdate, onOpenChange, stepGroupOverride, conditionOverride]);
|
|
66
69
|
if (!field || !component) {
|
|
67
70
|
return null;
|
|
68
71
|
}
|
|
@@ -109,6 +112,7 @@ function EditFieldDialog({
|
|
|
109
112
|
),
|
|
110
113
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Which step this field belongs to" })
|
|
111
114
|
] }),
|
|
115
|
+
/* @__PURE__ */ jsxRuntime.jsx(conditionEditor.ConditionEditor, { value: conditionOverride ? conditionOverride.value : field.props.showIf, onChange: (value) => setConditionOverride({ value }), fieldIds: allFieldIds.filter((id) => id !== field.id) }),
|
|
112
116
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t pt-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
113
117
|
index,
|
|
114
118
|
{
|
|
@@ -3,6 +3,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
3
3
|
import { useMemo, useState, useCallback } from 'react';
|
|
4
4
|
import AutoForm from '../auto-form/index.mjs';
|
|
5
5
|
import { buildFieldConfigFromJsonSchema } from '../auto-form/helpers.mjs';
|
|
6
|
+
import { ConditionEditor } from './condition-editor.mjs';
|
|
6
7
|
import { Input } from '../input.mjs';
|
|
7
8
|
import { Label } from '../label.mjs';
|
|
8
9
|
import { Button } from '../button.mjs';
|
|
@@ -28,6 +29,7 @@ function EditFieldDialog({
|
|
|
28
29
|
}, [field, open]);
|
|
29
30
|
const [fieldNameOverride, setFieldNameOverride] = useState(null);
|
|
30
31
|
const [localPropsOverride, setLocalPropsOverride] = useState(null);
|
|
32
|
+
const [conditionOverride, setConditionOverride] = useState(null);
|
|
31
33
|
const [stepGroupOverride, setStepGroupOverride] = useState(null);
|
|
32
34
|
const fieldName = fieldNameOverride ?? initialValues.fieldName;
|
|
33
35
|
const localProps = localPropsOverride ?? initialValues.props;
|
|
@@ -42,6 +44,7 @@ function EditFieldDialog({
|
|
|
42
44
|
setFieldNameOverride(null);
|
|
43
45
|
setLocalPropsOverride(null);
|
|
44
46
|
setStepGroupOverride(null);
|
|
47
|
+
setConditionOverride(null);
|
|
45
48
|
}
|
|
46
49
|
const formKey = initialValues.key;
|
|
47
50
|
const handleValuesChange = useCallback(
|
|
@@ -52,7 +55,7 @@ function EditFieldDialog({
|
|
|
52
55
|
);
|
|
53
56
|
const handleSave = useCallback(() => {
|
|
54
57
|
if (!field) return;
|
|
55
|
-
const props = { ...localProps };
|
|
58
|
+
const props = { ...localProps, showIf: conditionOverride ? conditionOverride.value : field.props.showIf };
|
|
56
59
|
if (typeof props.options === "string") {
|
|
57
60
|
props.options = props.options.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
58
61
|
}
|
|
@@ -60,7 +63,7 @@ function EditFieldDialog({
|
|
|
60
63
|
const stepGroup = stepGroupOverride !== null && stepGroupOverride !== field.stepGroup ? stepGroupOverride : void 0;
|
|
61
64
|
onUpdate(field.id, props, newId, stepGroup);
|
|
62
65
|
onOpenChange(false);
|
|
63
|
-
}, [field, localProps, fieldName, onUpdate, onOpenChange, stepGroupOverride]);
|
|
66
|
+
}, [field, localProps, fieldName, onUpdate, onOpenChange, stepGroupOverride, conditionOverride]);
|
|
64
67
|
if (!field || !component) {
|
|
65
68
|
return null;
|
|
66
69
|
}
|
|
@@ -107,6 +110,7 @@ function EditFieldDialog({
|
|
|
107
110
|
),
|
|
108
111
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Which step this field belongs to" })
|
|
109
112
|
] }),
|
|
113
|
+
/* @__PURE__ */ jsx(ConditionEditor, { value: conditionOverride ? conditionOverride.value : field.props.showIf, onChange: (value) => setConditionOverride({ value }), fieldIds: allFieldIds.filter((id) => id !== field.id) }),
|
|
110
114
|
/* @__PURE__ */ jsx("div", { className: "border-t pt-4", children: /* @__PURE__ */ jsx(
|
|
111
115
|
AutoForm,
|
|
112
116
|
{
|
|
@@ -292,7 +292,12 @@ function FormBuilder({
|
|
|
292
292
|
onActiveStepChange: setActiveStepIndex,
|
|
293
293
|
onAddStep: handleAddStep,
|
|
294
294
|
onDeleteStep: handleDeleteStep,
|
|
295
|
-
onRenameStep: handleRenameStep
|
|
295
|
+
onRenameStep: handleRenameStep,
|
|
296
|
+
onStepConditionChange: (index, showIf) => {
|
|
297
|
+
const nextSteps = steps.map((step, i) => i === index ? { ...step, showIf } : step);
|
|
298
|
+
setSteps(nextSteps);
|
|
299
|
+
notifyChange(fields, nextSteps);
|
|
300
|
+
}
|
|
296
301
|
}
|
|
297
302
|
) }),
|
|
298
303
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1 lg:w-96 border-t lg:border-t-0 lg:border-l lg:overflow-auto min-h-[300px]", children: /* @__PURE__ */ jsxRuntime.jsxs(tabs.Tabs, { defaultValue: "preview", className: "h-full flex flex-col", children: [
|
|
@@ -291,7 +291,12 @@ function FormBuilder({
|
|
|
291
291
|
onActiveStepChange: setActiveStepIndex,
|
|
292
292
|
onAddStep: handleAddStep,
|
|
293
293
|
onDeleteStep: handleDeleteStep,
|
|
294
|
-
onRenameStep: handleRenameStep
|
|
294
|
+
onRenameStep: handleRenameStep,
|
|
295
|
+
onStepConditionChange: (index, showIf) => {
|
|
296
|
+
const nextSteps = steps.map((step, i) => i === index ? { ...step, showIf } : step);
|
|
297
|
+
setSteps(nextSteps);
|
|
298
|
+
notifyChange(fields, nextSteps);
|
|
299
|
+
}
|
|
295
300
|
}
|
|
296
301
|
) }),
|
|
297
302
|
/* @__PURE__ */ jsx("div", { className: "w-full flex-1 lg:w-96 border-t lg:border-t-0 lg:border-l lg:overflow-auto min-h-[300px]", children: /* @__PURE__ */ jsxs(Tabs, { defaultValue: "preview", className: "h-full flex flex-col", children: [
|
|
@@ -12,6 +12,7 @@ function fieldsToProperties(fields, components, includeStepGroup = false) {
|
|
|
12
12
|
}
|
|
13
13
|
const isRequired = field.props.required ?? false;
|
|
14
14
|
const schemaProp = component.toJSONSchema(field.props, isRequired);
|
|
15
|
+
if (field.props.showIf) schemaProp.showIf = field.props.showIf;
|
|
15
16
|
if (includeStepGroup && field.stepGroup !== void 0) {
|
|
16
17
|
schemaProp.stepGroup = field.stepGroup;
|
|
17
18
|
}
|
|
@@ -64,6 +65,7 @@ function propertiesToFields(properties, requiredSet, components, stepGroupMap) {
|
|
|
64
65
|
}
|
|
65
66
|
const resolvedStepGroup = prop.stepGroup !== void 0 ? prop.stepGroup : stepGroupMap?.[key];
|
|
66
67
|
if (field) {
|
|
68
|
+
if (prop.showIf) field.props.showIf = prop.showIf;
|
|
67
69
|
if (resolvedStepGroup !== void 0) {
|
|
68
70
|
field.stepGroup = resolvedStepGroup;
|
|
69
71
|
}
|
|
@@ -10,6 +10,7 @@ function fieldsToProperties(fields, components, includeStepGroup = false) {
|
|
|
10
10
|
}
|
|
11
11
|
const isRequired = field.props.required ?? false;
|
|
12
12
|
const schemaProp = component.toJSONSchema(field.props, isRequired);
|
|
13
|
+
if (field.props.showIf) schemaProp.showIf = field.props.showIf;
|
|
13
14
|
if (includeStepGroup && field.stepGroup !== void 0) {
|
|
14
15
|
schemaProp.stepGroup = field.stepGroup;
|
|
15
16
|
}
|
|
@@ -62,6 +63,7 @@ function propertiesToFields(properties, requiredSet, components, stepGroupMap) {
|
|
|
62
63
|
}
|
|
63
64
|
const resolvedStepGroup = prop.stepGroup !== void 0 ? prop.stepGroup : stepGroupMap?.[key];
|
|
64
65
|
if (field) {
|
|
66
|
+
if (prop.showIf) field.props.showIf = prop.showIf;
|
|
65
67
|
if (resolvedStepGroup !== void 0) {
|
|
66
68
|
field.stepGroup = resolvedStepGroup;
|
|
67
69
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { Slot } from '@radix-ui/react-slot';
|
|
5
|
-
import { FormProvider,
|
|
5
|
+
import { FormProvider, useFormContext, useFormState, Controller } from 'react-hook-form';
|
|
6
6
|
import { cn } from '../lib/utils.mjs';
|
|
7
7
|
import { Label } from './label.mjs';
|
|
8
8
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function matchesShowIf(condition, values) {
|
|
4
|
+
if (!condition) return true;
|
|
5
|
+
const value = Object.hasOwn(values, condition.field) ? values[condition.field] : void 0;
|
|
6
|
+
switch (condition.operator) {
|
|
7
|
+
case "equals":
|
|
8
|
+
return value === condition.value;
|
|
9
|
+
case "notEquals":
|
|
10
|
+
return value !== condition.value;
|
|
11
|
+
case "in":
|
|
12
|
+
return Array.isArray(condition.value) && condition.value.includes(value);
|
|
13
|
+
case "isTruthy":
|
|
14
|
+
return Boolean(value);
|
|
15
|
+
default:
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
exports.matchesShowIf = matchesShowIf;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function matchesShowIf(condition, values) {
|
|
2
|
+
if (!condition) return true;
|
|
3
|
+
const value = Object.hasOwn(values, condition.field) ? values[condition.field] : void 0;
|
|
4
|
+
switch (condition.operator) {
|
|
5
|
+
case "equals":
|
|
6
|
+
return value === condition.value;
|
|
7
|
+
case "notEquals":
|
|
8
|
+
return value !== condition.value;
|
|
9
|
+
case "in":
|
|
10
|
+
return Array.isArray(condition.value) && condition.value.includes(value);
|
|
11
|
+
case "isTruthy":
|
|
12
|
+
return Boolean(value);
|
|
13
|
+
default:
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { matchesShowIf };
|