@verbb/plugin-kit-react 1.0.9 → 1.0.10

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/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 1.0.10 - 2026-07-09
6
+
7
+ ### Added
8
+ - Added `requiredRichText` validation rule for schema fields that store TipTap/ProseMirror JSON, so empty rich-text documents (including `[]` and bare paragraph nodes) are treated as blank.
9
+ - Added `isRichTextEmpty` utility to detect when stored TipTap content has no user-visible text (exported from `@verbb/plugin-kit-react/utils`).
10
+
11
+ ### Changed
12
+ - Changed validation engines to treat both `required` and `requiredRichText` as required-field rules for dependency and shortcut logic.
13
+
14
+ ### Fixed
15
+ - Fixed `translate()` failing validation when Craft's translation helper throws (for example missing translation keys), falling back to the raw message instead.
16
+
5
17
  ## 1.0.9 - 2026-07-02
6
18
 
7
19
  ### Changed
@@ -1 +1 @@
1
- {"version":3,"file":"ValidationEngine.d.ts","sourceRoot":"","sources":["../../../src/forms/engine/ValidationEngine.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAc,WAAW,EAAE,UAAU,EAAoB,MAAM,eAAe,CAAC;AAG3F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAU5C,KAAK,qBAAqB,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAsMjG,MAAM,MAAM,gBAAgB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CAAE,GAAG,SAAS,CAAC;AAEhF,eAAO,MAAM,sBAAsB,GAC/B,OAAO,WAAW,EAClB,UAAS;IAAE,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;CAAO;uBAUrC,UAAU,KAAG,gBAAgB;CAmC1D,CAAC"}
1
+ {"version":3,"file":"ValidationEngine.d.ts","sourceRoot":"","sources":["../../../src/forms/engine/ValidationEngine.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAc,WAAW,EAAE,UAAU,EAAoB,MAAM,eAAe,CAAC;AAI3F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAU5C,KAAK,qBAAqB,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAsMjG,MAAM,MAAM,gBAAgB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CAAE,GAAG,SAAS,CAAC;AAEhF,eAAO,MAAM,sBAAsB,GAC/B,OAAO,WAAW,EAClB,UAAS;IAAE,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;CAAO;uBAUrC,UAAU,KAAG,gBAAgB;CAmC1D,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { evaluateCondition } from "../../utils/schema.js";
2
+ import { isRequiredRuleName } from "./rules/requiredRules.js";
2
3
  import { isEmptyValue } from "./rules/utils.js";
3
4
  import { ruleHandlers } from "./rules/index.js";
4
5
  import { get } from "lodash-es";
@@ -50,7 +51,7 @@ var expandWildcardPaths = (values, path) => {
50
51
  var validateValue = (field, rules, value, context) => {
51
52
  const label = String(field.label || field.name || "");
52
53
  const isRequired = rules.some((rule) => {
53
- return rule.name === "required";
54
+ return isRequiredRuleName(rule.name);
54
55
  });
55
56
  for (const rule of rules) {
56
57
  const { name, args } = rule;
@@ -1 +1 @@
1
- {"version":3,"file":"ValidationEngine.js","names":[],"sources":["../../../src/forms/engine/ValidationEngine.ts"],"sourcesContent":["import { get } from 'lodash-es';\nimport { evaluateCondition } from '@verbb/plugin-kit-react/utils/schema';\n\nimport type { FieldEntry, SchemaIndex, SchemaNode, SchemaRenderable } from './SchemaIndex';\nimport { ruleHandlers, RuleHandlerContext } from './rules';\nimport { isEmptyValue } from './rules/utils';\nimport type { FormValues } from './context';\n\ntype RuleToken = {\n name: string;\n args: string[];\n};\ntype ConditionContext = {\n condition: string;\n field: SchemaNode;\n};\ntype ConditionDataResolver = (values: FormValues, field?: SchemaNode) => Record<string, unknown>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n};\n\nconst parseRules = (field: { validation?: string; required?: boolean }): RuleToken[] => {\n const rawRules = typeof field.validation === 'string' ? field.validation : '';\n const tokens = rawRules\n .split('|')\n .map((token) => { return token.trim(); })\n .filter(Boolean);\n\n const hasRequiredRule = tokens.some((rule) => { return rule === 'required' || rule.startsWith('required'); });\n if (field.required && !hasRequiredRule) {\n tokens.unshift('required');\n }\n\n return tokens.map((token) => {\n const [name, ...rest] = token.split(':');\n const args = rest.length > 0 ? rest.join(':').split(',') : [];\n return { name, args };\n });\n};\n\nconst expandWildcardPaths = (values: FormValues, path: string) => {\n if (!path.includes('*')) {\n return [path];\n }\n\n const parts = path.split('.');\n const results: string[] = [];\n\n const walk = (current: unknown, index: number, acc: string[]) => {\n if (index >= parts.length) {\n results.push(acc.join('.'));\n return;\n }\n\n const part = parts[index];\n if (part === '*') {\n if (Array.isArray(current)) {\n current.forEach((item, idx) => {\n walk(item, index + 1, [...acc, String(idx)]);\n });\n }\n return;\n }\n\n if (isRecord(current) && part in current) {\n walk(current[part], index + 1, [...acc, part]);\n return;\n }\n\n walk(undefined, index + 1, [...acc, part]);\n };\n\n walk(values, 0, []);\n return results;\n};\n\nconst validateValue = (\n field: SchemaNode,\n rules: RuleToken[],\n value: unknown,\n context: RuleHandlerContext,\n) => {\n const label = String(field.label || field.name || '');\n const isRequired = rules.some((rule) => { return rule.name === 'required'; });\n\n for (const rule of rules) {\n const { name, args } = rule;\n const shouldSkip = !isRequired && isEmptyValue(value);\n\n if (shouldSkip) {\n continue;\n }\n\n const handler = ruleHandlers[name];\n if (!handler) {\n continue;\n }\n\n const message = handler(value, label, args, context);\n if (message) {\n return message;\n }\n }\n\n return null;\n};\n\nconst buildConditionData = (\n field: SchemaNode,\n values: FormValues,\n conditionDataResolver?: ConditionDataResolver,\n) => {\n const scopePath = typeof field?._scopePath === 'string' ? field._scopePath : '';\n const scopedValues = scopePath ? get(values, scopePath) : null;\n const scopedObject = isRecord(scopedValues) ? scopedValues : {};\n const conditionContext = conditionDataResolver?.(values, field);\n const normalizedConditionContext = isRecord(conditionContext) ? conditionContext : {};\n const fieldData = isRecord(field._data) ? field._data : {};\n\n return {\n ...values,\n ...scopedObject,\n ...fieldData,\n ...normalizedConditionContext,\n };\n};\n\nconst shouldValidateField = (\n field: SchemaNode,\n values: FormValues,\n conditionDataResolver?: ConditionDataResolver,\n) => {\n const condition = field?.if;\n\n if (!condition) {\n return true;\n }\n\n try {\n return evaluateCondition(condition, buildConditionData(field, values, conditionDataResolver));\n } catch {\n // Fail-open to avoid accidentally blocking saves due to malformed conditions.\n return true;\n }\n};\n\nconst collectPathConditions = (schema: SchemaRenderable) => {\n const pathConditions = new Map<string, ConditionContext[]>();\n\n const walk = (node: SchemaRenderable, currentPath = '', inherited: ConditionContext[] = []) => {\n if (Array.isArray(node)) {\n node.forEach((child) => {\n walk(child, currentPath, inherited);\n });\n return;\n }\n\n if (!isRecord(node)) {\n return;\n }\n\n const name = typeof node.name === 'string' && node.name ? node.name : '';\n let nodePath = currentPath;\n if (name) {\n nodePath = currentPath ? `${currentPath}.${name}` : name;\n }\n\n const ownCondition = typeof node.if === 'string' && node.if\n ? [{ condition: node.if, field: node }]\n : [];\n const nextInherited = [...inherited, ...ownCondition];\n\n if (nodePath && nextInherited.length) {\n pathConditions.set(nodePath, nextInherited);\n }\n\n if (Array.isArray(node.children)) {\n walk(node.children, nodePath, nextInherited);\n }\n\n if (Array.isArray(node.schema)) {\n walk(node.schema, nodePath, nextInherited);\n }\n };\n\n walk(schema, '', []);\n\n return pathConditions;\n};\n\nconst shouldValidatePathConditions = (\n path: string,\n fallbackField: SchemaNode,\n values: FormValues,\n pathConditions: Map<string, ConditionContext[]>,\n conditionDataResolver?: ConditionDataResolver,\n) => {\n const conditions = pathConditions.get(path) || [];\n\n if (!conditions.length) {\n return true;\n }\n\n return conditions.every(({ condition, field }) => {\n try {\n return evaluateCondition(condition, buildConditionData(field || fallbackField, values, conditionDataResolver));\n } catch {\n // Fail-open to avoid accidental save blocking on malformed conditions.\n return true;\n }\n });\n};\n\nexport type ValidationResult = { fields: Record<string, string[]> } | undefined;\n\nexport const createValidationEngine = (\n index: SchemaIndex,\n options: { conditionDataResolver?: ConditionDataResolver } = {},\n) => {\n const { conditionDataResolver } = options;\n const fieldRules = new Map<FieldEntry, RuleToken[]>();\n const pathConditions = collectPathConditions(index.schema);\n\n index.fieldEntries.forEach((entry) => {\n fieldRules.set(entry, parseRules(entry.field));\n });\n\n const validate = (values: FormValues): ValidationResult => {\n const fieldErrors: Record<string, string[]> = {};\n index.fieldEntries.forEach((entry) => {\n const rules = fieldRules.get(entry) || [];\n if (!rules.length) {\n return;\n }\n\n if (!shouldValidateField(entry.field, values, conditionDataResolver)) {\n return;\n }\n\n const paths = expandWildcardPaths(values, entry.path);\n paths.forEach((path) => {\n if (!shouldValidatePathConditions(path, entry.field, values, pathConditions, conditionDataResolver)) {\n return;\n }\n\n const value = get(values, path);\n const message = validateValue(entry.field, rules, value, {\n path,\n values,\n field: entry.field,\n });\n if (message) {\n fieldErrors[path] = [message];\n\n }\n });\n });\n\n return Object.keys(fieldErrors).length > 0 ? { fields: fieldErrors } : undefined;\n };\n\n return { validate };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ValidationEngine.js","names":[],"sources":["../../../src/forms/engine/ValidationEngine.ts"],"sourcesContent":["import { get } from 'lodash-es';\nimport { evaluateCondition } from '@verbb/plugin-kit-react/utils/schema';\n\nimport type { FieldEntry, SchemaIndex, SchemaNode, SchemaRenderable } from './SchemaIndex';\nimport { ruleHandlers, RuleHandlerContext } from './rules';\nimport { isRequiredRuleName } from './rules/requiredRules';\nimport { isEmptyValue } from './rules/utils';\nimport type { FormValues } from './context';\n\ntype RuleToken = {\n name: string;\n args: string[];\n};\ntype ConditionContext = {\n condition: string;\n field: SchemaNode;\n};\ntype ConditionDataResolver = (values: FormValues, field?: SchemaNode) => Record<string, unknown>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n};\n\nconst parseRules = (field: { validation?: string; required?: boolean }): RuleToken[] => {\n const rawRules = typeof field.validation === 'string' ? field.validation : '';\n const tokens = rawRules\n .split('|')\n .map((token) => { return token.trim(); })\n .filter(Boolean);\n\n const hasRequiredRule = tokens.some((rule) => { return rule === 'required' || rule.startsWith('required'); });\n if (field.required && !hasRequiredRule) {\n tokens.unshift('required');\n }\n\n return tokens.map((token) => {\n const [name, ...rest] = token.split(':');\n const args = rest.length > 0 ? rest.join(':').split(',') : [];\n return { name, args };\n });\n};\n\nconst expandWildcardPaths = (values: FormValues, path: string) => {\n if (!path.includes('*')) {\n return [path];\n }\n\n const parts = path.split('.');\n const results: string[] = [];\n\n const walk = (current: unknown, index: number, acc: string[]) => {\n if (index >= parts.length) {\n results.push(acc.join('.'));\n return;\n }\n\n const part = parts[index];\n if (part === '*') {\n if (Array.isArray(current)) {\n current.forEach((item, idx) => {\n walk(item, index + 1, [...acc, String(idx)]);\n });\n }\n return;\n }\n\n if (isRecord(current) && part in current) {\n walk(current[part], index + 1, [...acc, part]);\n return;\n }\n\n walk(undefined, index + 1, [...acc, part]);\n };\n\n walk(values, 0, []);\n return results;\n};\n\nconst validateValue = (\n field: SchemaNode,\n rules: RuleToken[],\n value: unknown,\n context: RuleHandlerContext,\n) => {\n const label = String(field.label || field.name || '');\n const isRequired = rules.some((rule) => { return isRequiredRuleName(rule.name); });\n\n for (const rule of rules) {\n const { name, args } = rule;\n const shouldSkip = !isRequired && isEmptyValue(value);\n\n if (shouldSkip) {\n continue;\n }\n\n const handler = ruleHandlers[name];\n if (!handler) {\n continue;\n }\n\n const message = handler(value, label, args, context);\n if (message) {\n return message;\n }\n }\n\n return null;\n};\n\nconst buildConditionData = (\n field: SchemaNode,\n values: FormValues,\n conditionDataResolver?: ConditionDataResolver,\n) => {\n const scopePath = typeof field?._scopePath === 'string' ? field._scopePath : '';\n const scopedValues = scopePath ? get(values, scopePath) : null;\n const scopedObject = isRecord(scopedValues) ? scopedValues : {};\n const conditionContext = conditionDataResolver?.(values, field);\n const normalizedConditionContext = isRecord(conditionContext) ? conditionContext : {};\n const fieldData = isRecord(field._data) ? field._data : {};\n\n return {\n ...values,\n ...scopedObject,\n ...fieldData,\n ...normalizedConditionContext,\n };\n};\n\nconst shouldValidateField = (\n field: SchemaNode,\n values: FormValues,\n conditionDataResolver?: ConditionDataResolver,\n) => {\n const condition = field?.if;\n\n if (!condition) {\n return true;\n }\n\n try {\n return evaluateCondition(condition, buildConditionData(field, values, conditionDataResolver));\n } catch {\n // Fail-open to avoid accidentally blocking saves due to malformed conditions.\n return true;\n }\n};\n\nconst collectPathConditions = (schema: SchemaRenderable) => {\n const pathConditions = new Map<string, ConditionContext[]>();\n\n const walk = (node: SchemaRenderable, currentPath = '', inherited: ConditionContext[] = []) => {\n if (Array.isArray(node)) {\n node.forEach((child) => {\n walk(child, currentPath, inherited);\n });\n return;\n }\n\n if (!isRecord(node)) {\n return;\n }\n\n const name = typeof node.name === 'string' && node.name ? node.name : '';\n let nodePath = currentPath;\n if (name) {\n nodePath = currentPath ? `${currentPath}.${name}` : name;\n }\n\n const ownCondition = typeof node.if === 'string' && node.if\n ? [{ condition: node.if, field: node }]\n : [];\n const nextInherited = [...inherited, ...ownCondition];\n\n if (nodePath && nextInherited.length) {\n pathConditions.set(nodePath, nextInherited);\n }\n\n if (Array.isArray(node.children)) {\n walk(node.children, nodePath, nextInherited);\n }\n\n if (Array.isArray(node.schema)) {\n walk(node.schema, nodePath, nextInherited);\n }\n };\n\n walk(schema, '', []);\n\n return pathConditions;\n};\n\nconst shouldValidatePathConditions = (\n path: string,\n fallbackField: SchemaNode,\n values: FormValues,\n pathConditions: Map<string, ConditionContext[]>,\n conditionDataResolver?: ConditionDataResolver,\n) => {\n const conditions = pathConditions.get(path) || [];\n\n if (!conditions.length) {\n return true;\n }\n\n return conditions.every(({ condition, field }) => {\n try {\n return evaluateCondition(condition, buildConditionData(field || fallbackField, values, conditionDataResolver));\n } catch {\n // Fail-open to avoid accidental save blocking on malformed conditions.\n return true;\n }\n });\n};\n\nexport type ValidationResult = { fields: Record<string, string[]> } | undefined;\n\nexport const createValidationEngine = (\n index: SchemaIndex,\n options: { conditionDataResolver?: ConditionDataResolver } = {},\n) => {\n const { conditionDataResolver } = options;\n const fieldRules = new Map<FieldEntry, RuleToken[]>();\n const pathConditions = collectPathConditions(index.schema);\n\n index.fieldEntries.forEach((entry) => {\n fieldRules.set(entry, parseRules(entry.field));\n });\n\n const validate = (values: FormValues): ValidationResult => {\n const fieldErrors: Record<string, string[]> = {};\n index.fieldEntries.forEach((entry) => {\n const rules = fieldRules.get(entry) || [];\n if (!rules.length) {\n return;\n }\n\n if (!shouldValidateField(entry.field, values, conditionDataResolver)) {\n return;\n }\n\n const paths = expandWildcardPaths(values, entry.path);\n paths.forEach((path) => {\n if (!shouldValidatePathConditions(path, entry.field, values, pathConditions, conditionDataResolver)) {\n return;\n }\n\n const value = get(values, path);\n const message = validateValue(entry.field, rules, value, {\n path,\n values,\n field: entry.field,\n });\n if (message) {\n fieldErrors[path] = [message];\n\n }\n });\n });\n\n return Object.keys(fieldErrors).length > 0 ? { fields: fieldErrors } : undefined;\n };\n\n return { validate };\n};\n"],"mappings":";;;;;;AAmBA,IAAM,YAAY,UAAqD;AACnE,QAAO,QAAQ,MAAM,IAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;AAG/E,IAAM,cAAc,UAAoE;CAEpF,MAAM,UADW,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa,IAEtE,MAAM,IAAI,CACV,KAAK,UAAU;AAAE,SAAO,MAAM,MAAM;GAAI,CACxC,OAAO,QAAQ;CAEpB,MAAM,kBAAkB,OAAO,MAAM,SAAS;AAAE,SAAO,SAAS,cAAc,KAAK,WAAW,WAAW;GAAI;AAC7G,KAAI,MAAM,YAAY,CAAC,gBACnB,QAAO,QAAQ,WAAW;AAG9B,QAAO,OAAO,KAAK,UAAU;EACzB,MAAM,CAAC,MAAM,GAAG,QAAQ,MAAM,MAAM,IAAI;AAExC,SAAO;GAAE;GAAM,MADF,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM,IAAI,GAAG,EAAE;GACxC;GACvB;;AAGN,IAAM,uBAAuB,QAAoB,SAAiB;AAC9D,KAAI,CAAC,KAAK,SAAS,IAAI,CACnB,QAAO,CAAC,KAAK;CAGjB,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,MAAM,UAAoB,EAAE;CAE5B,MAAM,QAAQ,SAAkB,OAAe,QAAkB;AAC7D,MAAI,SAAS,MAAM,QAAQ;AACvB,WAAQ,KAAK,IAAI,KAAK,IAAI,CAAC;AAC3B;;EAGJ,MAAM,OAAO,MAAM;AACnB,MAAI,SAAS,KAAK;AACd,OAAI,MAAM,QAAQ,QAAQ,CACtB,SAAQ,SAAS,MAAM,QAAQ;AAC3B,SAAK,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC;KAC9C;AAEN;;AAGJ,MAAI,SAAS,QAAQ,IAAI,QAAQ,SAAS;AACtC,QAAK,QAAQ,OAAO,QAAQ,GAAG,CAAC,GAAG,KAAK,KAAK,CAAC;AAC9C;;AAGJ,OAAK,KAAA,GAAW,QAAQ,GAAG,CAAC,GAAG,KAAK,KAAK,CAAC;;AAG9C,MAAK,QAAQ,GAAG,EAAE,CAAC;AACnB,QAAO;;AAGX,IAAM,iBACF,OACA,OACA,OACA,YACC;CACD,MAAM,QAAQ,OAAO,MAAM,SAAS,MAAM,QAAQ,GAAG;CACrD,MAAM,aAAa,MAAM,MAAM,SAAS;AAAE,SAAO,mBAAmB,KAAK,KAAK;GAAI;AAElF,MAAK,MAAM,QAAQ,OAAO;EACtB,MAAM,EAAE,MAAM,SAAS;AAGvB,MAFmB,CAAC,cAAc,aAAa,MAAM,CAGjD;EAGJ,MAAM,UAAU,aAAa;AAC7B,MAAI,CAAC,QACD;EAGJ,MAAM,UAAU,QAAQ,OAAO,OAAO,MAAM,QAAQ;AACpD,MAAI,QACA,QAAO;;AAIf,QAAO;;AAGX,IAAM,sBACF,OACA,QACA,0BACC;CACD,MAAM,YAAY,OAAO,OAAO,eAAe,WAAW,MAAM,aAAa;CAC7E,MAAM,eAAe,YAAY,IAAI,QAAQ,UAAU,GAAG;CAC1D,MAAM,eAAe,SAAS,aAAa,GAAG,eAAe,EAAE;CAC/D,MAAM,mBAAmB,wBAAwB,QAAQ,MAAM;CAC/D,MAAM,6BAA6B,SAAS,iBAAiB,GAAG,mBAAmB,EAAE;CACrF,MAAM,YAAY,SAAS,MAAM,MAAM,GAAG,MAAM,QAAQ,EAAE;AAE1D,QAAO;EACH,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;EACN;;AAGL,IAAM,uBACF,OACA,QACA,0BACC;CACD,MAAM,YAAY,OAAO;AAEzB,KAAI,CAAC,UACD,QAAO;AAGX,KAAI;AACA,SAAO,kBAAkB,WAAW,mBAAmB,OAAO,QAAQ,sBAAsB,CAAC;SACzF;AAEJ,SAAO;;;AAIf,IAAM,yBAAyB,WAA6B;CACxD,MAAM,iCAAiB,IAAI,KAAiC;CAE5D,MAAM,QAAQ,MAAwB,cAAc,IAAI,YAAgC,EAAE,KAAK;AAC3F,MAAI,MAAM,QAAQ,KAAK,EAAE;AACrB,QAAK,SAAS,UAAU;AACpB,SAAK,OAAO,aAAa,UAAU;KACrC;AACF;;AAGJ,MAAI,CAAC,SAAS,KAAK,CACf;EAGJ,MAAM,OAAO,OAAO,KAAK,SAAS,YAAY,KAAK,OAAO,KAAK,OAAO;EACtE,IAAI,WAAW;AACf,MAAI,KACA,YAAW,cAAc,GAAG,YAAY,GAAG,SAAS;EAGxD,MAAM,eAAe,OAAO,KAAK,OAAO,YAAY,KAAK,KACnD,CAAC;GAAE,WAAW,KAAK;GAAI,OAAO;GAAM,CAAC,GACrC,EAAE;EACR,MAAM,gBAAgB,CAAC,GAAG,WAAW,GAAG,aAAa;AAErD,MAAI,YAAY,cAAc,OAC1B,gBAAe,IAAI,UAAU,cAAc;AAG/C,MAAI,MAAM,QAAQ,KAAK,SAAS,CAC5B,MAAK,KAAK,UAAU,UAAU,cAAc;AAGhD,MAAI,MAAM,QAAQ,KAAK,OAAO,CAC1B,MAAK,KAAK,QAAQ,UAAU,cAAc;;AAIlD,MAAK,QAAQ,IAAI,EAAE,CAAC;AAEpB,QAAO;;AAGX,IAAM,gCACF,MACA,eACA,QACA,gBACA,0BACC;CACD,MAAM,aAAa,eAAe,IAAI,KAAK,IAAI,EAAE;AAEjD,KAAI,CAAC,WAAW,OACZ,QAAO;AAGX,QAAO,WAAW,OAAO,EAAE,WAAW,YAAY;AAC9C,MAAI;AACA,UAAO,kBAAkB,WAAW,mBAAmB,SAAS,eAAe,QAAQ,sBAAsB,CAAC;UAC1G;AAEJ,UAAO;;GAEb;;AAKN,IAAa,0BACT,OACA,UAA6D,EAAE,KAC9D;CACD,MAAM,EAAE,0BAA0B;CAClC,MAAM,6BAAa,IAAI,KAA8B;CACrD,MAAM,iBAAiB,sBAAsB,MAAM,OAAO;AAE1D,OAAM,aAAa,SAAS,UAAU;AAClC,aAAW,IAAI,OAAO,WAAW,MAAM,MAAM,CAAC;GAChD;CAEF,MAAM,YAAY,WAAyC;EACvD,MAAM,cAAwC,EAAE;AAChD,QAAM,aAAa,SAAS,UAAU;GAClC,MAAM,QAAQ,WAAW,IAAI,MAAM,IAAI,EAAE;AACzC,OAAI,CAAC,MAAM,OACP;AAGJ,OAAI,CAAC,oBAAoB,MAAM,OAAO,QAAQ,sBAAsB,CAChE;AAGU,uBAAoB,QAAQ,MAAM,KAChD,CAAM,SAAS,SAAS;AACpB,QAAI,CAAC,6BAA6B,MAAM,MAAM,OAAO,QAAQ,gBAAgB,sBAAsB,CAC/F;IAGJ,MAAM,QAAQ,IAAI,QAAQ,KAAK;IAC/B,MAAM,UAAU,cAAc,MAAM,OAAO,OAAO,OAAO;KACrD;KACA;KACA,OAAO,MAAM;KAChB,CAAC;AACF,QAAI,QACA,aAAY,QAAQ,CAAC,QAAQ;KAGnC;IACJ;AAEF,SAAO,OAAO,KAAK,YAAY,CAAC,SAAS,IAAI,EAAE,QAAQ,aAAa,GAAG,KAAA;;AAG3E,QAAO,EAAE,UAAU"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/forms/engine/rules/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,MAAM,kBAAkB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,kBAAkB,KAAK,MAAM,GAAG,IAAI,CAAC;AAEzH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAQpD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/forms/engine/rules/index.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,MAAM,kBAAkB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,kBAAkB,KAAK,MAAM,GAAG,IAAI,CAAC;AAEzH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CASpD,CAAC"}
@@ -4,12 +4,16 @@ import { handleRule } from "./handle.js";
4
4
  import { maxRule } from "./max.js";
5
5
  import { minRule } from "./min.js";
6
6
  import { requiredRule } from "./required.js";
7
+ import { requiredRichTextRule } from "./requiredRichText.js";
7
8
  import { uniqueHandleRule } from "./uniqueHandle.js";
8
9
  //#region src/forms/engine/rules/index.ts
9
10
  var ruleHandlers = {
10
11
  required: (value, label) => {
11
12
  return requiredRule(value, label);
12
13
  },
14
+ requiredRichText: (value, label) => {
15
+ return requiredRichTextRule(value, label);
16
+ },
13
17
  min: (value, label, args) => {
14
18
  return minRule(value, label, args);
15
19
  },
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/forms/engine/rules/index.ts"],"sourcesContent":["import { emailRule } from './email';\nimport { emailOrVariableRule } from './emailOrVariable';\nimport { handleRule } from './handle';\nimport { maxRule } from './max';\nimport { minRule } from './min';\nimport { requiredRule } from './required';\nimport { uniqueHandleRule } from './uniqueHandle';\n\nimport type { SchemaNode } from '../SchemaIndex';\n\nexport type RuleHandlerContext = {\n path: string;\n values: Record<string, unknown>;\n field: SchemaNode;\n};\n\nexport type RuleHandler = (value: unknown, label: string, args: string[], context?: RuleHandlerContext) => string | null;\n\nexport const ruleHandlers: Record<string, RuleHandler> = {\n required: (value, label) => { return requiredRule(value, label); },\n min: (value, label, args) => { return minRule(value, label, args); },\n max: (value, label, args) => { return maxRule(value, label, args); },\n email: (value, label) => { return emailRule(value, label); },\n emailOrVariable: (value, label) => { return emailOrVariableRule(value, label); },\n handle: (value) => { return handleRule(value); },\n uniqueHandle: (value, label, args, context) => { return uniqueHandleRule(value, label, args, context); },\n};\n"],"mappings":";;;;;;;;AAkBA,IAAa,eAA4C;CACrD,WAAW,OAAO,UAAU;AAAE,SAAO,aAAa,OAAO,MAAM;;CAC/D,MAAM,OAAO,OAAO,SAAS;AAAE,SAAO,QAAQ,OAAO,OAAO,KAAK;;CACjE,MAAM,OAAO,OAAO,SAAS;AAAE,SAAO,QAAQ,OAAO,OAAO,KAAK;;CACjE,QAAQ,OAAO,UAAU;AAAE,SAAO,UAAU,OAAO,MAAM;;CACzD,kBAAkB,OAAO,UAAU;AAAE,SAAO,oBAAoB,OAAO,MAAM;;CAC7E,SAAS,UAAU;AAAE,SAAO,WAAW,MAAM;;CAC7C,eAAe,OAAO,OAAO,MAAM,YAAY;AAAE,SAAO,iBAAiB,OAAO,OAAO,MAAM,QAAQ;;CACxG"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/forms/engine/rules/index.ts"],"sourcesContent":["import { emailRule } from './email';\nimport { emailOrVariableRule } from './emailOrVariable';\nimport { handleRule } from './handle';\nimport { maxRule } from './max';\nimport { minRule } from './min';\nimport { requiredRule } from './required';\nimport { requiredRichTextRule } from './requiredRichText';\nimport { uniqueHandleRule } from './uniqueHandle';\n\nimport type { SchemaNode } from '../SchemaIndex';\n\nexport type RuleHandlerContext = {\n path: string;\n values: Record<string, unknown>;\n field: SchemaNode;\n};\n\nexport type RuleHandler = (value: unknown, label: string, args: string[], context?: RuleHandlerContext) => string | null;\n\nexport const ruleHandlers: Record<string, RuleHandler> = {\n required: (value, label) => { return requiredRule(value, label); },\n requiredRichText: (value, label) => { return requiredRichTextRule(value, label); },\n min: (value, label, args) => { return minRule(value, label, args); },\n max: (value, label, args) => { return maxRule(value, label, args); },\n email: (value, label) => { return emailRule(value, label); },\n emailOrVariable: (value, label) => { return emailOrVariableRule(value, label); },\n handle: (value) => { return handleRule(value); },\n uniqueHandle: (value, label, args, context) => { return uniqueHandleRule(value, label, args, context); },\n};\n"],"mappings":";;;;;;;;;AAmBA,IAAa,eAA4C;CACrD,WAAW,OAAO,UAAU;AAAE,SAAO,aAAa,OAAO,MAAM;;CAC/D,mBAAmB,OAAO,UAAU;AAAE,SAAO,qBAAqB,OAAO,MAAM;;CAC/E,MAAM,OAAO,OAAO,SAAS;AAAE,SAAO,QAAQ,OAAO,OAAO,KAAK;;CACjE,MAAM,OAAO,OAAO,SAAS;AAAE,SAAO,QAAQ,OAAO,OAAO,KAAK;;CACjE,QAAQ,OAAO,UAAU;AAAE,SAAO,UAAU,OAAO,MAAM;;CACzD,kBAAkB,OAAO,UAAU;AAAE,SAAO,oBAAoB,OAAO,MAAM;;CAC7E,SAAS,UAAU;AAAE,SAAO,WAAW,MAAM;;CAC7C,eAAe,OAAO,OAAO,MAAM,YAAY;AAAE,SAAO,iBAAiB,OAAO,OAAO,MAAM,QAAQ;;CACxG"}
@@ -0,0 +1,2 @@
1
+ export declare const requiredRichTextRule: (value: unknown, label: string) => string | null;
2
+ //# sourceMappingURL=requiredRichText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requiredRichText.d.ts","sourceRoot":"","sources":["../../../../src/forms/engine/rules/requiredRichText.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,oBAAoB,GAAI,OAAO,OAAO,EAAE,OAAO,MAAM,kBAMjE,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { translate } from "../../../utils/translation.js";
2
+ import { isRichTextEmpty } from "../../../utils/tiptap.js";
3
+ //#region src/forms/engine/rules/requiredRichText.ts
4
+ var requiredRichTextRule = (value, label) => {
5
+ if (isRichTextEmpty(value)) return translate("{attribute} cannot be blank.", { attribute: label });
6
+ return null;
7
+ };
8
+ //#endregion
9
+ export { requiredRichTextRule };
10
+
11
+ //# sourceMappingURL=requiredRichText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requiredRichText.js","names":[],"sources":["../../../../src/forms/engine/rules/requiredRichText.ts"],"sourcesContent":["import { translate } from '@verbb/plugin-kit-react/utils/translation';\nimport { isRichTextEmpty } from '../../../utils/tiptap';\n\nexport const requiredRichTextRule = (value: unknown, label: string) => {\n if (isRichTextEmpty(value)) {\n return translate('{attribute} cannot be blank.', { attribute: label });\n }\n\n return null;\n};\n"],"mappings":";;;AAGA,IAAa,wBAAwB,OAAgB,UAAkB;AACnE,KAAI,gBAAgB,MAAM,CACtB,QAAO,UAAU,gCAAgC,EAAE,WAAW,OAAO,CAAC;AAG1E,QAAO"}
@@ -0,0 +1,3 @@
1
+ export declare const REQUIRED_RULE_NAMES: Set<string>;
2
+ export declare const isRequiredRuleName: (ruleName: string) => boolean;
3
+ //# sourceMappingURL=requiredRules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requiredRules.d.ts","sourceRoot":"","sources":["../../../../src/forms/engine/rules/requiredRules.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,aAA4C,CAAC;AAE7E,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,YAElD,CAAC"}
@@ -0,0 +1,9 @@
1
+ //#region src/forms/engine/rules/requiredRules.ts
2
+ var REQUIRED_RULE_NAMES = new Set(["required", "requiredRichText"]);
3
+ var isRequiredRuleName = (ruleName) => {
4
+ return REQUIRED_RULE_NAMES.has(ruleName);
5
+ };
6
+ //#endregion
7
+ export { REQUIRED_RULE_NAMES, isRequiredRuleName };
8
+
9
+ //# sourceMappingURL=requiredRules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requiredRules.js","names":[],"sources":["../../../../src/forms/engine/rules/requiredRules.ts"],"sourcesContent":["export const REQUIRED_RULE_NAMES = new Set(['required', 'requiredRichText']);\n\nexport const isRequiredRuleName = (ruleName: string) => {\n return REQUIRED_RULE_NAMES.has(ruleName);\n};\n"],"mappings":";AAAA,IAAa,sBAAsB,IAAI,IAAI,CAAC,YAAY,mBAAmB,CAAC;AAE5E,IAAa,sBAAsB,aAAqB;AACpD,QAAO,oBAAoB,IAAI,SAAS"}
@@ -15,7 +15,7 @@ import { getSchemaFieldIndex, hasSchemaErrorsCached } from "./schemaIndexCache.j
15
15
  import { normalizeSchemaNode } from "./schemaNormalize.js";
16
16
  import { zustandHmrFix } from "./store.js";
17
17
  import { clearTimeOptionsCache, generateTimeOptions } from "./timeOptions.js";
18
- import { getRichTextHtml, getRichTextText } from "./tiptap.js";
18
+ import { getRichTextHtml, getRichTextText, isRichTextEmpty } from "./tiptap.js";
19
19
  import { validateFormValues } from "./validation.js";
20
20
  export * from "@verbb/plugin-kit";
21
21
  //#region src/utils/index.ts
@@ -49,6 +49,7 @@ var utils_exports = /* @__PURE__ */ __exportAll({
49
49
  hostGetTimepickerOptions: () => hostGetTimepickerOptions,
50
50
  hostOpenElementSelector: () => hostOpenElementSelector,
51
51
  hostRequest: () => hostRequest,
52
+ isRichTextEmpty: () => isRichTextEmpty,
52
53
  normalizeAttrs: () => normalizeAttrs,
53
54
  normalizeSchemaNode: () => normalizeSchemaNode,
54
55
  parseDateTimeValue: () => parseDateTimeValue,
@@ -69,6 +70,6 @@ var utils_exports = /* @__PURE__ */ __exportAll({
69
70
  import * as import__verbb_plugin_kit from "@verbb/plugin-kit";
70
71
  __reExport(utils_exports, import__verbb_plugin_kit);
71
72
  //#endregion
72
- export { buildUniqueHandleFromSource, clearTimeOptionsCache, cn, configurePluginKitReact, createCraftHostBridge, createSchemaFieldIndex, ensureDocumentScrollStability, evaluateCondition, extractFieldNames, extractFields, formatDateTimeValue, generateTimeOptions, getDynamicReservedHandles, getHostBridge, getPortalClassName, getPortalContainer, getPortalTargetForAppend, getRichTextHtml, getRichTextText, getSchemaFieldIndex, getSchemaFieldNames, getShadowRootSelectors, hasSchemaErrors, hasSchemaErrorsCached, hostFormatDate, hostGetLocale, hostGetTimepickerOptions, hostOpenElementSelector, hostRequest, normalizeAttrs, normalizeSchemaNode, parseDateTimeValue, parseLocalDate, resolveCalendarMonth, setHostBridge, setPortalClassName, setPortalContainer, setShadowRootSelectors, setTranslateFunction, setTranslationCategory, startOfMonth, translate, traverseSchema, utils_exports, validateFormValues, zustandHmrFix };
73
+ export { buildUniqueHandleFromSource, clearTimeOptionsCache, cn, configurePluginKitReact, createCraftHostBridge, createSchemaFieldIndex, ensureDocumentScrollStability, evaluateCondition, extractFieldNames, extractFields, formatDateTimeValue, generateTimeOptions, getDynamicReservedHandles, getHostBridge, getPortalClassName, getPortalContainer, getPortalTargetForAppend, getRichTextHtml, getRichTextText, getSchemaFieldIndex, getSchemaFieldNames, getShadowRootSelectors, hasSchemaErrors, hasSchemaErrorsCached, hostFormatDate, hostGetLocale, hostGetTimepickerOptions, hostOpenElementSelector, hostRequest, isRichTextEmpty, normalizeAttrs, normalizeSchemaNode, parseDateTimeValue, parseLocalDate, resolveCalendarMonth, setHostBridge, setPortalClassName, setPortalContainer, setShadowRootSelectors, setTranslateFunction, setTranslationCategory, startOfMonth, translate, traverseSchema, utils_exports, validateFormValues, zustandHmrFix };
73
74
 
74
75
  //# sourceMappingURL=index.js.map
@@ -10,4 +10,10 @@ export declare const getRichTextHtml: (json: any) => any;
10
10
  * @returns {string} - Plain text string
11
11
  */
12
12
  export declare const getRichTextText: (json: any) => any;
13
+ /**
14
+ * Whether stored TipTap/ProseMirror content has no user-visible text.
15
+ * Empty editors often serialize to `[]` or `[{ type: 'paragraph' }]`, which are
16
+ * not blank for generic `isEmptyValue` checks.
17
+ */
18
+ export declare const isRichTextEmpty: (value: unknown) => boolean;
13
19
  //# sourceMappingURL=tiptap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tiptap.d.ts","sourceRoot":"","sources":["../../src/utils/tiptap.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,SAAI,QAuBnC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,SAAI,QAmBnC,CAAC"}
1
+ {"version":3,"file":"tiptap.d.ts","sourceRoot":"","sources":["../../src/utils/tiptap.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,SAAI,QAuBnC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,SAAI,QAmBnC,CAAC;AAyEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,OAAO,YAQ7C,CAAC"}
@@ -33,7 +33,60 @@ var getRichTextText = (json) => {
33
33
  if (!json) return "";
34
34
  return getRichTextHtml(json).replace(/<[^>]*>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, "\"").replace(/&#39;/g, "'").replace(/\s+/g, " ").trim();
35
35
  };
36
+ var INVISIBLE_CHAR_PATTERN = /[\u200B\u200C\u200D\u2060\uFEFF]/g;
37
+ var normalizeRichTextNodes = (value) => {
38
+ if (value == null || value === "") return [];
39
+ if (Array.isArray(value)) return value;
40
+ if (typeof value === "object") {
41
+ const node = value;
42
+ if (node.type === "doc" && Array.isArray(node.content)) return node.content;
43
+ if (node.type) return [node];
44
+ }
45
+ if (typeof value === "string") try {
46
+ return normalizeRichTextNodes(JSON.parse(value));
47
+ } catch {
48
+ return value.replace(INVISIBLE_CHAR_PATTERN, "").trim() ? [{
49
+ type: "paragraph",
50
+ content: [{
51
+ type: "text",
52
+ text: value
53
+ }]
54
+ }] : [];
55
+ }
56
+ return [];
57
+ };
58
+ var collectRichTextPlainText = (nodes) => {
59
+ let text = "";
60
+ const visit = (node) => {
61
+ if (!node || typeof node !== "object") return;
62
+ const jsonNode = node;
63
+ if (jsonNode.type === "text" && typeof jsonNode.text === "string") {
64
+ text += jsonNode.text.replace(INVISIBLE_CHAR_PATTERN, "");
65
+ return;
66
+ }
67
+ if (jsonNode.type === "variableTag") {
68
+ const attrs = jsonNode.attrs;
69
+ const label = typeof attrs?.label === "string" ? attrs.label : "";
70
+ const variableValue = typeof attrs?.value === "string" ? attrs.value : "";
71
+ text += (label || variableValue).replace(INVISIBLE_CHAR_PATTERN, "");
72
+ return;
73
+ }
74
+ if (Array.isArray(jsonNode.content)) jsonNode.content.forEach(visit);
75
+ };
76
+ nodes.forEach(visit);
77
+ return text.trim();
78
+ };
79
+ /**
80
+ * Whether stored TipTap/ProseMirror content has no user-visible text.
81
+ * Empty editors often serialize to `[]` or `[{ type: 'paragraph' }]`, which are
82
+ * not blank for generic `isEmptyValue` checks.
83
+ */
84
+ var isRichTextEmpty = (value) => {
85
+ const nodes = normalizeRichTextNodes(value);
86
+ if (!nodes.length) return true;
87
+ return collectRichTextPlainText(nodes).length === 0;
88
+ };
36
89
  //#endregion
37
- export { getRichTextHtml, getRichTextText };
90
+ export { getRichTextHtml, getRichTextText, isRichTextEmpty };
38
91
 
39
92
  //# sourceMappingURL=tiptap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tiptap.js","names":[],"sources":["../../src/utils/tiptap.ts"],"sourcesContent":["import { generateHTML } from '@tiptap/core';\nimport Document from '@tiptap/extension-document';\nimport Paragraph from '@tiptap/extension-paragraph';\nimport Text from '@tiptap/extension-text';\n\n/**\n * Convert ProseMirror JSON content to HTML\n * @param {Array} json - ProseMirror JSON content array\n * @returns {string} - Generated HTML string\n */\nexport const getRichTextHtml = (json) => {\n if (!json) {\n return '';\n }\n\n if (typeof json === 'string') {\n // If this is json-encoded, try to parse it\n try {\n json = JSON.parse(json);\n } catch {\n // If it's not valid JSON, return the original string\n return json;\n }\n }\n\n return generateHTML({\n type: 'doc',\n content: json,\n }, [\n Document,\n Paragraph,\n Text,\n ]);\n};\n\n/**\n * Extract plain text from ProseMirror JSON content\n * @param {Array} json - ProseMirror JSON content array\n * @returns {string} - Plain text string\n */\nexport const getRichTextText = (json) => {\n if (!json) {\n return '';\n }\n\n // Generate HTML first\n const html = getRichTextHtml(json);\n\n // Strip HTML tags and decode entities\n return html\n .replace(/<[^>]*>/g, ' ') // Replace HTML tags with spaces\n .replace(/&nbsp;/g, ' ') // Replace non-breaking spaces\n .replace(/&amp;/g, '&') // Decode common HTML entities\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/\\s+/g, ' ') // Replace multiple spaces with single space\n .trim();\n};\n"],"mappings":";;;;;;;;;;AAUA,IAAa,mBAAmB,SAAS;AACrC,KAAI,CAAC,KACD,QAAO;AAGX,KAAI,OAAO,SAAS,SAEhB,KAAI;AACA,SAAO,KAAK,MAAM,KAAK;SACnB;AAEJ,SAAO;;AAIf,QAAO,aAAa;EAChB,MAAM;EACN,SAAS;EACZ,EAAE;EACC;EACA;EACA;EACH,CAAC;;;;;;;AAQN,IAAa,mBAAmB,SAAS;AACrC,KAAI,CAAC,KACD,QAAO;AAOX,QAHa,gBAAgB,KAGtB,CACF,QAAQ,YAAY,IAAI,CACxB,QAAQ,WAAW,IAAI,CACvB,QAAQ,UAAU,IAAI,CACtB,QAAQ,SAAS,IAAI,CACrB,QAAQ,SAAS,IAAI,CACrB,QAAQ,WAAW,KAAI,CACvB,QAAQ,UAAU,IAAI,CACtB,QAAQ,QAAQ,IAAI,CACpB,MAAM"}
1
+ {"version":3,"file":"tiptap.js","names":[],"sources":["../../src/utils/tiptap.ts"],"sourcesContent":["import { generateHTML } from '@tiptap/core';\nimport Document from '@tiptap/extension-document';\nimport Paragraph from '@tiptap/extension-paragraph';\nimport Text from '@tiptap/extension-text';\n\n/**\n * Convert ProseMirror JSON content to HTML\n * @param {Array} json - ProseMirror JSON content array\n * @returns {string} - Generated HTML string\n */\nexport const getRichTextHtml = (json) => {\n if (!json) {\n return '';\n }\n\n if (typeof json === 'string') {\n // If this is json-encoded, try to parse it\n try {\n json = JSON.parse(json);\n } catch {\n // If it's not valid JSON, return the original string\n return json;\n }\n }\n\n return generateHTML({\n type: 'doc',\n content: json,\n }, [\n Document,\n Paragraph,\n Text,\n ]);\n};\n\n/**\n * Extract plain text from ProseMirror JSON content\n * @param {Array} json - ProseMirror JSON content array\n * @returns {string} - Plain text string\n */\nexport const getRichTextText = (json) => {\n if (!json) {\n return '';\n }\n\n // Generate HTML first\n const html = getRichTextHtml(json);\n\n // Strip HTML tags and decode entities\n return html\n .replace(/<[^>]*>/g, ' ') // Replace HTML tags with spaces\n .replace(/&nbsp;/g, ' ') // Replace non-breaking spaces\n .replace(/&amp;/g, '&') // Decode common HTML entities\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/\\s+/g, ' ') // Replace multiple spaces with single space\n .trim();\n};\n\nconst INVISIBLE_CHAR_PATTERN = /[\\u200B\\u200C\\u200D\\u2060\\uFEFF]/g;\n\nconst normalizeRichTextNodes = (value: unknown): unknown[] => {\n if (value == null || value === '') {\n return [];\n }\n\n if (Array.isArray(value)) {\n return value;\n }\n\n if (typeof value === 'object') {\n const node = value as Record<string, unknown>;\n\n if (node.type === 'doc' && Array.isArray(node.content)) {\n return node.content;\n }\n\n if (node.type) {\n return [node];\n }\n }\n\n if (typeof value === 'string') {\n try {\n return normalizeRichTextNodes(JSON.parse(value));\n } catch {\n const text = value.replace(INVISIBLE_CHAR_PATTERN, '').trim();\n\n return text\n ? [{ type: 'paragraph', content: [{ type: 'text', text: value }] }]\n : [];\n }\n }\n\n return [];\n};\n\nconst collectRichTextPlainText = (nodes: unknown[]): string => {\n let text = '';\n\n const visit = (node: unknown) => {\n if (!node || typeof node !== 'object') {\n return;\n }\n\n const jsonNode = node as Record<string, unknown>;\n\n if (jsonNode.type === 'text' && typeof jsonNode.text === 'string') {\n text += jsonNode.text.replace(INVISIBLE_CHAR_PATTERN, '');\n return;\n }\n\n if (jsonNode.type === 'variableTag') {\n const attrs = jsonNode.attrs as Record<string, unknown> | undefined;\n const label = typeof attrs?.label === 'string' ? attrs.label : '';\n const variableValue = typeof attrs?.value === 'string' ? attrs.value : '';\n text += (label || variableValue).replace(INVISIBLE_CHAR_PATTERN, '');\n return;\n }\n\n if (Array.isArray(jsonNode.content)) {\n jsonNode.content.forEach(visit);\n }\n };\n\n nodes.forEach(visit);\n\n return text.trim();\n};\n\n/**\n * Whether stored TipTap/ProseMirror content has no user-visible text.\n * Empty editors often serialize to `[]` or `[{ type: 'paragraph' }]`, which are\n * not blank for generic `isEmptyValue` checks.\n */\nexport const isRichTextEmpty = (value: unknown) => {\n const nodes = normalizeRichTextNodes(value);\n\n if (!nodes.length) {\n return true;\n }\n\n return collectRichTextPlainText(nodes).length === 0;\n};\n"],"mappings":";;;;;;;;;;AAUA,IAAa,mBAAmB,SAAS;AACrC,KAAI,CAAC,KACD,QAAO;AAGX,KAAI,OAAO,SAAS,SAEhB,KAAI;AACA,SAAO,KAAK,MAAM,KAAK;SACnB;AAEJ,SAAO;;AAIf,QAAO,aAAa;EAChB,MAAM;EACN,SAAS;EACZ,EAAE;EACC;EACA;EACA;EACH,CAAC;;;;;;;AAQN,IAAa,mBAAmB,SAAS;AACrC,KAAI,CAAC,KACD,QAAO;AAOX,QAHa,gBAAgB,KAGtB,CACF,QAAQ,YAAY,IAAI,CACxB,QAAQ,WAAW,IAAI,CACvB,QAAQ,UAAU,IAAI,CACtB,QAAQ,SAAS,IAAI,CACrB,QAAQ,SAAS,IAAI,CACrB,QAAQ,WAAW,KAAI,CACvB,QAAQ,UAAU,IAAI,CACtB,QAAQ,QAAQ,IAAI,CACpB,MAAM;;AAGf,IAAM,yBAAyB;AAE/B,IAAM,0BAA0B,UAA8B;AAC1D,KAAI,SAAS,QAAQ,UAAU,GAC3B,QAAO,EAAE;AAGb,KAAI,MAAM,QAAQ,MAAM,CACpB,QAAO;AAGX,KAAI,OAAO,UAAU,UAAU;EAC3B,MAAM,OAAO;AAEb,MAAI,KAAK,SAAS,SAAS,MAAM,QAAQ,KAAK,QAAQ,CAClD,QAAO,KAAK;AAGhB,MAAI,KAAK,KACL,QAAO,CAAC,KAAK;;AAIrB,KAAI,OAAO,UAAU,SACjB,KAAI;AACA,SAAO,uBAAuB,KAAK,MAAM,MAAM,CAAC;SAC5C;AAGJ,SAFa,MAAM,QAAQ,wBAAwB,GAAG,CAAC,MAEhD,GACD,CAAC;GAAE,MAAM;GAAa,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM;IAAO,CAAC;GAAE,CAAC,GACjE,EAAE;;AAIhB,QAAO,EAAE;;AAGb,IAAM,4BAA4B,UAA6B;CAC3D,IAAI,OAAO;CAEX,MAAM,SAAS,SAAkB;AAC7B,MAAI,CAAC,QAAQ,OAAO,SAAS,SACzB;EAGJ,MAAM,WAAW;AAEjB,MAAI,SAAS,SAAS,UAAU,OAAO,SAAS,SAAS,UAAU;AAC/D,WAAQ,SAAS,KAAK,QAAQ,wBAAwB,GAAG;AACzD;;AAGJ,MAAI,SAAS,SAAS,eAAe;GACjC,MAAM,QAAQ,SAAS;GACvB,MAAM,QAAQ,OAAO,OAAO,UAAU,WAAW,MAAM,QAAQ;GAC/D,MAAM,gBAAgB,OAAO,OAAO,UAAU,WAAW,MAAM,QAAQ;AACvE,YAAS,SAAS,eAAe,QAAQ,wBAAwB,GAAG;AACpE;;AAGJ,MAAI,MAAM,QAAQ,SAAS,QAAQ,CAC/B,UAAS,QAAQ,QAAQ,MAAM;;AAIvC,OAAM,QAAQ,MAAM;AAEpB,QAAO,KAAK,MAAM;;;;;;;AAQtB,IAAa,mBAAmB,UAAmB;CAC/C,MAAM,QAAQ,uBAAuB,MAAM;AAE3C,KAAI,CAAC,MAAM,OACP,QAAO;AAGX,QAAO,yBAAyB,MAAM,CAAC,WAAW"}
@@ -1 +1 @@
1
- {"version":3,"file":"translation.d.ts","sourceRoot":"","sources":["../../src/utils/translation.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAKrD,eAAO,MAAM,sBAAsB,GAAI,UAAU,MAAM,KAAG,IAEzD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,KAAK,MAAM,KAAG,IAEnH,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,SAAS,MAAM,EAAE,SAAS,eAAe,KAAG,MAcrE,CAAC"}
1
+ {"version":3,"file":"translation.d.ts","sourceRoot":"","sources":["../../src/utils/translation.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAKrD,eAAO,MAAM,sBAAsB,GAAI,UAAU,MAAM,KAAG,IAEzD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,KAAK,MAAM,KAAG,IAEnH,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,SAAS,MAAM,EAAE,SAAS,eAAe,KAAG,MAkBrE,CAAC"}
@@ -11,7 +11,11 @@ var translate = (message, params) => {
11
11
  if (translateFn) return translateFn(translationCategory, message, params);
12
12
  if (typeof window !== "undefined") {
13
13
  const craft = window.Craft;
14
- if (craft?.t) return craft.t(translationCategory, message, params);
14
+ if (craft?.t) try {
15
+ return craft.t(translationCategory, message, params);
16
+ } catch {
17
+ return message;
18
+ }
15
19
  }
16
20
  return message;
17
21
  };
@@ -1 +1 @@
1
- {"version":3,"file":"translation.js","names":[],"sources":["../../src/utils/translation.ts"],"sourcesContent":["export type TranslateParams = Record<string, string>;\n\nlet translationCategory = 'plugin-handle';\nlet translateFn: ((category: string, message: string, params?: TranslateParams) => string) | undefined;\n\nexport const setTranslationCategory = (category: string): void => {\n translationCategory = category.trim() || 'plugin-handle';\n};\n\nexport const setTranslateFunction = (fn?: (category: string, message: string, params?: TranslateParams) => string): void => {\n translateFn = fn;\n};\n\nexport const translate = (message: string, params?: TranslateParams): string => {\n if (translateFn) {\n return translateFn(translationCategory, message, params);\n }\n\n if (typeof window !== 'undefined') {\n const craft = (window as { Craft?: { t?: (category: string, message: string, params?: TranslateParams) => string } }).Craft;\n\n if (craft?.t) {\n return craft.t(translationCategory, message, params);\n }\n }\n\n return message;\n};\n"],"mappings":";AAEA,IAAI,sBAAsB;AAC1B,IAAI;AAEJ,IAAa,0BAA0B,aAA2B;AAC9D,uBAAsB,SAAS,MAAM,IAAI;;AAG7C,IAAa,wBAAwB,OAAuF;AACxH,eAAc;;AAGlB,IAAa,aAAa,SAAiB,WAAqC;AAC5E,KAAI,YACA,QAAO,YAAY,qBAAqB,SAAS,OAAO;AAG5D,KAAI,OAAO,WAAW,aAAa;EAC/B,MAAM,QAAS,OAAuG;AAEtH,MAAI,OAAO,EACP,QAAO,MAAM,EAAE,qBAAqB,SAAS,OAAO;;AAI5D,QAAO"}
1
+ {"version":3,"file":"translation.js","names":[],"sources":["../../src/utils/translation.ts"],"sourcesContent":["export type TranslateParams = Record<string, string>;\n\nlet translationCategory = 'plugin-handle';\nlet translateFn: ((category: string, message: string, params?: TranslateParams) => string) | undefined;\n\nexport const setTranslationCategory = (category: string): void => {\n translationCategory = category.trim() || 'plugin-handle';\n};\n\nexport const setTranslateFunction = (fn?: (category: string, message: string, params?: TranslateParams) => string): void => {\n translateFn = fn;\n};\n\nexport const translate = (message: string, params?: TranslateParams): string => {\n if (translateFn) {\n return translateFn(translationCategory, message, params);\n }\n\n if (typeof window !== 'undefined') {\n const craft = (window as { Craft?: { t?: (category: string, message: string, params?: TranslateParams) => string } }).Craft;\n\n if (craft?.t) {\n try {\n return craft.t(translationCategory, message, params);\n } catch {\n return message;\n }\n }\n }\n\n return message;\n};\n"],"mappings":";AAEA,IAAI,sBAAsB;AAC1B,IAAI;AAEJ,IAAa,0BAA0B,aAA2B;AAC9D,uBAAsB,SAAS,MAAM,IAAI;;AAG7C,IAAa,wBAAwB,OAAuF;AACxH,eAAc;;AAGlB,IAAa,aAAa,SAAiB,WAAqC;AAC5E,KAAI,YACA,QAAO,YAAY,qBAAqB,SAAS,OAAO;AAG5D,KAAI,OAAO,WAAW,aAAa;EAC/B,MAAM,QAAS,OAAuG;AAEtH,MAAI,OAAO,EACP,KAAI;AACA,UAAO,MAAM,EAAE,qBAAqB,SAAS,OAAO;UAChD;AACJ,UAAO;;;AAKnB,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AA6VA,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CAAE,GAAG,SAAS,CA0GlD"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAsWA,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CAAE,GAAG,SAAS,CA0GlD"}
@@ -1,4 +1,6 @@
1
1
  import { translate } from "./translation.js";
2
+ import { isRichTextEmpty } from "./tiptap.js";
3
+ import { isRequiredRuleName } from "../forms/engine/rules/requiredRules.js";
2
4
  import * as v from "valibot";
3
5
  //#region src/utils/validation.ts
4
6
  var isRecord = (value) => {
@@ -135,7 +137,7 @@ var variableRegex = /({.*?})/;
135
137
  var buildFieldSchema = (field, rules) => {
136
138
  const label = String(field.label || field.name || "");
137
139
  const isRequired = rules.some((rule) => {
138
- return rule.name === "required";
140
+ return isRequiredRuleName(rule.name);
139
141
  });
140
142
  const actions = [];
141
143
  rules.forEach((rule) => {
@@ -150,6 +152,11 @@ var buildFieldSchema = (field, rules) => {
150
152
  return !isEmptyValue(value);
151
153
  }, translate("{attribute} cannot be blank.", { attribute: label })));
152
154
  break;
155
+ case "requiredRichText":
156
+ actions.push(v.check((value) => {
157
+ return !isRichTextEmpty(value);
158
+ }, translate("{attribute} cannot be blank.", { attribute: label })));
159
+ break;
153
160
  case "email":
154
161
  actions.push(v.check((value) => {
155
162
  if (maybeSkip(value)) return true;
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","names":[],"sources":["../../src/utils/validation.ts"],"sourcesContent":["import * as v from 'valibot';\nimport { translate } from '@verbb/plugin-kit-react/utils/translation';\n\n// ============================================================================\n// Valibot schema adapter\n// ============================================================================\n// We accept Laravel-style rule strings from Craft schema and turn them into\n// Valibot validation actions. This keeps the server-driven rules contract\n// while avoiding validatorjs' brittle attribute handling.\n\n// Minimal schema shape required to derive rules/labels.\ntype SchemaField = {\n name?: string;\n label?: string;\n required?: boolean;\n validation?: string;\n $field?: string;\n children?: SchemaValue;\n columns?: Array<SchemaField & { type?: string }>;\n};\n\ntype SchemaValue = SchemaField | SchemaValue[] | null | undefined;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n};\n\ntype RuleToken = {\n name: string;\n args: string[];\n};\n\nconst parseRules = (field: SchemaField): RuleToken[] => {\n const rawRules = typeof field.validation === 'string' ? field.validation : '';\n const tokens = rawRules\n .split('|')\n .map((token) => { return token.trim(); })\n .filter(Boolean);\n\n const hasRequiredRule = tokens.some((rule) => { return rule === 'required' || rule.startsWith('required'); });\n if (field.required && !hasRequiredRule) {\n tokens.unshift('required');\n }\n\n return tokens.map((token) => {\n const [name, ...rest] = token.split(':');\n const args = rest.length > 0 ? rest.join(':').split(',') : [];\n return { name, args };\n });\n};\n\nconst isEmptyValue = (value: unknown) => {\n if (value === undefined || value === null) {\n return true;\n }\n\n if (typeof value === 'string') {\n return value === '';\n }\n\n if (Array.isArray(value)) {\n return value.length === 0;\n }\n\n return false;\n};\n\nconst getValueSize = (value: unknown) => {\n if (typeof value === 'number') {\n return value;\n }\n\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed !== '' && Number.isFinite(Number(trimmed))) {\n return Number(trimmed);\n }\n\n return value.length;\n }\n\n if (Array.isArray(value)) {\n return value.length;\n }\n\n return NaN;\n};\n\n// Walk schema nodes and collect all fields that can be validated.\n// - list fields: expand children using wildcard paths (`list.*.field`)\n// - table fields: validate the table itself (required / min rules), then each\n// column per row (`table.*.column`)\n// - default fields: just collect as-is\nconst collectFields = (node: SchemaValue, prefix = '', fields: SchemaField[] = []) => {\n if (!node) {\n return fields;\n }\n\n if (Array.isArray(node)) {\n node.forEach((child) => { return collectFields(child, prefix, fields); });\n return fields;\n }\n\n if (!isRecord(node)) {\n return fields;\n }\n\n if (node.$field === 'list' && node.name) {\n if (node.children) {\n collectFields(node.children, `${prefix}${node.name}.*.`, fields);\n }\n return fields;\n }\n\n if (node.$field === 'table' && node.name) {\n fields.push({\n ...node,\n name: `${prefix}${node.name}`,\n });\n\n if (!Array.isArray(node.columns)) {\n return fields;\n }\n\n node.columns.forEach((column: SchemaField & { type?: string }) => {\n if (!column?.name) {\n return;\n }\n\n if (column.type === 'heading' || column.type === 'label') {\n return;\n }\n\n fields.push({\n ...column,\n name: `${prefix}${node.name}.*.${column.name}`,\n });\n });\n\n return fields;\n }\n\n if (node.$field && node.name) {\n fields.push({\n ...node,\n name: `${prefix}${node.name}`,\n });\n }\n\n if (node.children) {\n collectFields(node.children, prefix, fields);\n }\n\n return fields;\n};\n\ntype TableDefinition = {\n name: string;\n label: string;\n columns: Record<string, string>;\n};\n\nconst collectTableDefinitions = (\n node: SchemaValue,\n tables: Record<string, TableDefinition> = {},\n): Record<string, TableDefinition> => {\n if (!node) {\n return tables;\n }\n\n if (Array.isArray(node)) {\n node.forEach((child) => { return collectTableDefinitions(child, tables); });\n return tables;\n }\n\n if (!isRecord(node)) {\n return tables;\n }\n\n if (node.$field === 'table' && node.name) {\n const tableName = String(node.name);\n const tableLabel = String(node.label || node.name);\n const columns: Record<string, string> = {};\n\n if (Array.isArray(node.columns)) {\n node.columns.forEach((column) => {\n if (!column?.name) {\n return;\n }\n\n columns[String(column.name)] = String(column.label || column.name);\n });\n }\n\n tables[tableName] = {\n name: tableName,\n label: tableLabel,\n columns,\n };\n }\n\n if (node.children) {\n collectTableDefinitions(node.children, tables);\n }\n\n return tables;\n};\n\nconst expandWildcardPaths = (values: Record<string, unknown>, path: string) => {\n if (!path.includes('*')) {\n return [path];\n }\n\n const parts = path.split('.');\n const results: string[] = [];\n\n const walk = (current: unknown, index: number, acc: string[]) => {\n if (index >= parts.length) {\n results.push(acc.join('.'));\n return;\n }\n\n const part = parts[index];\n if (part === '*') {\n if (Array.isArray(current)) {\n current.forEach((item, idx) => {\n walk(item, index + 1, [...acc, String(idx)]);\n });\n }\n return;\n }\n\n if (isRecord(current) && part in current) {\n walk(current[part], index + 1, [...acc, part]);\n return;\n }\n\n // Allow missing leaf keys so required rules still validate.\n walk(undefined, index + 1, [...acc, part]);\n };\n\n walk(values, 0, []);\n return results;\n};\n\nconst getValueAtPath = (values: Record<string, unknown>, path: string) => {\n if (!path) {\n return undefined;\n }\n\n return path.split('.').reduce<unknown>((current, segment) => {\n if (current === undefined || current === null) {\n return undefined;\n }\n\n const key = Array.isArray(current) ? Number(segment) : segment;\n return current[key as keyof typeof current];\n }, values);\n};\n\nconst emailRegex = /(^$|^(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$)/;\nconst variableRegex = /({.*?})/;\n\nconst buildFieldSchema = (field: SchemaField, rules: RuleToken[]) => {\n const label = String(field.label || field.name || '');\n const isRequired = rules.some((rule) => { return rule.name === 'required'; });\n\n const actions = [];\n\n rules.forEach((rule) => {\n const ruleName = rule.name;\n const { args } = rule;\n\n const maybeSkip = (value: unknown) => {\n return !isRequired && isEmptyValue(value);\n };\n\n switch (ruleName) {\n case 'required':\n actions.push(v.check(\n (value) => { return !isEmptyValue(value); },\n translate('{attribute} cannot be blank.', { attribute: label }),\n ));\n break;\n\n case 'email':\n actions.push(v.check(\n (value) => {\n if (maybeSkip(value)) {\n return true;\n }\n return emailRegex.test(String(value));\n },\n translate('{attribute} must be a valid email address.', { attribute: label }),\n ));\n break;\n\n case 'emailOrVariable':\n actions.push(v.check(\n (value) => {\n if (maybeSkip(value)) {\n return true;\n }\n const text = String(value);\n return variableRegex.test(text) || emailRegex.test(text);\n },\n translate('{attribute} must be a valid email address or variable.', { attribute: label }),\n ));\n break;\n\n case 'min': {\n const min = Number(args[0]);\n actions.push(v.check(\n (value) => {\n if (maybeSkip(value)) {\n return true;\n }\n const size = getValueSize(value);\n return Number.isFinite(size) ? size >= min : false;\n },\n translate('{attribute} must be at least {min}.', { attribute: label, min: String(args[0]) }),\n ));\n break;\n }\n\n case 'max': {\n const max = Number(args[0]);\n actions.push(v.check(\n (value) => {\n if (maybeSkip(value)) {\n return true;\n }\n const size = getValueSize(value);\n return Number.isFinite(size) ? size <= max : false;\n },\n translate('{attribute} must be at most {max}.', { attribute: label, max: String(args[0]) }),\n ));\n break;\n }\n\n default:\n break;\n }\n });\n\n return v.pipe(v.any(), ...actions);\n};\n\n// Run Valibot and return TanStack Form–friendly error shape.\nexport function validateFormValues(\n schema: unknown,\n values: Record<string, unknown>,\n): { fields: Record<string, string[]> } | undefined {\n const normalizedValues = values && typeof values === 'object' ? values : {};\n const fields = collectFields(schema as SchemaValue);\n\n if (!fields.length) {\n return undefined;\n }\n\n const fieldErrors: Record<string, string[]> = {};\n\n fields.forEach((field) => {\n if (!field?.name) {\n return;\n }\n\n const rules = parseRules(field);\n if (!rules.length) {\n return;\n }\n\n const validator = buildFieldSchema(field, rules);\n const paths = expandWildcardPaths(normalizedValues, field.name);\n\n paths.forEach((path) => {\n const value = getValueAtPath(normalizedValues, path);\n const result = v.safeParse(validator, value);\n\n if (result.success) {\n return;\n }\n\n const message = (result.issues || [])\n .map((issue) => { return issue.message; })\n .filter(Boolean)[0];\n\n if (message) {\n fieldErrors[path] = [message];\n }\n });\n });\n\n // Aggregate table row errors up to the parent table field.\n const tableDefinitions = collectTableDefinitions(schema);\n const formatColumnMessage = (message: string, label: string) => {\n const trimmed = String(message || '').trim();\n if (!trimmed) {\n return label;\n }\n\n const match = trimmed.match(/^.+?(\\s+(?:cannot|must|is)\\b.*)$/i);\n if (match) {\n return `${label}${match[1]}`;\n }\n\n return `${label}: ${trimmed}`;\n };\n\n Object.entries(tableDefinitions).forEach(([tableName, definition]) => {\n const nestedKeys = Object.keys(fieldErrors).filter((key) => {\n return key.startsWith(`${tableName}.`);\n });\n if (nestedKeys.length === 0) {\n return;\n }\n\n const columnErrors: Record<string, string[]> = {};\n nestedKeys.forEach((key) => {\n const matches = key.match(new RegExp(`^${tableName}\\\\.\\\\d+\\\\.(.+)$`));\n const columnName = matches?.[1];\n if (!columnName) {\n return;\n }\n\n const messages = fieldErrors[key] || [];\n if (!messages.length) {\n return;\n }\n\n if (!columnErrors[columnName]) {\n columnErrors[columnName] = [];\n }\n\n columnErrors[columnName].push(...messages);\n });\n\n const columnMessages = Object.entries(columnErrors).flatMap(([columnName, messages]) => {\n if (!messages.length) {\n return [];\n }\n\n const columnLabel = definition.columns[columnName] || columnName;\n const label = `${definition.label} - ${columnLabel}`;\n const uniqueMessages = Array.from(new Set(messages));\n const firstMessage = uniqueMessages[0];\n return firstMessage ? [formatColumnMessage(firstMessage, label)] : [];\n });\n\n if (!columnMessages.length) {\n return;\n }\n\n const merged = new Set([...(fieldErrors[tableName] || []), ...columnMessages]);\n fieldErrors[tableName] = Array.from(merged);\n });\n\n return Object.keys(fieldErrors).length > 0 ? { fields: fieldErrors } : undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"validation.js","names":[],"sources":["../../src/utils/validation.ts"],"sourcesContent":["import * as v from 'valibot';\nimport { translate } from '@verbb/plugin-kit-react/utils/translation';\nimport { isRequiredRuleName } from '../forms/engine/rules/requiredRules';\nimport { isRichTextEmpty } from './tiptap';\n\n// ============================================================================\n// Valibot schema adapter\n// ============================================================================\n// We accept Laravel-style rule strings from Craft schema and turn them into\n// Valibot validation actions. This keeps the server-driven rules contract\n// while avoiding validatorjs' brittle attribute handling.\n\n// Minimal schema shape required to derive rules/labels.\ntype SchemaField = {\n name?: string;\n label?: string;\n required?: boolean;\n validation?: string;\n $field?: string;\n children?: SchemaValue;\n columns?: Array<SchemaField & { type?: string }>;\n};\n\ntype SchemaValue = SchemaField | SchemaValue[] | null | undefined;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n};\n\ntype RuleToken = {\n name: string;\n args: string[];\n};\n\nconst parseRules = (field: SchemaField): RuleToken[] => {\n const rawRules = typeof field.validation === 'string' ? field.validation : '';\n const tokens = rawRules\n .split('|')\n .map((token) => { return token.trim(); })\n .filter(Boolean);\n\n const hasRequiredRule = tokens.some((rule) => { return rule === 'required' || rule.startsWith('required'); });\n if (field.required && !hasRequiredRule) {\n tokens.unshift('required');\n }\n\n return tokens.map((token) => {\n const [name, ...rest] = token.split(':');\n const args = rest.length > 0 ? rest.join(':').split(',') : [];\n return { name, args };\n });\n};\n\nconst isEmptyValue = (value: unknown) => {\n if (value === undefined || value === null) {\n return true;\n }\n\n if (typeof value === 'string') {\n return value === '';\n }\n\n if (Array.isArray(value)) {\n return value.length === 0;\n }\n\n return false;\n};\n\nconst getValueSize = (value: unknown) => {\n if (typeof value === 'number') {\n return value;\n }\n\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed !== '' && Number.isFinite(Number(trimmed))) {\n return Number(trimmed);\n }\n\n return value.length;\n }\n\n if (Array.isArray(value)) {\n return value.length;\n }\n\n return NaN;\n};\n\n// Walk schema nodes and collect all fields that can be validated.\n// - list fields: expand children using wildcard paths (`list.*.field`)\n// - table fields: validate the table itself (required / min rules), then each\n// column per row (`table.*.column`)\n// - default fields: just collect as-is\nconst collectFields = (node: SchemaValue, prefix = '', fields: SchemaField[] = []) => {\n if (!node) {\n return fields;\n }\n\n if (Array.isArray(node)) {\n node.forEach((child) => { return collectFields(child, prefix, fields); });\n return fields;\n }\n\n if (!isRecord(node)) {\n return fields;\n }\n\n if (node.$field === 'list' && node.name) {\n if (node.children) {\n collectFields(node.children, `${prefix}${node.name}.*.`, fields);\n }\n return fields;\n }\n\n if (node.$field === 'table' && node.name) {\n fields.push({\n ...node,\n name: `${prefix}${node.name}`,\n });\n\n if (!Array.isArray(node.columns)) {\n return fields;\n }\n\n node.columns.forEach((column: SchemaField & { type?: string }) => {\n if (!column?.name) {\n return;\n }\n\n if (column.type === 'heading' || column.type === 'label') {\n return;\n }\n\n fields.push({\n ...column,\n name: `${prefix}${node.name}.*.${column.name}`,\n });\n });\n\n return fields;\n }\n\n if (node.$field && node.name) {\n fields.push({\n ...node,\n name: `${prefix}${node.name}`,\n });\n }\n\n if (node.children) {\n collectFields(node.children, prefix, fields);\n }\n\n return fields;\n};\n\ntype TableDefinition = {\n name: string;\n label: string;\n columns: Record<string, string>;\n};\n\nconst collectTableDefinitions = (\n node: SchemaValue,\n tables: Record<string, TableDefinition> = {},\n): Record<string, TableDefinition> => {\n if (!node) {\n return tables;\n }\n\n if (Array.isArray(node)) {\n node.forEach((child) => { return collectTableDefinitions(child, tables); });\n return tables;\n }\n\n if (!isRecord(node)) {\n return tables;\n }\n\n if (node.$field === 'table' && node.name) {\n const tableName = String(node.name);\n const tableLabel = String(node.label || node.name);\n const columns: Record<string, string> = {};\n\n if (Array.isArray(node.columns)) {\n node.columns.forEach((column) => {\n if (!column?.name) {\n return;\n }\n\n columns[String(column.name)] = String(column.label || column.name);\n });\n }\n\n tables[tableName] = {\n name: tableName,\n label: tableLabel,\n columns,\n };\n }\n\n if (node.children) {\n collectTableDefinitions(node.children, tables);\n }\n\n return tables;\n};\n\nconst expandWildcardPaths = (values: Record<string, unknown>, path: string) => {\n if (!path.includes('*')) {\n return [path];\n }\n\n const parts = path.split('.');\n const results: string[] = [];\n\n const walk = (current: unknown, index: number, acc: string[]) => {\n if (index >= parts.length) {\n results.push(acc.join('.'));\n return;\n }\n\n const part = parts[index];\n if (part === '*') {\n if (Array.isArray(current)) {\n current.forEach((item, idx) => {\n walk(item, index + 1, [...acc, String(idx)]);\n });\n }\n return;\n }\n\n if (isRecord(current) && part in current) {\n walk(current[part], index + 1, [...acc, part]);\n return;\n }\n\n // Allow missing leaf keys so required rules still validate.\n walk(undefined, index + 1, [...acc, part]);\n };\n\n walk(values, 0, []);\n return results;\n};\n\nconst getValueAtPath = (values: Record<string, unknown>, path: string) => {\n if (!path) {\n return undefined;\n }\n\n return path.split('.').reduce<unknown>((current, segment) => {\n if (current === undefined || current === null) {\n return undefined;\n }\n\n const key = Array.isArray(current) ? Number(segment) : segment;\n return current[key as keyof typeof current];\n }, values);\n};\n\nconst emailRegex = /(^$|^(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$)/;\nconst variableRegex = /({.*?})/;\n\nconst buildFieldSchema = (field: SchemaField, rules: RuleToken[]) => {\n const label = String(field.label || field.name || '');\n const isRequired = rules.some((rule) => { return isRequiredRuleName(rule.name); });\n\n const actions = [];\n\n rules.forEach((rule) => {\n const ruleName = rule.name;\n const { args } = rule;\n\n const maybeSkip = (value: unknown) => {\n return !isRequired && isEmptyValue(value);\n };\n\n switch (ruleName) {\n case 'required':\n actions.push(v.check(\n (value) => { return !isEmptyValue(value); },\n translate('{attribute} cannot be blank.', { attribute: label }),\n ));\n break;\n\n case 'requiredRichText':\n actions.push(v.check(\n (value) => { return !isRichTextEmpty(value); },\n translate('{attribute} cannot be blank.', { attribute: label }),\n ));\n break;\n\n case 'email':\n actions.push(v.check(\n (value) => {\n if (maybeSkip(value)) {\n return true;\n }\n return emailRegex.test(String(value));\n },\n translate('{attribute} must be a valid email address.', { attribute: label }),\n ));\n break;\n\n case 'emailOrVariable':\n actions.push(v.check(\n (value) => {\n if (maybeSkip(value)) {\n return true;\n }\n const text = String(value);\n return variableRegex.test(text) || emailRegex.test(text);\n },\n translate('{attribute} must be a valid email address or variable.', { attribute: label }),\n ));\n break;\n\n case 'min': {\n const min = Number(args[0]);\n actions.push(v.check(\n (value) => {\n if (maybeSkip(value)) {\n return true;\n }\n const size = getValueSize(value);\n return Number.isFinite(size) ? size >= min : false;\n },\n translate('{attribute} must be at least {min}.', { attribute: label, min: String(args[0]) }),\n ));\n break;\n }\n\n case 'max': {\n const max = Number(args[0]);\n actions.push(v.check(\n (value) => {\n if (maybeSkip(value)) {\n return true;\n }\n const size = getValueSize(value);\n return Number.isFinite(size) ? size <= max : false;\n },\n translate('{attribute} must be at most {max}.', { attribute: label, max: String(args[0]) }),\n ));\n break;\n }\n\n default:\n break;\n }\n });\n\n return v.pipe(v.any(), ...actions);\n};\n\n// Run Valibot and return TanStack Form–friendly error shape.\nexport function validateFormValues(\n schema: unknown,\n values: Record<string, unknown>,\n): { fields: Record<string, string[]> } | undefined {\n const normalizedValues = values && typeof values === 'object' ? values : {};\n const fields = collectFields(schema as SchemaValue);\n\n if (!fields.length) {\n return undefined;\n }\n\n const fieldErrors: Record<string, string[]> = {};\n\n fields.forEach((field) => {\n if (!field?.name) {\n return;\n }\n\n const rules = parseRules(field);\n if (!rules.length) {\n return;\n }\n\n const validator = buildFieldSchema(field, rules);\n const paths = expandWildcardPaths(normalizedValues, field.name);\n\n paths.forEach((path) => {\n const value = getValueAtPath(normalizedValues, path);\n const result = v.safeParse(validator, value);\n\n if (result.success) {\n return;\n }\n\n const message = (result.issues || [])\n .map((issue) => { return issue.message; })\n .filter(Boolean)[0];\n\n if (message) {\n fieldErrors[path] = [message];\n }\n });\n });\n\n // Aggregate table row errors up to the parent table field.\n const tableDefinitions = collectTableDefinitions(schema);\n const formatColumnMessage = (message: string, label: string) => {\n const trimmed = String(message || '').trim();\n if (!trimmed) {\n return label;\n }\n\n const match = trimmed.match(/^.+?(\\s+(?:cannot|must|is)\\b.*)$/i);\n if (match) {\n return `${label}${match[1]}`;\n }\n\n return `${label}: ${trimmed}`;\n };\n\n Object.entries(tableDefinitions).forEach(([tableName, definition]) => {\n const nestedKeys = Object.keys(fieldErrors).filter((key) => {\n return key.startsWith(`${tableName}.`);\n });\n if (nestedKeys.length === 0) {\n return;\n }\n\n const columnErrors: Record<string, string[]> = {};\n nestedKeys.forEach((key) => {\n const matches = key.match(new RegExp(`^${tableName}\\\\.\\\\d+\\\\.(.+)$`));\n const columnName = matches?.[1];\n if (!columnName) {\n return;\n }\n\n const messages = fieldErrors[key] || [];\n if (!messages.length) {\n return;\n }\n\n if (!columnErrors[columnName]) {\n columnErrors[columnName] = [];\n }\n\n columnErrors[columnName].push(...messages);\n });\n\n const columnMessages = Object.entries(columnErrors).flatMap(([columnName, messages]) => {\n if (!messages.length) {\n return [];\n }\n\n const columnLabel = definition.columns[columnName] || columnName;\n const label = `${definition.label} - ${columnLabel}`;\n const uniqueMessages = Array.from(new Set(messages));\n const firstMessage = uniqueMessages[0];\n return firstMessage ? [formatColumnMessage(firstMessage, label)] : [];\n });\n\n if (!columnMessages.length) {\n return;\n }\n\n const merged = new Set([...(fieldErrors[tableName] || []), ...columnMessages]);\n fieldErrors[tableName] = Array.from(merged);\n });\n\n return Object.keys(fieldErrors).length > 0 ? { fields: fieldErrors } : undefined;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verbb/plugin-kit-react",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -154,7 +154,7 @@
154
154
  "@tiptap/react": "^3.22.4",
155
155
  "@types/prismjs": "^1.26.6",
156
156
  "@uiw/react-codemirror": "^4.25.10",
157
- "@verbb/plugin-kit": "1.0.9",
157
+ "@verbb/plugin-kit": "1.0.10",
158
158
  "class-variance-authority": "^0.7.1",
159
159
  "clsx": "^2.1.1",
160
160
  "cmdk": "^1.1.1",