diff --git a/formule-demo/cypress/e2e/builder.cy.ts b/formule-demo/cypress/e2e/builder.cy.ts
index 3d51f64..7fc4560 100644
--- a/formule-demo/cypress/e2e/builder.cy.ts
+++ b/formule-demo/cypress/e2e/builder.cy.ts
@@ -194,6 +194,20 @@ describe("test basic functionality", () => {
// TODO test also suggestion endpoint, after that feature is migrated to formule
});
+ it("tests email field", () => {
+ cy.addFieldWithName("email", "myfield");
+ cy.getByDataCy("treeItem").click();
+
+ // Test pattern allowing only one character
+ cy.getByDataCy("formPreview")
+ .find(`input#root${SEP}myfield`)
+ .as("myfield")
+ .clearTypeBlur("a");
+ cy.getByDataCy("formPreview").hasErrorMessage('must match format "email"');
+ cy.get("@myfield").clearTypeBlur("test@example.com");
+ cy.getByDataCy("formPreview").hasNoErrorMessage();
+ });
+
it("tests number field", () => {
cy.addFieldWithName("number", "myfield");
cy.getByDataCy("treeItem").click();
diff --git a/formule-demo/src/App.tsx b/formule-demo/src/App.tsx
index af0612d..cd04b72 100644
--- a/formule-demo/src/App.tsx
+++ b/formule-demo/src/App.tsx
@@ -34,7 +34,7 @@ import {
} from "antd";
import { useEffect, useState } from "react";
import {
- CodeViewer,
+ SchemaCodeEditor,
FormPreview,
FormuleContext,
SchemaPreview,
@@ -331,11 +331,11 @@ const App = () => {
}}
>
Schema
-
{
}}
>
UI Schema
-
{
}}
>
Form data
-
@@ -434,7 +434,7 @@ const App = () => {
const reader = new FileReader();
reader.onload = (event) => {
const newSchema = JSON.parse(
- event?.target?.result as string
+ event?.target?.result as string,
);
const { schema, uiSchema } = newSchema;
if (schema && uiSchema) {
@@ -443,7 +443,7 @@ const App = () => {
message.success("Uploaded and loaded successfully");
} else {
message.error(
- "Your json should include a schema and a uiSchema key"
+ "Your json should include a schema and a uiSchema key",
);
}
};
diff --git a/src/admin/components/SchemaCodeEditor.jsx b/src/admin/components/SchemaCodeEditor.jsx
new file mode 100644
index 0000000..7157041
--- /dev/null
+++ b/src/admin/components/SchemaCodeEditor.jsx
@@ -0,0 +1,37 @@
+import {
+ updateSchemaByPath,
+ updateUiSchemaByPath,
+} from "../../store/schemaWizard";
+import { useDispatch } from "react-redux";
+import CodeEditor from "../../utils/CodeEditor";
+
+const SchemaCodeEditor = ({ valueType, value, height, lang, isReadOnly }) => {
+ const dispatch = useDispatch();
+
+ const _onSchemaChange = (data) => {
+ dispatch(updateSchemaByPath({ path: [], value: JSON.parse(data) }));
+ };
+
+ const _onUiSchemaChange = (data) => {
+ dispatch(updateUiSchemaByPath({ path: [], value: JSON.parse(data) }));
+ };
+
+ const _handleEdit = (data) => {
+ if (valueType == "schema") _onSchemaChange(data);
+ else if (valueType == "uiSchema") _onUiSchemaChange(data);
+ };
+
+ return (
+
+ );
+};
+
+export default SchemaCodeEditor;
diff --git a/src/admin/utils/fieldTypes.jsx b/src/admin/utils/fieldTypes.jsx
index 8e4c0d9..fb1be19 100644
--- a/src/admin/utils/fieldTypes.jsx
+++ b/src/admin/utils/fieldTypes.jsx
@@ -486,6 +486,31 @@ const simple = {
type: "string",
format: "regex",
},
+ format: {
+ title: "Format",
+ type: "string",
+ enum: [
+ "date",
+ "time",
+ "date-time",
+ "duration",
+ "regex",
+ "email",
+ "idn-email",
+ "hostname",
+ "idn-hostname",
+ "ipv4",
+ "ipv6",
+ "json-pointer",
+ "relative-json-pointer",
+ "uri",
+ "uri-reference",
+ "uri-template",
+ "iri",
+ "iri-reference",
+ "uuid",
+ ],
+ },
readOnly: extra.optionsSchema.readOnly,
isRequired: extra.optionsSchema.isRequired,
},
@@ -1061,6 +1086,93 @@ const simple = {
},
},
},
+ email: {
+ title: "Email",
+ icon: ,
+ description: "Email field supporting validation",
+ className: "tour-email-field",
+ child: {},
+ optionsSchema: {
+ type: "object",
+ title: "Text Schema",
+ properties: {
+ ...common.optionsSchema,
+ pattern: {
+ title: "Validation regex",
+ description:
+ "The input will be validated against this regex on form submission",
+ type: "string",
+ format: "regex",
+ },
+ readOnly: extra.optionsSchema.readOnly,
+ isRequired: extra.optionsSchema.isRequired,
+ },
+ },
+ optionsSchemaUiSchema: {
+ ...common.optionsSchemaUiSchema,
+ readOnly: extra.optionsSchemaUiSchema.readOnly,
+ isRequired: extra.optionsSchemaUiSchema.isRequired,
+ pattern: {
+ "ui:placeholder": "^.*$",
+ },
+ },
+ optionsUiSchema: {
+ type: "object",
+ title: "UI Schema",
+ properties: {
+ "ui:options": {
+ type: "object",
+ title: "UI Options",
+ dependencies:
+ common.optionsUiSchema.properties["ui:options"].dependencies,
+ properties: {
+ ...common.optionsUiSchema.properties["ui:options"].properties,
+ suggestions: {
+ type: "string",
+ title: "Add a suggestion URL endpoint",
+ description: "Provide an URL endpoint, to fetch data from there",
+ },
+ convertToUppercase: {
+ type: "boolean",
+ title: "Convert input to uppercase",
+ },
+ mask: {
+ type: "string",
+ title: "Input mask",
+ tooltip:
+ "Add a mask to visualize and limit the format of the input. Use the following format: `0` (number), `a` (lowercase letter), `A` (uppercase letter), `*` (letter or number). You can escape all these with `\\`. The rest of the characters will be treated as constants",
+ },
+ },
+ },
+ "ui:label": common.optionsUiSchema.properties["ui:label"],
+ },
+ },
+ optionsUiSchemaUiSchema: {
+ ...common.optionsUiSchemaUiSchema,
+ "ui:options": {
+ ...common.optionsUiSchemaUiSchema["ui:options"],
+ mask: {
+ "ui:placeholder": "BN-000/aa",
+ "ui:options": {
+ descriptionIsMarkdown: true,
+ tooltipIsMarkdown: true,
+ },
+ },
+ convertToUppercase: {
+ "ui:widget": "switch",
+ },
+ },
+ },
+ default: {
+ schema: {
+ type: "string",
+ format: "email",
+ },
+ uiSchema: {
+ "ui:widget": "text",
+ },
+ },
+ },
};
const advanced = {
diff --git a/src/admin/utils/index.jsx b/src/admin/utils/index.jsx
index da3d855..ac56b82 100644
--- a/src/admin/utils/index.jsx
+++ b/src/admin/utils/index.jsx
@@ -26,7 +26,7 @@ export const _validate = function (formData, errors) {
};
export const shoudDisplayGuideLinePopUp = (schema) => {
- return schema.properties && Object.keys(schema.properties).length === 0;
+ return schema?.properties && Object.keys(schema?.properties).length === 0;
};
export const isItTheArrayField = (schema, uiSchema) => {
diff --git a/src/index.ts b/src/index.ts
index b89f7fa..361514a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -10,6 +10,7 @@ export { FormuleForm } from "./exposed";
export { default as PropertyEditor } from "./admin/components/PropertyEditor";
export { default as SelectFieldType } from "./admin/components/SelectFieldType";
+export { default as SchemaCodeEditor } from "./admin/components/SchemaCodeEditor";
export { default as SchemaPreview } from "./admin/components/SchemaPreview";
export { default as FormPreview } from "./admin/components/FormPreview";
export { default as EditablePreview } from "./admin/components/EditablePreview";