@dou-ui/form-builder 0.0.0-stage → 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/builder/canvas.js +695 -0
  4. package/dist/builder/canvas.js.map +1 -0
  5. package/dist/builder/completion.js +49 -0
  6. package/dist/builder/completion.js.map +1 -0
  7. package/dist/builder/condition-editor.js +6 -0
  8. package/dist/builder/condition-editor.js.map +1 -0
  9. package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js +410 -0
  10. package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
  11. package/dist/builder/condition.js +159 -0
  12. package/dist/builder/condition.js.map +1 -0
  13. package/dist/builder/context.js +477 -0
  14. package/dist/builder/context.js.map +1 -0
  15. package/dist/builder/core/commands.js +373 -0
  16. package/dist/builder/core/commands.js.map +1 -0
  17. package/dist/builder/core/history.js +76 -0
  18. package/dist/builder/core/history.js.map +1 -0
  19. package/dist/builder/core/transaction.js +298 -0
  20. package/dist/builder/core/transaction.js.map +1 -0
  21. package/dist/builder/drag.js +466 -0
  22. package/dist/builder/drag.js.map +1 -0
  23. package/dist/builder/expression-box.js +19 -0
  24. package/dist/builder/expression-box.js.map +1 -0
  25. package/dist/builder/expression-input.js +6 -0
  26. package/dist/builder/expression-input.js.map +1 -0
  27. package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js +117 -0
  28. package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
  29. package/dist/builder/extension.js +47 -0
  30. package/dist/builder/extension.js.map +1 -0
  31. package/dist/builder/form-builder.js +6 -0
  32. package/dist/builder/form-builder.js.map +1 -0
  33. package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js +450 -0
  34. package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js.map +1 -0
  35. package/dist/builder/index.js +22 -0
  36. package/dist/builder/index.js.map +1 -0
  37. package/dist/builder/inspector.js +6 -0
  38. package/dist/builder/inspector.js.map +1 -0
  39. package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js +442 -0
  40. package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js.map +1 -0
  41. package/dist/builder/json-dialog.js +6 -0
  42. package/dist/builder/json-dialog.js.map +1 -0
  43. package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js +281 -0
  44. package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  45. package/dist/builder/locale.js +1271 -0
  46. package/dist/builder/locale.js.map +1 -0
  47. package/dist/builder/logic-fields.js +18 -0
  48. package/dist/builder/logic-fields.js.map +1 -0
  49. package/dist/builder/logic.js +332 -0
  50. package/dist/builder/logic.js.map +1 -0
  51. package/dist/builder/menu.js +92 -0
  52. package/dist/builder/menu.js.map +1 -0
  53. package/dist/builder/outline-row.js +6 -0
  54. package/dist/builder/outline-row.js.map +1 -0
  55. package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js +88 -0
  56. package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js.map +1 -0
  57. package/dist/builder/outline.js +6 -0
  58. package/dist/builder/outline.js.map +1 -0
  59. package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js +111 -0
  60. package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  61. package/dist/builder/palette.js +6 -0
  62. package/dist/builder/palette.js.map +1 -0
  63. package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js +96 -0
  64. package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js.map +1 -0
  65. package/dist/builder/preview.js +6 -0
  66. package/dist/builder/preview.js.map +1 -0
  67. package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js +111 -0
  68. package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js.map +1 -0
  69. package/dist/builder/settings-binding.js +57 -0
  70. package/dist/builder/settings-binding.js.map +1 -0
  71. package/dist/builder/settings.js +487 -0
  72. package/dist/builder/settings.js.map +1 -0
  73. package/dist/builder/span-field.js +104 -0
  74. package/dist/builder/span-field.js.map +1 -0
  75. package/dist/code/expression-input.js +6 -0
  76. package/dist/code/expression-input.js.map +1 -0
  77. package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js +88 -0
  78. package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
  79. package/dist/code/extension.js +202 -0
  80. package/dist/code/extension.js.map +1 -0
  81. package/dist/code/index.js +19 -0
  82. package/dist/code/index.js.map +1 -0
  83. package/dist/code/language.js +43 -0
  84. package/dist/code/language.js.map +1 -0
  85. package/dist/collaboration/index.js +382 -0
  86. package/dist/collaboration/index.js.map +1 -0
  87. package/dist/collaboration/order.js +88 -0
  88. package/dist/collaboration/order.js.map +1 -0
  89. package/dist/core/check.js +314 -0
  90. package/dist/core/check.js.map +1 -0
  91. package/dist/core/document.js +112 -0
  92. package/dist/core/document.js.map +1 -0
  93. package/dist/core/expression.js +854 -0
  94. package/dist/core/expression.js.map +1 -0
  95. package/dist/core/formulas.js +242 -0
  96. package/dist/core/formulas.js.map +1 -0
  97. package/dist/core/rules.js +83 -0
  98. package/dist/core/rules.js.map +1 -0
  99. package/dist/core/values.js +80 -0
  100. package/dist/core/values.js.map +1 -0
  101. package/dist/fields/builtin.js +167 -0
  102. package/dist/fields/builtin.js.map +1 -0
  103. package/dist/fields/components.js +155 -0
  104. package/dist/fields/components.js.map +1 -0
  105. package/dist/fields/define.js +44 -0
  106. package/dist/fields/define.js.map +1 -0
  107. package/dist/fields/format.js +125 -0
  108. package/dist/fields/format.js.map +1 -0
  109. package/dist/fields/options.js +54 -0
  110. package/dist/fields/options.js.map +1 -0
  111. package/dist/index.js +20 -0
  112. package/dist/locale.js +161 -0
  113. package/dist/locale.js.map +1 -0
  114. package/dist/renderer/containers.js +430 -0
  115. package/dist/renderer/containers.js.map +1 -0
  116. package/dist/renderer/context.js +21 -0
  117. package/dist/renderer/context.js.map +1 -0
  118. package/dist/renderer/form-renderer.js +6 -0
  119. package/dist/renderer/form-renderer.js.map +1 -0
  120. package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js +272 -0
  121. package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  122. package/dist/renderer/index.js +19 -0
  123. package/dist/renderer/index.js.map +1 -0
  124. package/dist/renderer/node-view.js +385 -0
  125. package/dist/renderer/node-view.js.map +1 -0
  126. package/dist/style.css +1 -0
  127. package/dist/style.d.ts +1 -0
  128. package/dist/style.js +27 -0
  129. package/dist/types/builder/canvas.d.ts +5 -0
  130. package/dist/types/builder/completion.d.ts +35 -0
  131. package/dist/types/builder/condition-editor.vue.d.ts +17 -0
  132. package/dist/types/builder/condition.d.ts +37 -0
  133. package/dist/types/builder/context.d.ts +149 -0
  134. package/dist/types/builder/core/commands.d.ts +74 -0
  135. package/dist/types/builder/core/history.d.ts +23 -0
  136. package/dist/types/builder/core/transaction.d.ts +108 -0
  137. package/dist/types/builder/drag.d.ts +52 -0
  138. package/dist/types/builder/expression-box.d.ts +8 -0
  139. package/dist/types/builder/expression-input.vue.d.ts +29 -0
  140. package/dist/types/builder/extension.d.ts +149 -0
  141. package/dist/types/builder/form-builder.vue.d.ts +24 -0
  142. package/dist/types/builder/index.d.ts +76 -0
  143. package/dist/types/builder/inspector.vue.d.ts +3 -0
  144. package/dist/types/builder/json-dialog.vue.d.ts +10 -0
  145. package/dist/types/builder/locale.d.ts +195 -0
  146. package/dist/types/builder/logic-fields.d.ts +2 -0
  147. package/dist/types/builder/logic.d.ts +57 -0
  148. package/dist/types/builder/menu.d.ts +23 -0
  149. package/dist/types/builder/outline-row.vue.d.ts +19 -0
  150. package/dist/types/builder/outline.vue.d.ts +3 -0
  151. package/dist/types/builder/palette.vue.d.ts +3 -0
  152. package/dist/types/builder/preview.vue.d.ts +3 -0
  153. package/dist/types/builder/settings-binding.d.ts +23 -0
  154. package/dist/types/builder/settings.d.ts +49 -0
  155. package/dist/types/builder/span-field.d.ts +4 -0
  156. package/dist/types/builder/types.d.ts +59 -0
  157. package/dist/types/code/expression-input.vue.d.ts +23 -0
  158. package/dist/types/code/extension.d.ts +45 -0
  159. package/dist/types/code/index.d.ts +12 -0
  160. package/dist/types/code/language.d.ts +6 -0
  161. package/dist/types/collaboration/index.d.ts +64 -0
  162. package/dist/types/collaboration/order.d.ts +20 -0
  163. package/dist/types/core/check.d.ts +68 -0
  164. package/dist/types/core/document.d.ts +36 -0
  165. package/dist/types/core/expression.d.ts +175 -0
  166. package/dist/types/core/formulas.d.ts +44 -0
  167. package/dist/types/core/rules.d.ts +23 -0
  168. package/dist/types/core/types.d.ts +211 -0
  169. package/dist/types/core/values.d.ts +22 -0
  170. package/dist/types/fields/builtin.d.ts +9 -0
  171. package/dist/types/fields/components.d.ts +177 -0
  172. package/dist/types/fields/define.d.ts +93 -0
  173. package/dist/types/fields/format.d.ts +76 -0
  174. package/dist/types/fields/options.d.ts +11 -0
  175. package/dist/types/index.d.ts +3 -0
  176. package/dist/types/locale.d.ts +45 -0
  177. package/dist/types/renderer/containers.d.ts +20 -0
  178. package/dist/types/renderer/context.d.ts +186 -0
  179. package/dist/types/renderer/form-renderer.vue.d.ts +25 -0
  180. package/dist/types/renderer/index.d.ts +81 -0
  181. package/dist/types/renderer/node-view.d.ts +56 -0
  182. package/package.json +88 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.js","names":[],"sources":["../../src/builder/locale.ts"],"sourcesContent":["import { useLocale } from 'dou-ui'\nimport { computed, toValue } from 'vue'\nimport type { MaybeRefOrGetter } from 'vue'\n\n/** The texts of the builder: its panels, actions, announcements and the settings of the built-in types. */\nexport interface FormBuilderMessages {\n /** Names of the built-in field types and of the containers, by type. */\n types: Record<string, string>\n /** Names of the palette's groups, by the `group` of a field type. */\n groups: Record<string, string>\n palette: {\n /** The palette's search box, read out and shown when empty. */\n search: string\n /** Shown when no type matches the search. */\n empty: string\n /** Read out on a type: `{label}`. */\n add: string\n }\n outline: { label: string; expand: string; collapse: string }\n canvas: {\n /** Names the canvas for screen readers. */\n label: string\n /** Shown on an empty form or container. */\n empty: string\n /** Shown on an empty form or container of a `readonly` builder. */\n readonlyEmpty: string\n }\n /** The tabs of the side panel. */\n /** `side` names the pane, or the button that opens it, holding the fields and the outline. */\n panels: { side: string; fields: string; outline: string; settings: string }\n actions: {\n parent: string\n up: string\n down: string\n duplicate: string\n remove: string\n /** The button that holds the other actions when a node is too narrow to show them. */\n more: string\n /** On phones: taps add nodes to the selection instead of replacing it. */\n selectMany: string\n wrap: string\n addPage: string\n undo: string\n redo: string\n }\n inspector: {\n /** Heading when nothing is selected: the form's own settings. */\n form: string\n /** Heading of several selected nodes: `{count}`. */\n multiple: string\n /** Heading over the settings of the field type. */\n type: string\n /** Headings over the checks, and over when the node shows, is disabled or required. */\n rules: string\n logic: string\n }\n /** Read out after a change. */\n announce: {\n inserted: string\n removed: string\n duplicated: string\n moved: string\n /** After a drag or `moveTo`: `{where}` is the container, `{count}` how many nodes moved. */\n movedTo: string\n movedManyTo: string\n wrapped: string\n undone: string\n redone: string\n /** After the whole form was replaced, e.g. by imported JSON. */\n replaced: string\n }\n /** The condition editor: rows of \"field, how, value\". */\n condition: {\n /** A line of the canvas mark's tooltip: a setting and its expression. `{label}`, `{text}`. */\n summary: string\n /** Names a row for screen readers, followed by its number. */\n row: string\n field: string\n operator: string\n value: string\n add: string\n remove: string\n /** How the rows combine. */\n all: string\n any: string\n /** Switch to writing the expression, and back. */\n toText: string\n toRows: string\n /** Why the expression cannot be shown as rows. */\n notRows: string\n yes: string\n no: string\n /** Groups of the field list inside a list: the item's fields and the form's. */\n itemGroup: string\n formGroup: string\n operators: Record<string, string>\n /** Names of the comparisons of dates, where they differ. */\n dateOperators: Record<string, string>\n }\n /** Expression text: what the completions mean, and the problems by their code. `{text}` is the text at fault. */\n expression: {\n values: string\n item: string\n value: string\n problems: Record<string, string>\n /** What the built-in functions take and do, for hover text and parameter hints. */\n functions: Record<string, { signature: string; info: string }>\n /** Shown beside `true`, `false`, `null` and `in` in completions. */\n keyword: string\n }\n preview: {\n /** The button that shows the preview. */\n toggle: string\n label: string\n device: string\n devices: { desktop: string; tablet: string; phone: string }\n submit: string\n reset: string\n /** Over the values a submit would send. */\n passed: string\n }\n /** The JSON of the form. */\n json: {\n title: string\n /** Lays the text out again, two spaces a level. */\n format: string\n file: string\n download: string\n copy: string\n copied: string\n cancel: string\n apply: string\n /** Closes the dialog of a `readonly` builder, which cannot apply anything. */\n close: string\n syntax: string\n /** `{line}`, `{column}`. */\n syntaxAt: string\n fine: string\n /** `{count}` problems not listed. */\n more: string\n /** A value of the wrong kind, by what it should be, and `required` for one that is missing. */\n shape: Record<string, string>\n /** The problems of `checkDocument`, by code. */\n problems: Record<string, string>\n }\n /** Moving nodes by dragging, or with the keyboard after `Space`. `{index}` counts from 1. */\n drag: {\n /** Read out before the first place, so it ends with its own stop. */\n picked: string\n place: string\n /** The top of the form, as `{where}` in `place`. */\n top: string\n cancelled: string\n /** The handle on a node's edge that changes its width. */\n resize: string\n }\n /** What new nodes are called. `{index}` counts from 1. */\n created: {\n option: string\n page: string\n step: string\n text: string\n alert: string\n }\n /** Labels of the settings, by key. */\n settings: Record<string, string>\n /** Choices of the settings, by setting and value. */\n choices: Record<string, Record<string, string>>\n errors: {\n /** A field holding a value needs a name. */\n name: string\n /** `{text}`: the name. */\n taken: string\n }\n}\n\nconst zhCN: FormBuilderMessages = {\n types: {\n input: '单行文本',\n textarea: '多行文本',\n 'input-number': '数字',\n select: '下拉选择',\n 'radio-group': '单选',\n 'checkbox-group': '多选',\n checkbox: '勾选框',\n switch: '开关',\n 'segmented-control': '分段选择',\n slider: '滑块',\n rate: '评分',\n 'date-picker': '日期',\n 'time-picker': '时间',\n 'color-picker': '颜色',\n cascader: '级联选择',\n 'tree-select': '树形选择',\n 'input-tag': '标签输入',\n 'input-otp': '验证码',\n upload: '上传',\n text: '文字',\n divider: '分割线',\n alert: '提示',\n section: '分组',\n tabs: '标签页',\n steps: '分步',\n page: '页面',\n list: '列表',\n },\n groups: { input: '输入', choice: '选择', more: '更多', display: '展示', layout: '布局' },\n palette: { search: '搜索字段', empty: '没有匹配的字段', add: '添加{label}' },\n outline: { label: '表单结构', expand: '展开', collapse: '收起' },\n canvas: { label: '表单画布', empty: '点击字段添加到这里', readonlyEmpty: '这里还没有内容' },\n panels: { side: '字段与结构', fields: '字段', outline: '结构', settings: '设置' },\n actions: {\n parent: '选中上一级',\n up: '上移',\n down: '下移',\n duplicate: '复制',\n remove: '删除',\n more: '更多操作',\n selectMany: '多选',\n wrap: '放进分组',\n addPage: '添加页面',\n undo: '撤销',\n redo: '重做',\n },\n inspector: {\n form: '表单',\n multiple: '已选中 {count} 项',\n type: '组件设置',\n rules: '校验',\n logic: '联动',\n },\n announce: {\n inserted: '已添加{label}',\n removed: '已删除 {count} 项',\n duplicated: '已复制 {count} 项',\n moved: '已移到第 {index} 位',\n movedTo: '已移到{where}的第 {index} 位',\n movedManyTo: '已把 {count} 个节点移到{where}的第 {index} 位',\n wrapped: '已放进分组',\n undone: '已撤销',\n redone: '已重做',\n replaced: '已换成导入的表单',\n },\n condition: {\n summary: '{label}:{text}',\n row: '条件',\n field: '字段',\n operator: '比较方式',\n value: '值',\n add: '添加条件',\n remove: '删除这条条件',\n all: '满足全部条件',\n any: '满足任一条件',\n toText: '写成表达式',\n toRows: '改用条件',\n notRows: '这个表达式不能拆成条件',\n yes: '是',\n no: '否',\n itemGroup: '列表这一项',\n formGroup: '表单',\n operators: {\n eq: '等于',\n ne: '不等于',\n gt: '大于',\n ge: '大于等于',\n lt: '小于',\n le: '小于等于',\n in: '是其中之一',\n contains: '包含',\n empty: '为空',\n filled: '不为空',\n },\n dateOperators: { gt: '晚于', ge: '不早于', lt: '早于', le: '不晚于' },\n },\n expression: {\n values: '表单的值',\n item: '列表这一项的值',\n value: '这个字段的值',\n functions: {\n len: { signature: 'len(value)', info: '文字的字数、列表的项数' },\n empty: { signature: 'empty(value)', info: '是否为空:空文字、空列表、没有值' },\n number: { signature: 'number(value)', info: '转成数字;没有值时得到 null' },\n sum: { signature: 'sum(...numbers)', info: '求和,可以传列表' },\n min: { signature: 'min(...numbers)', info: '最小的数' },\n max: { signature: 'max(...numbers)', info: '最大的数' },\n round: { signature: 'round(value, digits?)', info: '四舍五入到 digits 位小数,默认取整' },\n abs: { signature: 'abs(value)', info: '绝对值' },\n today: { signature: 'today(offset?)', info: '今天的日期(YYYY-MM-DD),offset 是往后的天数' },\n days: { signature: 'days(from, to)', info: '两个日期相差的天数' },\n contains: { signature: 'contains(collection, item)', info: '文字或列表里是否有 item' },\n },\n keyword: '关键字',\n problems: {\n 'unexpected-character': '不认识的字符“{text}”',\n 'unterminated-string': '文字缺少结尾的引号',\n 'unexpected-token': '这里不应出现“{text}”',\n 'unexpected-end': '表达式还没写完',\n 'unknown-name': '不认识的名字“{text}”,字段要写成 values.字段名',\n assignment: '比较是否相等要用 ==',\n 'too-deep': '表达式嵌套太深',\n 'too-long': '表达式太长',\n 'unknown-field': '没有字段“{text}”',\n 'unknown-function': '没有函数“{text}”',\n },\n },\n preview: {\n toggle: '预览',\n label: '表单预览',\n device: '预览宽度',\n devices: { desktop: '桌面', tablet: '平板', phone: '手机' },\n submit: '提交',\n reset: '重置',\n passed: '校验通过,会提交这些值',\n },\n json: {\n title: '表单 JSON',\n format: '格式化',\n file: '打开文件',\n download: '下载',\n copy: '复制',\n copied: '已复制',\n cancel: '取消',\n apply: '应用',\n close: '关闭',\n syntax: 'JSON 格式有误',\n syntaxAt: '第 {line} 行第 {column} 列:JSON 格式有误',\n fine: '没有发现问题',\n more: '还有 {count} 个问题',\n shape: {\n required: '缺少这一项',\n object: '应为对象',\n array: '应为数组',\n string: '应为文字',\n number: '应为数字',\n boolean: '应为 true 或 false',\n span: '应为数字,或按表单宽度分别设置的对象',\n mark: '应为 true、false 或 \"optional\"',\n },\n problems: {\n version: '不认识的版本 {text}',\n 'duplicate-id': 'id“{text}”重复',\n 'missing-name': '缺少字段名',\n 'duplicate-name': '字段名“{text}”重复',\n 'unknown-type': '没有“{text}”这种字段类型',\n 'misplaced-page': '页面只能放在标签页或分步里',\n 'not-a-page': '标签页和分步里只能放页面',\n empty: '里面还是空的',\n 'formula-cycle': '公式互相引用:{text}',\n 'unknown-validator': '没有校验函数“{text}”',\n 'check-and-validator': '同一条规则不能同时写表达式和校验函数',\n },\n },\n drag: {\n picked: '已拿起,用方向键选择位置,Enter 放下,Esc 取消。',\n place: '放到{where}的第 {index} 位',\n top: '表单最外层',\n cancelled: '已取消移动',\n resize: '拖动调整宽度',\n },\n created: {\n option: '选项 {index}',\n page: '页面 {index}',\n step: '第 {index} 步',\n text: '一段说明文字',\n alert: '提示',\n },\n settings: {\n name: '字段名',\n nameHelp: '值写在表单值的这个路径下,如 contact.phone',\n itemName: '字段名',\n itemNameHelp: '值写在列表每一项的这个键下',\n label: '标签',\n help: '提示文字',\n default: '默认值',\n required: '必填',\n span: '宽度',\n spanResponsive: '按表单宽度分别设置',\n title: '标题',\n description: '说明',\n bordered: '显示边框',\n columns: '栅格列数',\n minItems: '最少项数',\n maxItems: '最多项数',\n sortable: '可以拖动排序',\n addText: '添加按钮文字',\n layout: '标签位置',\n labelAlign: '标签对齐',\n labelWidth: '标签宽度',\n size: '尺寸',\n requiredMark: '必填标记',\n placeholder: '占位文字',\n clearable: '可以清空',\n showCount: '显示字数',\n maxlength: '最多字数',\n rows: '行数',\n autosize: '随内容增高',\n min: '最小值',\n max: '最大值',\n step: '步长',\n precision: '小数位数',\n controls: '显示加减按钮',\n options: '选项',\n optionLabel: '文字',\n optionValue: '值',\n multiple: '可以多选',\n filterable: '可以搜索',\n direction: '排列',\n text: '旁边的文字',\n range: '选择一个范围',\n allowHalf: '可以选半星',\n count: '星星数',\n dateType: '选择的单位',\n showAlpha: '可以调透明度',\n maxTags: '最多标签数',\n length: '位数',\n mask: '隐藏输入的内容',\n accept: '接受的文件类型',\n maxCount: '最多文件数',\n dropzone: '显示拖放区域',\n content: '内容',\n variant: '样式',\n dashed: '虚线',\n tone: '语气',\n visibleWhen: '显示条件',\n visibleWhenHelp: '满足条件时才显示;不设置时总是显示',\n disabledWhen: '禁用条件',\n disabledWhenHelp: '满足条件时不能填写',\n requiredWhen: '必填条件',\n requiredWhenHelp: '满足条件时必填,设置后代替上面的“必填”',\n formula: '计算公式',\n formulaHelp: '值由公式算出,不能手动填写',\n addRule: '添加规则',\n ruleKind: '规则',\n ruleType: '格式',\n ruleMin: '最小',\n ruleMax: '最大',\n ruleRangeHelp: '文字按字数,多选和列表按个数,数字按大小',\n rulePattern: '正则表达式',\n ruleFlags: '标志',\n ruleCheck: '表达式',\n ruleCheckHelp: 'value 是这个字段的值,values 是整个表单;结果为真时通过',\n ruleValidator: '校验函数',\n ruleValidatorHelp: '由使用表单的代码通过 validators 提供,可以请求接口',\n ruleMessage: '出错时的提示',\n ruleTrigger: '检查时机',\n },\n choices: {\n layout: { vertical: '在上方', horizontal: '在左侧', inline: '排成一行' },\n labelAlign: { start: '靠左', end: '靠右' },\n size: { sm: '小', md: '中', lg: '大' },\n requiredMark: { true: '星号', optional: '标注选填', false: '不标注' },\n direction: { horizontal: '横向', vertical: '纵向' },\n dateType: {\n date: '日',\n week: '周',\n month: '月',\n quarter: '季度',\n year: '年',\n datetime: '日期和时间',\n },\n variant: { title: '标题', body: '正文', caption: '小字' },\n ruleKind: {\n type: '格式',\n range: '范围',\n pattern: '正则',\n check: '表达式',\n validator: '校验函数',\n },\n ruleType: { email: '邮箱', url: '网址', number: '数字', integer: '整数', string: '文字' },\n ruleTrigger: { auto: '默认', change: '输入时', blur: '离开时' },\n tone: { neutral: '中性', primary: '强调', success: '成功', warning: '警告', danger: '危险' },\n breakpoint: { base: '最窄', sm: '≥ 480', md: '≥ 640', lg: '≥ 800', xl: '≥ 960' },\n },\n errors: { name: '请填写字段名', taken: '字段名“{text}”已经用过了' },\n}\n\nconst zhTW: FormBuilderMessages = {\n types: {\n input: '單行文字',\n textarea: '多行文字',\n 'input-number': '數字',\n select: '下拉選擇',\n 'radio-group': '單選',\n 'checkbox-group': '多選',\n checkbox: '勾選框',\n switch: '開關',\n 'segmented-control': '分段選擇',\n slider: '滑桿',\n rate: '評分',\n 'date-picker': '日期',\n 'time-picker': '時間',\n 'color-picker': '顏色',\n cascader: '級聯選擇',\n 'tree-select': '樹狀選擇',\n 'input-tag': '標籤輸入',\n 'input-otp': '驗證碼',\n upload: '上傳',\n text: '文字',\n divider: '分隔線',\n alert: '提示',\n section: '分組',\n tabs: '分頁',\n steps: '分步',\n page: '頁面',\n list: '清單',\n },\n groups: { input: '輸入', choice: '選擇', more: '更多', display: '展示', layout: '版面' },\n palette: { search: '搜尋欄位', empty: '沒有符合的欄位', add: '新增{label}' },\n outline: { label: '表單結構', expand: '展開', collapse: '收合' },\n canvas: { label: '表單畫布', empty: '點選欄位新增到這裡', readonlyEmpty: '這裡還沒有內容' },\n panels: { side: '欄位與結構', fields: '欄位', outline: '結構', settings: '設定' },\n actions: {\n parent: '選取上一層',\n up: '上移',\n down: '下移',\n duplicate: '複製',\n remove: '刪除',\n more: '更多操作',\n selectMany: '多選',\n wrap: '放進分組',\n addPage: '新增頁面',\n undo: '復原',\n redo: '重做',\n },\n inspector: {\n form: '表單',\n multiple: '已選取 {count} 項',\n type: '元件設定',\n rules: '驗證',\n logic: '連動',\n },\n announce: {\n inserted: '已新增{label}',\n removed: '已刪除 {count} 項',\n duplicated: '已複製 {count} 項',\n moved: '已移到第 {index} 位',\n movedTo: '已移到{where}的第 {index} 位',\n movedManyTo: '已把 {count} 个节点移到{where}的第 {index} 位',\n wrapped: '已放進分組',\n undone: '已復原',\n redone: '已重做',\n replaced: '已換成匯入的表單',\n },\n condition: {\n summary: '{label}:{text}',\n row: '條件',\n field: '欄位',\n operator: '比較方式',\n value: '值',\n add: '新增條件',\n remove: '刪除這條條件',\n all: '符合全部條件',\n any: '符合任一條件',\n toText: '寫成運算式',\n toRows: '改用條件',\n notRows: '這個運算式無法拆成條件',\n yes: '是',\n no: '否',\n itemGroup: '清單這一項',\n formGroup: '表單',\n operators: {\n eq: '等於',\n ne: '不等於',\n gt: '大於',\n ge: '大於等於',\n lt: '小於',\n le: '小於等於',\n in: '是其中之一',\n contains: '包含',\n empty: '為空',\n filled: '不為空',\n },\n dateOperators: { gt: '晚於', ge: '不早於', lt: '早於', le: '不晚於' },\n },\n expression: {\n values: '表單的值',\n item: '清單這一項的值',\n value: '這個欄位的值',\n functions: {\n len: { signature: 'len(value)', info: '文字的字數、清單的項數' },\n empty: { signature: 'empty(value)', info: '是否為空:空文字、空清單、沒有值' },\n number: { signature: 'number(value)', info: '轉成數字;沒有值時得到 null' },\n sum: { signature: 'sum(...numbers)', info: '加總,可以傳入清單' },\n min: { signature: 'min(...numbers)', info: '最小的數' },\n max: { signature: 'max(...numbers)', info: '最大的數' },\n round: { signature: 'round(value, digits?)', info: '四捨五入到 digits 位小數,預設取整數' },\n abs: { signature: 'abs(value)', info: '絕對值' },\n today: { signature: 'today(offset?)', info: '今天的日期(YYYY-MM-DD),offset 是往後的天數' },\n days: { signature: 'days(from, to)', info: '兩個日期相差的天數' },\n contains: { signature: 'contains(collection, item)', info: '文字或清單裡是否有 item' },\n },\n keyword: '關鍵字',\n problems: {\n 'unexpected-character': '無法辨識的字元「{text}」',\n 'unterminated-string': '文字缺少結尾的引號',\n 'unexpected-token': '這裡不應出現「{text}」',\n 'unexpected-end': '運算式還沒寫完',\n 'unknown-name': '無法辨識的名稱「{text}」,欄位要寫成 values.欄位名稱',\n assignment: '比較是否相等要用 ==',\n 'too-deep': '運算式巢狀太深',\n 'too-long': '運算式太長',\n 'unknown-field': '沒有欄位「{text}」',\n 'unknown-function': '沒有函式「{text}」',\n },\n },\n preview: {\n toggle: '預覽',\n label: '表單預覽',\n device: '預覽寬度',\n devices: { desktop: '桌面', tablet: '平板', phone: '手機' },\n submit: '送出',\n reset: '重設',\n passed: '驗證通過,會送出這些值',\n },\n json: {\n title: '表單 JSON',\n format: '格式化',\n file: '開啟檔案',\n download: '下載',\n copy: '複製',\n copied: '已複製',\n cancel: '取消',\n apply: '套用',\n close: '關閉',\n syntax: 'JSON 格式有誤',\n syntaxAt: '第 {line} 行第 {column} 欄:JSON 格式有誤',\n fine: '沒有發現問題',\n more: '還有 {count} 個問題',\n shape: {\n required: '缺少這一項',\n object: '應為物件',\n array: '應為陣列',\n string: '應為文字',\n number: '應為數字',\n boolean: '應為 true 或 false',\n span: '應為數字,或依表單寬度分別設定的物件',\n mark: '應為 true、false 或 \"optional\"',\n },\n problems: {\n version: '無法辨識的版本 {text}',\n 'duplicate-id': 'id「{text}」重複',\n 'missing-name': '缺少欄位名稱',\n 'duplicate-name': '欄位名稱「{text}」重複',\n 'unknown-type': '沒有「{text}」這種欄位類型',\n 'misplaced-page': '頁面只能放在分頁或步驟裡',\n 'not-a-page': '分頁和步驟裡只能放頁面',\n empty: '裡面還是空的',\n 'formula-cycle': '公式互相參照:{text}',\n 'unknown-validator': '沒有校驗函式「{text}」',\n 'check-and-validator': '同一條規則不能同時寫運算式和校驗函式',\n },\n },\n drag: {\n picked: '已拿起,用方向鍵選擇位置,Enter 放下,Esc 取消。',\n place: '放到{where}的第 {index} 位',\n top: '表單最外層',\n cancelled: '已取消移動',\n resize: '拖動調整寬度',\n },\n created: {\n option: '選項 {index}',\n page: '頁面 {index}',\n step: '第 {index} 步',\n text: '一段說明文字',\n alert: '提示',\n },\n settings: {\n name: '欄位名稱',\n nameHelp: '值寫在表單值的這個路徑下,如 contact.phone',\n itemName: '欄位名稱',\n itemNameHelp: '值寫在清單每一項的這個鍵下',\n label: '標籤',\n help: '提示文字',\n default: '預設值',\n required: '必填',\n span: '寬度',\n spanResponsive: '依表單寬度分別設定',\n title: '標題',\n description: '說明',\n bordered: '顯示邊框',\n columns: '格線欄數',\n minItems: '最少項數',\n maxItems: '最多項數',\n sortable: '可以拖曳排序',\n addText: '新增按鈕文字',\n layout: '標籤位置',\n labelAlign: '標籤對齊',\n labelWidth: '標籤寬度',\n size: '尺寸',\n requiredMark: '必填標記',\n placeholder: '提示文字',\n clearable: '可以清除',\n showCount: '顯示字數',\n maxlength: '最多字數',\n rows: '行數',\n autosize: '隨內容增高',\n min: '最小值',\n max: '最大值',\n step: '間隔',\n precision: '小數位數',\n controls: '顯示加減按鈕',\n options: '選項',\n optionLabel: '文字',\n optionValue: '值',\n multiple: '可以多選',\n filterable: '可以搜尋',\n direction: '排列',\n text: '旁邊的文字',\n range: '選擇一個範圍',\n allowHalf: '可以選半星',\n count: '星星數',\n dateType: '選擇的單位',\n showAlpha: '可以調透明度',\n maxTags: '最多標籤數',\n length: '位數',\n mask: '隱藏輸入的內容',\n accept: '接受的檔案類型',\n maxCount: '最多檔案數',\n dropzone: '顯示拖放區域',\n content: '內容',\n variant: '樣式',\n dashed: '虛線',\n tone: '語氣',\n visibleWhen: '顯示條件',\n visibleWhenHelp: '符合條件時才顯示;未設定時一律顯示',\n disabledWhen: '停用條件',\n disabledWhenHelp: '符合條件時無法填寫',\n requiredWhen: '必填條件',\n requiredWhenHelp: '符合條件時必填,設定後取代上面的「必填」',\n formula: '計算公式',\n formulaHelp: '值由公式算出,無法手動填寫',\n addRule: '新增規則',\n ruleKind: '規則',\n ruleType: '格式',\n ruleMin: '最小',\n ruleMax: '最大',\n ruleRangeHelp: '文字依字數,多選和清單依個數,數字依大小',\n rulePattern: '正規表示式',\n ruleFlags: '旗標',\n ruleCheck: '運算式',\n ruleCheckHelp: 'value 是這個欄位的值,values 是整個表單;結果為真時通過',\n ruleValidator: '校驗函式',\n ruleValidatorHelp: '由使用表單的程式碼透過 validators 提供,可以請求介面',\n ruleMessage: '出錯時的提示',\n ruleTrigger: '檢查時機',\n },\n choices: {\n layout: { vertical: '在上方', horizontal: '在左側', inline: '排成一行' },\n labelAlign: { start: '靠左', end: '靠右' },\n size: { sm: '小', md: '中', lg: '大' },\n requiredMark: { true: '星號', optional: '標註選填', false: '不標註' },\n direction: { horizontal: '橫向', vertical: '縱向' },\n dateType: {\n date: '日',\n week: '週',\n month: '月',\n quarter: '季',\n year: '年',\n datetime: '日期和時間',\n },\n variant: { title: '標題', body: '內文', caption: '小字' },\n ruleKind: {\n type: '格式',\n range: '範圍',\n pattern: '正規',\n check: '運算式',\n validator: '校驗函式',\n },\n ruleType: { email: '電子郵件', url: '網址', number: '數字', integer: '整數', string: '文字' },\n ruleTrigger: { auto: '預設', change: '輸入時', blur: '離開時' },\n tone: { neutral: '中性', primary: '強調', success: '成功', warning: '警告', danger: '危險' },\n breakpoint: { base: '最窄', sm: '≥ 480', md: '≥ 640', lg: '≥ 800', xl: '≥ 960' },\n },\n errors: { name: '請填寫欄位名稱', taken: '欄位名稱「{text}」已經用過了' },\n}\n\nconst en: FormBuilderMessages = {\n types: {\n input: 'Short text',\n textarea: 'Long text',\n 'input-number': 'Number',\n select: 'Select',\n 'radio-group': 'Single choice',\n 'checkbox-group': 'Multiple choice',\n checkbox: 'Checkbox',\n switch: 'Switch',\n 'segmented-control': 'Segmented',\n slider: 'Slider',\n rate: 'Rating',\n 'date-picker': 'Date',\n 'time-picker': 'Time',\n 'color-picker': 'Color',\n cascader: 'Cascader',\n 'tree-select': 'Tree select',\n 'input-tag': 'Tags',\n 'input-otp': 'Code',\n upload: 'Upload',\n text: 'Text',\n divider: 'Divider',\n alert: 'Alert',\n section: 'Section',\n tabs: 'Tabs',\n steps: 'Steps',\n page: 'Page',\n list: 'List',\n },\n groups: { input: 'Input', choice: 'Choice', more: 'More', display: 'Display', layout: 'Layout' },\n palette: { search: 'Search fields', empty: 'No field matches', add: 'Add {label}' },\n outline: { label: 'Form outline', expand: 'Expand', collapse: 'Collapse' },\n canvas: {\n label: 'Form canvas',\n empty: 'Click a field to add it here',\n readonlyEmpty: 'There is nothing in here yet',\n },\n panels: {\n side: 'Fields and outline',\n fields: 'Fields',\n outline: 'Outline',\n settings: 'Settings',\n },\n actions: {\n parent: 'Select parent',\n up: 'Move up',\n down: 'Move down',\n duplicate: 'Duplicate',\n remove: 'Delete',\n more: 'More actions',\n selectMany: 'Select several',\n wrap: 'Put in a section',\n addPage: 'Add page',\n undo: 'Undo',\n redo: 'Redo',\n },\n inspector: {\n form: 'Form',\n multiple: '{count} selected',\n type: 'Component',\n rules: 'Checks',\n logic: 'Logic',\n },\n announce: {\n inserted: '{label} added',\n removed: '{count} deleted',\n duplicated: '{count} duplicated',\n moved: 'Moved to position {index}',\n movedTo: 'Moved to {where}, position {index}',\n movedManyTo: 'Moved {count} nodes to {where}, position {index}',\n wrapped: 'Put in a section',\n undone: 'Undone',\n redone: 'Redone',\n replaced: 'Replaced with the imported form',\n },\n condition: {\n summary: '{label}: {text}',\n row: 'Condition',\n field: 'Field',\n operator: 'Comparison',\n value: 'Value',\n add: 'Add a condition',\n remove: 'Remove this condition',\n all: 'All of them',\n any: 'Any of them',\n toText: 'Write an expression',\n toRows: 'Use conditions',\n notRows: 'This expression cannot be split into conditions',\n yes: 'Yes',\n no: 'No',\n itemGroup: 'This item',\n formGroup: 'Form',\n operators: {\n eq: 'is',\n ne: 'is not',\n gt: 'is more than',\n ge: 'is at least',\n lt: 'is less than',\n le: 'is at most',\n in: 'is one of',\n contains: 'contains',\n empty: 'is empty',\n filled: 'is not empty',\n },\n dateOperators: { gt: 'is after', ge: 'is not before', lt: 'is before', le: 'is not after' },\n },\n expression: {\n values: 'The form’s values',\n item: 'This item’s values',\n value: 'This field’s value',\n functions: {\n len: { signature: 'len(value)', info: 'The length of a text or the items of a list' },\n empty: {\n signature: 'empty(value)',\n info: 'Whether it is empty: no text, no items, no value',\n },\n number: { signature: 'number(value)', info: 'As a number; null when there is no value' },\n sum: { signature: 'sum(...numbers)', info: 'The total; lists count too' },\n min: { signature: 'min(...numbers)', info: 'The smallest number' },\n max: { signature: 'max(...numbers)', info: 'The largest number' },\n round: {\n signature: 'round(value, digits?)',\n info: 'Rounded to digits decimals, whole by default',\n },\n abs: { signature: 'abs(value)', info: 'The absolute value' },\n today: { signature: 'today(offset?)', info: 'Today as YYYY-MM-DD, offset days later' },\n days: { signature: 'days(from, to)', info: 'The days from one date to another' },\n contains: {\n signature: 'contains(collection, item)',\n info: 'Whether a text or list holds item',\n },\n },\n keyword: 'Keyword',\n problems: {\n 'unexpected-character': 'Unexpected character “{text}”',\n 'unterminated-string': 'The text is missing its closing quote',\n 'unexpected-token': '“{text}” does not belong here',\n 'unexpected-end': 'The expression is not finished',\n 'unknown-name': 'Unknown name “{text}”; write fields as values.name',\n assignment: 'Use == to compare two values',\n 'too-deep': 'The expression nests too deeply',\n 'too-long': 'The expression is too long',\n 'unknown-field': 'There is no field “{text}”',\n 'unknown-function': 'There is no function “{text}”',\n },\n },\n preview: {\n toggle: 'Preview',\n label: 'Form preview',\n device: 'Preview width',\n devices: { desktop: 'Desktop', tablet: 'Tablet', phone: 'Phone' },\n submit: 'Submit',\n reset: 'Reset',\n passed: 'All checks passed. These values would be sent:',\n },\n json: {\n title: 'Form JSON',\n format: 'Format',\n file: 'Open file',\n download: 'Download',\n copy: 'Copy',\n copied: 'Copied',\n cancel: 'Cancel',\n apply: 'Apply',\n close: 'Close',\n syntax: 'The JSON is not valid',\n syntaxAt: 'Line {line}, column {column}: the JSON is not valid',\n fine: 'No problems found',\n more: '{count} more problems',\n shape: {\n required: 'Missing',\n object: 'Should be an object',\n array: 'Should be an array',\n string: 'Should be text',\n number: 'Should be a number',\n boolean: 'Should be true or false',\n span: 'Should be a number, or an object of numbers by form width',\n mark: 'Should be true, false or \"optional\"',\n },\n problems: {\n version: 'Version {text} is not known',\n 'duplicate-id': 'The id “{text}” is used twice',\n 'missing-name': 'The field has no name',\n 'duplicate-name': 'The name “{text}” is used twice',\n 'unknown-type': 'There is no field type “{text}”',\n 'misplaced-page': 'A page belongs in tabs or steps',\n 'not-a-page': 'Tabs and steps hold pages only',\n empty: 'It is empty',\n 'formula-cycle': 'The formulas read each other: {text}',\n 'unknown-validator': 'There is no validator “{text}”',\n 'check-and-validator': 'A rule cannot have both an expression and a validator',\n },\n },\n drag: {\n picked: 'Picked up. Use the arrow keys to choose a place, Enter to drop, Escape to cancel. ',\n place: 'In {where}, position {index}',\n top: 'the top of the form',\n cancelled: 'Move cancelled',\n resize: 'Drag to change the width',\n },\n created: {\n option: 'Option {index}',\n page: 'Page {index}',\n step: 'Step {index}',\n text: 'Some text',\n alert: 'Note',\n },\n settings: {\n name: 'Name',\n nameHelp: 'The path the value is written to, e.g. contact.phone',\n itemName: 'Name',\n itemNameHelp: 'The key the value is written to in each item',\n label: 'Label',\n help: 'Help',\n default: 'Default',\n required: 'Required',\n span: 'Width',\n spanResponsive: 'By form width',\n title: 'Title',\n description: 'Description',\n bordered: 'Border',\n columns: 'Grid columns',\n minItems: 'Fewest items',\n maxItems: 'Most items',\n sortable: 'Can be reordered',\n addText: 'Add button text',\n layout: 'Labels',\n labelAlign: 'Label alignment',\n labelWidth: 'Label width',\n size: 'Size',\n requiredMark: 'Required mark',\n placeholder: 'Placeholder',\n clearable: 'Clearable',\n showCount: 'Show count',\n maxlength: 'Most characters',\n rows: 'Rows',\n autosize: 'Grow with content',\n min: 'Minimum',\n max: 'Maximum',\n step: 'Step',\n precision: 'Decimals',\n controls: 'Show steppers',\n options: 'Options',\n optionLabel: 'Text',\n optionValue: 'Value',\n multiple: 'Multiple',\n filterable: 'Searchable',\n direction: 'Direction',\n text: 'Text beside it',\n range: 'Pick a range',\n allowHalf: 'Half stars',\n count: 'Stars',\n dateType: 'Unit',\n showAlpha: 'Opacity',\n maxTags: 'Most tags',\n length: 'Digits',\n mask: 'Hide what is typed',\n accept: 'File types',\n maxCount: 'Most files',\n dropzone: 'Drop zone',\n content: 'Content',\n variant: 'Style',\n dashed: 'Dashed',\n tone: 'Tone',\n visibleWhen: 'Show when',\n visibleWhenHelp: 'Shown only while this holds; always shown when left empty',\n disabledWhen: 'Disable when',\n disabledWhenHelp: 'Cannot be filled in while this holds',\n requiredWhen: 'Require when',\n requiredWhenHelp: 'Required while this holds; takes over from “Required” above',\n formula: 'Formula',\n formulaHelp: 'The value is worked out by the formula and cannot be typed',\n addRule: 'Add a rule',\n ruleKind: 'Rule',\n ruleType: 'Format',\n ruleMin: 'Least',\n ruleMax: 'Most',\n ruleRangeHelp: 'Characters for text, items for choices and lists, size for numbers',\n rulePattern: 'Regular expression',\n ruleFlags: 'Flags',\n ruleCheck: 'Expression',\n ruleCheckHelp: 'value is this field’s value and values the whole form; passes when true',\n ruleValidator: 'Validator',\n ruleValidatorHelp: 'Given in code through validators; may ask the server',\n ruleMessage: 'Message on error',\n ruleTrigger: 'Check on',\n },\n choices: {\n layout: { vertical: 'Above', horizontal: 'Beside', inline: 'In a row' },\n labelAlign: { start: 'Start', end: 'End' },\n size: { sm: 'Small', md: 'Medium', lg: 'Large' },\n requiredMark: { true: 'Asterisk', optional: 'Mark optional', false: 'None' },\n direction: { horizontal: 'Across', vertical: 'Down' },\n dateType: {\n date: 'Day',\n week: 'Week',\n month: 'Month',\n quarter: 'Quarter',\n year: 'Year',\n datetime: 'Date and time',\n },\n variant: { title: 'Heading', body: 'Body', caption: 'Caption' },\n ruleKind: {\n type: 'Format',\n range: 'Range',\n pattern: 'Pattern',\n check: 'Expression',\n validator: 'Validator',\n },\n ruleType: {\n email: 'Email',\n url: 'URL',\n number: 'Number',\n integer: 'Whole number',\n string: 'Text',\n },\n ruleTrigger: { auto: 'Default', change: 'Typing', blur: 'Leaving' },\n tone: {\n neutral: 'Neutral',\n primary: 'Primary',\n success: 'Success',\n warning: 'Warning',\n danger: 'Danger',\n },\n breakpoint: { base: 'Narrowest', sm: '≥ 480', md: '≥ 640', lg: '≥ 800', xl: '≥ 960' },\n },\n errors: { name: 'Give the field a name', taken: 'The name “{text}” is taken' },\n}\n\nexport const formBuilderLocales: Record<string, FormBuilderMessages> = {\n 'zh-CN': zhCN,\n 'zh-TW': zhTW,\n en,\n}\n\n/** Texts to change; each group is merged, so only the texts given are replaced. */\nexport type FormBuilderMessagesOverride = {\n [K in keyof FormBuilderMessages]?: K extends 'choices'\n ? Record<string, Record<string, string>>\n : Partial<FormBuilderMessages[K]>\n}\n\n/** The builder's texts, picked by the name of DouUI's current locale. */\nexport function useFormBuilderMessages(\n override?: MaybeRefOrGetter<FormBuilderMessagesOverride | undefined>,\n) {\n const { locale } = useLocale()\n return computed<FormBuilderMessages>(() => {\n const name = locale.value.name\n const base =\n formBuilderLocales[name] ??\n formBuilderLocales[name.split('-')[0]!] ??\n (name.startsWith('zh') ? zhCN : en)\n const extra = toValue(override)\n if (!extra) return base\n const merged = { ...base } as Record<string, unknown>\n for (const [key, value] of Object.entries(extra)) {\n if (!value) continue\n const own = (base as unknown as Record<string, Record<string, unknown>>)[key]!\n if (key === 'choices') {\n const choices = { ...own } as Record<string, Record<string, string>>\n for (const [setting, labels] of Object.entries(\n value as Record<string, Record<string, string>>,\n ))\n choices[setting] = { ...choices[setting], ...labels }\n merged[key] = choices\n } else merged[key] = { ...own, ...value }\n }\n return merged as unknown as FormBuilderMessages\n })\n}\n"],"mappings":";;;AAgLA,IAAM,OAA4B;CAChC,OAAO;EACL,OAAO;EACP,UAAU;EACV,gBAAgB;EAChB,QAAQ;EACR,eAAe;EACf,kBAAkB;EAClB,UAAU;EACV,QAAQ;EACR,qBAAqB;EACrB,QAAQ;EACR,MAAM;EACN,eAAe;EACf,eAAe;EACf,gBAAgB;EAChB,UAAU;EACV,eAAe;EACf,aAAa;EACb,aAAa;EACb,QAAQ;EACR,MAAM;EACN,SAAS;EACT,OAAO;EACP,SAAS;EACT,MAAM;EACN,OAAO;EACP,MAAM;EACN,MAAM;CACR;CACA,QAAQ;EAAE,OAAO;EAAM,QAAQ;EAAM,MAAM;EAAM,SAAS;EAAM,QAAQ;CAAK;CAC7E,SAAS;EAAE,QAAQ;EAAQ,OAAO;EAAW,KAAK;CAAY;CAC9D,SAAS;EAAE,OAAO;EAAQ,QAAQ;EAAM,UAAU;CAAK;CACvD,QAAQ;EAAE,OAAO;EAAQ,OAAO;EAAa,eAAe;CAAU;CACtE,QAAQ;EAAE,MAAM;EAAS,QAAQ;EAAM,SAAS;EAAM,UAAU;CAAK;CACrE,SAAS;EACP,QAAQ;EACR,IAAI;EACJ,MAAM;EACN,WAAW;EACX,QAAQ;EACR,MAAM;EACN,YAAY;EACZ,MAAM;EACN,SAAS;EACT,MAAM;EACN,MAAM;CACR;CACA,WAAW;EACT,MAAM;EACN,UAAU;EACV,MAAM;EACN,OAAO;EACP,OAAO;CACT;CACA,UAAU;EACR,UAAU;EACV,SAAS;EACT,YAAY;EACZ,OAAO;EACP,SAAS;EACT,aAAa;EACb,SAAS;EACT,QAAQ;EACR,QAAQ;EACR,UAAU;CACZ;CACA,WAAW;EACT,SAAS;EACT,KAAK;EACL,OAAO;EACP,UAAU;EACV,OAAO;EACP,KAAK;EACL,QAAQ;EACR,KAAK;EACL,KAAK;EACL,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,KAAK;EACL,IAAI;EACJ,WAAW;EACX,WAAW;EACX,WAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,UAAU;GACV,OAAO;GACP,QAAQ;EACV;EACA,eAAe;GAAE,IAAI;GAAM,IAAI;GAAO,IAAI;GAAM,IAAI;EAAM;CAC5D;CACA,YAAY;EACV,QAAQ;EACR,MAAM;EACN,OAAO;EACP,WAAW;GACT,KAAK;IAAE,WAAW;IAAc,MAAM;GAAc;GACpD,OAAO;IAAE,WAAW;IAAgB,MAAM;GAAmB;GAC7D,QAAQ;IAAE,WAAW;IAAiB,MAAM;GAAmB;GAC/D,KAAK;IAAE,WAAW;IAAmB,MAAM;GAAW;GACtD,KAAK;IAAE,WAAW;IAAmB,MAAM;GAAO;GAClD,KAAK;IAAE,WAAW;IAAmB,MAAM;GAAO;GAClD,OAAO;IAAE,WAAW;IAAyB,MAAM;GAAwB;GAC3E,KAAK;IAAE,WAAW;IAAc,MAAM;GAAM;GAC5C,OAAO;IAAE,WAAW;IAAkB,MAAM;GAAkC;GAC9E,MAAM;IAAE,WAAW;IAAkB,MAAM;GAAY;GACvD,UAAU;IAAE,WAAW;IAA8B,MAAM;GAAiB;EAC9E;EACA,SAAS;EACT,UAAU;GACR,wBAAwB;GACxB,uBAAuB;GACvB,oBAAoB;GACpB,kBAAkB;GAClB,gBAAgB;GAChB,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,iBAAiB;GACjB,oBAAoB;EACtB;CACF;CACA,SAAS;EACP,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,SAAS;GAAE,SAAS;GAAM,QAAQ;GAAM,OAAO;EAAK;EACpD,QAAQ;EACR,OAAO;EACP,QAAQ;CACV;CACA,MAAM;EACJ,OAAO;EACP,QAAQ;EACR,MAAM;EACN,UAAU;EACV,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,OAAO;EACP,QAAQ;EACR,UAAU;EACV,MAAM;EACN,MAAM;EACN,OAAO;GACL,UAAU;GACV,QAAQ;GACR,OAAO;GACP,QAAQ;GACR,QAAQ;GACR,SAAS;GACT,MAAM;GACN,MAAM;EACR;EACA,UAAU;GACR,SAAS;GACT,gBAAgB;GAChB,gBAAgB;GAChB,kBAAkB;GAClB,gBAAgB;GAChB,kBAAkB;GAClB,cAAc;GACd,OAAO;GACP,iBAAiB;GACjB,qBAAqB;GACrB,uBAAuB;EACzB;CACF;CACA,MAAM;EACJ,QAAQ;EACR,OAAO;EACP,KAAK;EACL,WAAW;EACX,QAAQ;CACV;CACA,SAAS;EACP,QAAQ;EACR,MAAM;EACN,MAAM;EACN,MAAM;EACN,OAAO;CACT;CACA,UAAU;EACR,MAAM;EACN,UAAU;EACV,UAAU;EACV,cAAc;EACd,OAAO;EACP,MAAM;EACN,SAAS;EACT,UAAU;EACV,MAAM;EACN,gBAAgB;EAChB,OAAO;EACP,aAAa;EACb,UAAU;EACV,SAAS;EACT,UAAU;EACV,UAAU;EACV,UAAU;EACV,SAAS;EACT,QAAQ;EACR,YAAY;EACZ,YAAY;EACZ,MAAM;EACN,cAAc;EACd,aAAa;EACb,WAAW;EACX,WAAW;EACX,WAAW;EACX,MAAM;EACN,UAAU;EACV,KAAK;EACL,KAAK;EACL,MAAM;EACN,WAAW;EACX,UAAU;EACV,SAAS;EACT,aAAa;EACb,aAAa;EACb,UAAU;EACV,YAAY;EACZ,WAAW;EACX,MAAM;EACN,OAAO;EACP,WAAW;EACX,OAAO;EACP,UAAU;EACV,WAAW;EACX,SAAS;EACT,QAAQ;EACR,MAAM;EACN,QAAQ;EACR,UAAU;EACV,UAAU;EACV,SAAS;EACT,SAAS;EACT,QAAQ;EACR,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,cAAc;EACd,kBAAkB;EAClB,cAAc;EACd,kBAAkB;EAClB,SAAS;EACT,aAAa;EACb,SAAS;EACT,UAAU;EACV,UAAU;EACV,SAAS;EACT,SAAS;EACT,eAAe;EACf,aAAa;EACb,WAAW;EACX,WAAW;EACX,eAAe;EACf,eAAe;EACf,mBAAmB;EACnB,aAAa;EACb,aAAa;CACf;CACA,SAAS;EACP,QAAQ;GAAE,UAAU;GAAO,YAAY;GAAO,QAAQ;EAAO;EAC7D,YAAY;GAAE,OAAO;GAAM,KAAK;EAAK;EACrC,MAAM;GAAE,IAAI;GAAK,IAAI;GAAK,IAAI;EAAI;EAClC,cAAc;GAAE,MAAM;GAAM,UAAU;GAAQ,OAAO;EAAM;EAC3D,WAAW;GAAE,YAAY;GAAM,UAAU;EAAK;EAC9C,UAAU;GACR,MAAM;GACN,MAAM;GACN,OAAO;GACP,SAAS;GACT,MAAM;GACN,UAAU;EACZ;EACA,SAAS;GAAE,OAAO;GAAM,MAAM;GAAM,SAAS;EAAK;EAClD,UAAU;GACR,MAAM;GACN,OAAO;GACP,SAAS;GACT,OAAO;GACP,WAAW;EACb;EACA,UAAU;GAAE,OAAO;GAAM,KAAK;GAAM,QAAQ;GAAM,SAAS;GAAM,QAAQ;EAAK;EAC9E,aAAa;GAAE,MAAM;GAAM,QAAQ;GAAO,MAAM;EAAM;EACtD,MAAM;GAAE,SAAS;GAAM,SAAS;GAAM,SAAS;GAAM,SAAS;GAAM,QAAQ;EAAK;EACjF,YAAY;GAAE,MAAM;GAAM,IAAI;GAAS,IAAI;GAAS,IAAI;GAAS,IAAI;EAAQ;CAC/E;CACA,QAAQ;EAAE,MAAM;EAAU,OAAO;CAAmB;AACtD;AAEA,IAAM,OAA4B;CAChC,OAAO;EACL,OAAO;EACP,UAAU;EACV,gBAAgB;EAChB,QAAQ;EACR,eAAe;EACf,kBAAkB;EAClB,UAAU;EACV,QAAQ;EACR,qBAAqB;EACrB,QAAQ;EACR,MAAM;EACN,eAAe;EACf,eAAe;EACf,gBAAgB;EAChB,UAAU;EACV,eAAe;EACf,aAAa;EACb,aAAa;EACb,QAAQ;EACR,MAAM;EACN,SAAS;EACT,OAAO;EACP,SAAS;EACT,MAAM;EACN,OAAO;EACP,MAAM;EACN,MAAM;CACR;CACA,QAAQ;EAAE,OAAO;EAAM,QAAQ;EAAM,MAAM;EAAM,SAAS;EAAM,QAAQ;CAAK;CAC7E,SAAS;EAAE,QAAQ;EAAQ,OAAO;EAAW,KAAK;CAAY;CAC9D,SAAS;EAAE,OAAO;EAAQ,QAAQ;EAAM,UAAU;CAAK;CACvD,QAAQ;EAAE,OAAO;EAAQ,OAAO;EAAa,eAAe;CAAU;CACtE,QAAQ;EAAE,MAAM;EAAS,QAAQ;EAAM,SAAS;EAAM,UAAU;CAAK;CACrE,SAAS;EACP,QAAQ;EACR,IAAI;EACJ,MAAM;EACN,WAAW;EACX,QAAQ;EACR,MAAM;EACN,YAAY;EACZ,MAAM;EACN,SAAS;EACT,MAAM;EACN,MAAM;CACR;CACA,WAAW;EACT,MAAM;EACN,UAAU;EACV,MAAM;EACN,OAAO;EACP,OAAO;CACT;CACA,UAAU;EACR,UAAU;EACV,SAAS;EACT,YAAY;EACZ,OAAO;EACP,SAAS;EACT,aAAa;EACb,SAAS;EACT,QAAQ;EACR,QAAQ;EACR,UAAU;CACZ;CACA,WAAW;EACT,SAAS;EACT,KAAK;EACL,OAAO;EACP,UAAU;EACV,OAAO;EACP,KAAK;EACL,QAAQ;EACR,KAAK;EACL,KAAK;EACL,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,KAAK;EACL,IAAI;EACJ,WAAW;EACX,WAAW;EACX,WAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,UAAU;GACV,OAAO;GACP,QAAQ;EACV;EACA,eAAe;GAAE,IAAI;GAAM,IAAI;GAAO,IAAI;GAAM,IAAI;EAAM;CAC5D;CACA,YAAY;EACV,QAAQ;EACR,MAAM;EACN,OAAO;EACP,WAAW;GACT,KAAK;IAAE,WAAW;IAAc,MAAM;GAAc;GACpD,OAAO;IAAE,WAAW;IAAgB,MAAM;GAAmB;GAC7D,QAAQ;IAAE,WAAW;IAAiB,MAAM;GAAmB;GAC/D,KAAK;IAAE,WAAW;IAAmB,MAAM;GAAY;GACvD,KAAK;IAAE,WAAW;IAAmB,MAAM;GAAO;GAClD,KAAK;IAAE,WAAW;IAAmB,MAAM;GAAO;GAClD,OAAO;IAAE,WAAW;IAAyB,MAAM;GAAyB;GAC5E,KAAK;IAAE,WAAW;IAAc,MAAM;GAAM;GAC5C,OAAO;IAAE,WAAW;IAAkB,MAAM;GAAkC;GAC9E,MAAM;IAAE,WAAW;IAAkB,MAAM;GAAY;GACvD,UAAU;IAAE,WAAW;IAA8B,MAAM;GAAiB;EAC9E;EACA,SAAS;EACT,UAAU;GACR,wBAAwB;GACxB,uBAAuB;GACvB,oBAAoB;GACpB,kBAAkB;GAClB,gBAAgB;GAChB,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,iBAAiB;GACjB,oBAAoB;EACtB;CACF;CACA,SAAS;EACP,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,SAAS;GAAE,SAAS;GAAM,QAAQ;GAAM,OAAO;EAAK;EACpD,QAAQ;EACR,OAAO;EACP,QAAQ;CACV;CACA,MAAM;EACJ,OAAO;EACP,QAAQ;EACR,MAAM;EACN,UAAU;EACV,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,OAAO;EACP,QAAQ;EACR,UAAU;EACV,MAAM;EACN,MAAM;EACN,OAAO;GACL,UAAU;GACV,QAAQ;GACR,OAAO;GACP,QAAQ;GACR,QAAQ;GACR,SAAS;GACT,MAAM;GACN,MAAM;EACR;EACA,UAAU;GACR,SAAS;GACT,gBAAgB;GAChB,gBAAgB;GAChB,kBAAkB;GAClB,gBAAgB;GAChB,kBAAkB;GAClB,cAAc;GACd,OAAO;GACP,iBAAiB;GACjB,qBAAqB;GACrB,uBAAuB;EACzB;CACF;CACA,MAAM;EACJ,QAAQ;EACR,OAAO;EACP,KAAK;EACL,WAAW;EACX,QAAQ;CACV;CACA,SAAS;EACP,QAAQ;EACR,MAAM;EACN,MAAM;EACN,MAAM;EACN,OAAO;CACT;CACA,UAAU;EACR,MAAM;EACN,UAAU;EACV,UAAU;EACV,cAAc;EACd,OAAO;EACP,MAAM;EACN,SAAS;EACT,UAAU;EACV,MAAM;EACN,gBAAgB;EAChB,OAAO;EACP,aAAa;EACb,UAAU;EACV,SAAS;EACT,UAAU;EACV,UAAU;EACV,UAAU;EACV,SAAS;EACT,QAAQ;EACR,YAAY;EACZ,YAAY;EACZ,MAAM;EACN,cAAc;EACd,aAAa;EACb,WAAW;EACX,WAAW;EACX,WAAW;EACX,MAAM;EACN,UAAU;EACV,KAAK;EACL,KAAK;EACL,MAAM;EACN,WAAW;EACX,UAAU;EACV,SAAS;EACT,aAAa;EACb,aAAa;EACb,UAAU;EACV,YAAY;EACZ,WAAW;EACX,MAAM;EACN,OAAO;EACP,WAAW;EACX,OAAO;EACP,UAAU;EACV,WAAW;EACX,SAAS;EACT,QAAQ;EACR,MAAM;EACN,QAAQ;EACR,UAAU;EACV,UAAU;EACV,SAAS;EACT,SAAS;EACT,QAAQ;EACR,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,cAAc;EACd,kBAAkB;EAClB,cAAc;EACd,kBAAkB;EAClB,SAAS;EACT,aAAa;EACb,SAAS;EACT,UAAU;EACV,UAAU;EACV,SAAS;EACT,SAAS;EACT,eAAe;EACf,aAAa;EACb,WAAW;EACX,WAAW;EACX,eAAe;EACf,eAAe;EACf,mBAAmB;EACnB,aAAa;EACb,aAAa;CACf;CACA,SAAS;EACP,QAAQ;GAAE,UAAU;GAAO,YAAY;GAAO,QAAQ;EAAO;EAC7D,YAAY;GAAE,OAAO;GAAM,KAAK;EAAK;EACrC,MAAM;GAAE,IAAI;GAAK,IAAI;GAAK,IAAI;EAAI;EAClC,cAAc;GAAE,MAAM;GAAM,UAAU;GAAQ,OAAO;EAAM;EAC3D,WAAW;GAAE,YAAY;GAAM,UAAU;EAAK;EAC9C,UAAU;GACR,MAAM;GACN,MAAM;GACN,OAAO;GACP,SAAS;GACT,MAAM;GACN,UAAU;EACZ;EACA,SAAS;GAAE,OAAO;GAAM,MAAM;GAAM,SAAS;EAAK;EAClD,UAAU;GACR,MAAM;GACN,OAAO;GACP,SAAS;GACT,OAAO;GACP,WAAW;EACb;EACA,UAAU;GAAE,OAAO;GAAQ,KAAK;GAAM,QAAQ;GAAM,SAAS;GAAM,QAAQ;EAAK;EAChF,aAAa;GAAE,MAAM;GAAM,QAAQ;GAAO,MAAM;EAAM;EACtD,MAAM;GAAE,SAAS;GAAM,SAAS;GAAM,SAAS;GAAM,SAAS;GAAM,QAAQ;EAAK;EACjF,YAAY;GAAE,MAAM;GAAM,IAAI;GAAS,IAAI;GAAS,IAAI;GAAS,IAAI;EAAQ;CAC/E;CACA,QAAQ;EAAE,MAAM;EAAW,OAAO;CAAoB;AACxD;AAEA,IAAM,KAA0B;CAC9B,OAAO;EACL,OAAO;EACP,UAAU;EACV,gBAAgB;EAChB,QAAQ;EACR,eAAe;EACf,kBAAkB;EAClB,UAAU;EACV,QAAQ;EACR,qBAAqB;EACrB,QAAQ;EACR,MAAM;EACN,eAAe;EACf,eAAe;EACf,gBAAgB;EAChB,UAAU;EACV,eAAe;EACf,aAAa;EACb,aAAa;EACb,QAAQ;EACR,MAAM;EACN,SAAS;EACT,OAAO;EACP,SAAS;EACT,MAAM;EACN,OAAO;EACP,MAAM;EACN,MAAM;CACR;CACA,QAAQ;EAAE,OAAO;EAAS,QAAQ;EAAU,MAAM;EAAQ,SAAS;EAAW,QAAQ;CAAS;CAC/F,SAAS;EAAE,QAAQ;EAAiB,OAAO;EAAoB,KAAK;CAAc;CAClF,SAAS;EAAE,OAAO;EAAgB,QAAQ;EAAU,UAAU;CAAW;CACzE,QAAQ;EACN,OAAO;EACP,OAAO;EACP,eAAe;CACjB;CACA,QAAQ;EACN,MAAM;EACN,QAAQ;EACR,SAAS;EACT,UAAU;CACZ;CACA,SAAS;EACP,QAAQ;EACR,IAAI;EACJ,MAAM;EACN,WAAW;EACX,QAAQ;EACR,MAAM;EACN,YAAY;EACZ,MAAM;EACN,SAAS;EACT,MAAM;EACN,MAAM;CACR;CACA,WAAW;EACT,MAAM;EACN,UAAU;EACV,MAAM;EACN,OAAO;EACP,OAAO;CACT;CACA,UAAU;EACR,UAAU;EACV,SAAS;EACT,YAAY;EACZ,OAAO;EACP,SAAS;EACT,aAAa;EACb,SAAS;EACT,QAAQ;EACR,QAAQ;EACR,UAAU;CACZ;CACA,WAAW;EACT,SAAS;EACT,KAAK;EACL,OAAO;EACP,UAAU;EACV,OAAO;EACP,KAAK;EACL,QAAQ;EACR,KAAK;EACL,KAAK;EACL,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,KAAK;EACL,IAAI;EACJ,WAAW;EACX,WAAW;EACX,WAAW;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,UAAU;GACV,OAAO;GACP,QAAQ;EACV;EACA,eAAe;GAAE,IAAI;GAAY,IAAI;GAAiB,IAAI;GAAa,IAAI;EAAe;CAC5F;CACA,YAAY;EACV,QAAQ;EACR,MAAM;EACN,OAAO;EACP,WAAW;GACT,KAAK;IAAE,WAAW;IAAc,MAAM;GAA8C;GACpF,OAAO;IACL,WAAW;IACX,MAAM;GACR;GACA,QAAQ;IAAE,WAAW;IAAiB,MAAM;GAA2C;GACvF,KAAK;IAAE,WAAW;IAAmB,MAAM;GAA6B;GACxE,KAAK;IAAE,WAAW;IAAmB,MAAM;GAAsB;GACjE,KAAK;IAAE,WAAW;IAAmB,MAAM;GAAqB;GAChE,OAAO;IACL,WAAW;IACX,MAAM;GACR;GACA,KAAK;IAAE,WAAW;IAAc,MAAM;GAAqB;GAC3D,OAAO;IAAE,WAAW;IAAkB,MAAM;GAAyC;GACrF,MAAM;IAAE,WAAW;IAAkB,MAAM;GAAoC;GAC/E,UAAU;IACR,WAAW;IACX,MAAM;GACR;EACF;EACA,SAAS;EACT,UAAU;GACR,wBAAwB;GACxB,uBAAuB;GACvB,oBAAoB;GACpB,kBAAkB;GAClB,gBAAgB;GAChB,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,iBAAiB;GACjB,oBAAoB;EACtB;CACF;CACA,SAAS;EACP,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,SAAS;GAAE,SAAS;GAAW,QAAQ;GAAU,OAAO;EAAQ;EAChE,QAAQ;EACR,OAAO;EACP,QAAQ;CACV;CACA,MAAM;EACJ,OAAO;EACP,QAAQ;EACR,MAAM;EACN,UAAU;EACV,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,OAAO;EACP,QAAQ;EACR,UAAU;EACV,MAAM;EACN,MAAM;EACN,OAAO;GACL,UAAU;GACV,QAAQ;GACR,OAAO;GACP,QAAQ;GACR,QAAQ;GACR,SAAS;GACT,MAAM;GACN,MAAM;EACR;EACA,UAAU;GACR,SAAS;GACT,gBAAgB;GAChB,gBAAgB;GAChB,kBAAkB;GAClB,gBAAgB;GAChB,kBAAkB;GAClB,cAAc;GACd,OAAO;GACP,iBAAiB;GACjB,qBAAqB;GACrB,uBAAuB;EACzB;CACF;CACA,MAAM;EACJ,QAAQ;EACR,OAAO;EACP,KAAK;EACL,WAAW;EACX,QAAQ;CACV;CACA,SAAS;EACP,QAAQ;EACR,MAAM;EACN,MAAM;EACN,MAAM;EACN,OAAO;CACT;CACA,UAAU;EACR,MAAM;EACN,UAAU;EACV,UAAU;EACV,cAAc;EACd,OAAO;EACP,MAAM;EACN,SAAS;EACT,UAAU;EACV,MAAM;EACN,gBAAgB;EAChB,OAAO;EACP,aAAa;EACb,UAAU;EACV,SAAS;EACT,UAAU;EACV,UAAU;EACV,UAAU;EACV,SAAS;EACT,QAAQ;EACR,YAAY;EACZ,YAAY;EACZ,MAAM;EACN,cAAc;EACd,aAAa;EACb,WAAW;EACX,WAAW;EACX,WAAW;EACX,MAAM;EACN,UAAU;EACV,KAAK;EACL,KAAK;EACL,MAAM;EACN,WAAW;EACX,UAAU;EACV,SAAS;EACT,aAAa;EACb,aAAa;EACb,UAAU;EACV,YAAY;EACZ,WAAW;EACX,MAAM;EACN,OAAO;EACP,WAAW;EACX,OAAO;EACP,UAAU;EACV,WAAW;EACX,SAAS;EACT,QAAQ;EACR,MAAM;EACN,QAAQ;EACR,UAAU;EACV,UAAU;EACV,SAAS;EACT,SAAS;EACT,QAAQ;EACR,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,cAAc;EACd,kBAAkB;EAClB,cAAc;EACd,kBAAkB;EAClB,SAAS;EACT,aAAa;EACb,SAAS;EACT,UAAU;EACV,UAAU;EACV,SAAS;EACT,SAAS;EACT,eAAe;EACf,aAAa;EACb,WAAW;EACX,WAAW;EACX,eAAe;EACf,eAAe;EACf,mBAAmB;EACnB,aAAa;EACb,aAAa;CACf;CACA,SAAS;EACP,QAAQ;GAAE,UAAU;GAAS,YAAY;GAAU,QAAQ;EAAW;EACtE,YAAY;GAAE,OAAO;GAAS,KAAK;EAAM;EACzC,MAAM;GAAE,IAAI;GAAS,IAAI;GAAU,IAAI;EAAQ;EAC/C,cAAc;GAAE,MAAM;GAAY,UAAU;GAAiB,OAAO;EAAO;EAC3E,WAAW;GAAE,YAAY;GAAU,UAAU;EAAO;EACpD,UAAU;GACR,MAAM;GACN,MAAM;GACN,OAAO;GACP,SAAS;GACT,MAAM;GACN,UAAU;EACZ;EACA,SAAS;GAAE,OAAO;GAAW,MAAM;GAAQ,SAAS;EAAU;EAC9D,UAAU;GACR,MAAM;GACN,OAAO;GACP,SAAS;GACT,OAAO;GACP,WAAW;EACb;EACA,UAAU;GACR,OAAO;GACP,KAAK;GACL,QAAQ;GACR,SAAS;GACT,QAAQ;EACV;EACA,aAAa;GAAE,MAAM;GAAW,QAAQ;GAAU,MAAM;EAAU;EAClE,MAAM;GACJ,SAAS;GACT,SAAS;GACT,SAAS;GACT,SAAS;GACT,QAAQ;EACV;EACA,YAAY;GAAE,MAAM;GAAa,IAAI;GAAS,IAAI;GAAS,IAAI;GAAS,IAAI;EAAQ;CACtF;CACA,QAAQ;EAAE,MAAM;EAAyB,OAAO;CAA6B;AAC/E;AAEA,IAAa,qBAA0D;CACrE,SAAS;CACT,SAAS;CACT;AACF;;AAUA,SAAgB,uBACd,UACA;CACA,MAAM,EAAE,WAAW,UAAU;CAC7B,OAAO,eAAoC;EACzC,MAAM,OAAO,OAAO,MAAM;EAC1B,MAAM,OACJ,mBAAmB,SACnB,mBAAmB,KAAK,MAAM,GAAG,CAAC,CAAC,QAClC,KAAK,WAAW,IAAI,IAAI,OAAO;EAClC,MAAM,QAAQ,QAAQ,QAAQ;EAC9B,IAAI,CAAC,OAAO,OAAO;EACnB,MAAM,SAAS,EAAE,GAAG,KAAK;EACzB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;GAChD,IAAI,CAAC,OAAO;GACZ,MAAM,MAAO,KAA4D;GACzE,IAAI,QAAQ,WAAW;IACrB,MAAM,UAAU,EAAE,GAAG,IAAI;IACzB,KAAK,MAAM,CAAC,SAAS,WAAW,OAAO,QACrC,KACF,GACE,QAAQ,WAAW;KAAE,GAAG,QAAQ;KAAU,GAAG;IAAO;IACtD,OAAO,OAAO;GAChB,OAAO,OAAO,OAAO;IAAE,GAAG;IAAK,GAAG;GAAM;EAC1C;EACA,OAAO;CACT,CAAC;AACH"}
@@ -0,0 +1,18 @@
1
+ import { defineFormField } from "../fields/define.js";
2
+ import { CONDITION_TYPE, EXPRESSION_TYPE } from "./settings.js";
3
+ import ExpressionBox from "./expression-box.js";
4
+ import condition_editor_default from "./condition-editor.js";
5
+ // src/builder/logic-fields.ts
6
+ var expressionField = defineFormField({
7
+ type: EXPRESSION_TYPE,
8
+ component: ExpressionBox,
9
+ empty: () => ""
10
+ });
11
+ var conditionField = defineFormField({
12
+ type: CONDITION_TYPE,
13
+ component: condition_editor_default,
14
+ empty: () => ""
15
+ });
16
+ export { conditionField, expressionField };
17
+
18
+ //# sourceMappingURL=logic-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logic-fields.js","names":["ExpressionInput","ConditionEditor"],"sources":["../../src/builder/logic-fields.ts"],"sourcesContent":["import { defineFormField } from '../fields/define'\nimport ConditionEditor from './condition-editor.vue'\nimport ExpressionInput from './expression-box'\nimport { CONDITION_TYPE, EXPRESSION_TYPE } from './settings'\n\nexport const expressionField = defineFormField({\n type: EXPRESSION_TYPE,\n component: ExpressionInput,\n empty: () => '',\n})\n\nexport const conditionField = defineFormField({\n type: CONDITION_TYPE,\n component: ConditionEditor,\n empty: () => '',\n})\n"],"mappings":";;;;;AAKA,IAAa,kBAAkB,gBAAgB;CAC7C,MAAM;CACN,WAAWA;CACX,aAAa;AACf,CAAC;AAED,IAAa,iBAAiB,gBAAgB;CAC5C,MAAM;CACN,WAAWC;CACX,aAAa;AACf,CAAC"}
@@ -0,0 +1,332 @@
1
+ import { isContainer, isField, isList } from "../core/document.js";
2
+ import { normalizeOptions } from "../fields/components.js";
3
+ import { formNodePlaces } from "./core/transaction.js";
4
+ import { scopeOf } from "./core/commands.js";
5
+ import { CONDITION_TYPE, EXPRESSION_TYPE, choices, field, nodeTitle, number, text } from "./settings.js";
6
+ // src/builder/logic.ts
7
+ var operatorsOf = {
8
+ text: [
9
+ "eq",
10
+ "ne",
11
+ "contains",
12
+ "empty",
13
+ "filled"
14
+ ],
15
+ number: [
16
+ "eq",
17
+ "ne",
18
+ "gt",
19
+ "ge",
20
+ "lt",
21
+ "le",
22
+ "empty",
23
+ "filled"
24
+ ],
25
+ date: [
26
+ "eq",
27
+ "ne",
28
+ "gt",
29
+ "ge",
30
+ "lt",
31
+ "le",
32
+ "empty",
33
+ "filled"
34
+ ],
35
+ boolean: ["eq", "ne"],
36
+ choice: [
37
+ "eq",
38
+ "ne",
39
+ "in",
40
+ "empty",
41
+ "filled"
42
+ ],
43
+ choices: [
44
+ "contains",
45
+ "empty",
46
+ "filled"
47
+ ],
48
+ list: ["empty", "filled"]
49
+ };
50
+ var KINDS = {
51
+ switch: "boolean",
52
+ checkbox: "boolean",
53
+ "input-number": "number",
54
+ rate: "number",
55
+ "date-picker": "date",
56
+ "time-picker": "date",
57
+ "radio-group": "choice",
58
+ "segmented-control": "choice",
59
+ "checkbox-group": "choices",
60
+ "input-tag": "choices",
61
+ upload: "list"
62
+ };
63
+ function kindOf(node, type) {
64
+ const props = node.props ?? {};
65
+ const own = KINDS[node.type];
66
+ if (own === "date" || own === "number") return props.range ? "list" : own;
67
+ if (own) return own;
68
+ if (node.type === "slider") return props.range ? "list" : "number";
69
+ if (type?.optionsProp) return props.multiple ? "choices" : "choice";
70
+ const empty = type?.empty?.({
71
+ ...type.defaultProps,
72
+ ...props
73
+ });
74
+ if (typeof empty === "boolean") return "boolean";
75
+ if (typeof empty === "number") return "number";
76
+ if (Array.isArray(empty)) return "choices";
77
+ return "text";
78
+ }
79
+ function optionsOf(node, type) {
80
+ const prop = type?.optionsProp;
81
+ const list = prop ? node.props?.[prop] ?? type?.defaultProps?.[prop] : void 0;
82
+ if (!Array.isArray(list)) return void 0;
83
+ return normalizeOptions(list).filter(({ value }) => value === null || [
84
+ "string",
85
+ "number",
86
+ "boolean"
87
+ ].includes(typeof value)).map(({ label, value }) => ({
88
+ label: String(label ?? value),
89
+ value
90
+ }));
91
+ }
92
+ /**
93
+ * The target of one field, kept per node: a change to one field of a large
94
+ * form makes a new object only for that field, so scopes built before and
95
+ * after can be told apart without comparing their contents.
96
+ */
97
+ var targetCache = /* @__PURE__ */ new WeakMap();
98
+ function fieldTarget(node, scope, fields, messages) {
99
+ const cached = targetCache.get(node);
100
+ if (cached && cached.scope === scope && cached.fields === fields && cached.messages === messages) return cached.target;
101
+ const type = fields.get(node.type);
102
+ let target = null;
103
+ if (type?.kind !== "display") {
104
+ const kind = kindOf(node, type);
105
+ target = {
106
+ scope,
107
+ path: node.name,
108
+ label: nodeTitle(node, fields, messages),
109
+ kind
110
+ };
111
+ if (kind === "choice" || kind === "choices") target.options = optionsOf(node, type);
112
+ }
113
+ targetCache.set(node, {
114
+ scope,
115
+ fields,
116
+ messages,
117
+ target
118
+ });
119
+ return target;
120
+ }
121
+ /** The value nodes of one scope, groups and pages included, lists as one value. */
122
+ function scopeTargets(nodes, scope, fields, messages, out) {
123
+ for (const node of nodes) {
124
+ if (isList(node)) {
125
+ if (node.name) out.push({
126
+ scope,
127
+ path: node.name,
128
+ label: nodeTitle(node, fields, messages),
129
+ kind: "list"
130
+ });
131
+ continue;
132
+ }
133
+ if (isContainer(node)) {
134
+ scopeTargets(node.children, scope, fields, messages, out);
135
+ continue;
136
+ }
137
+ if (!isField(node) || !node.name) continue;
138
+ const target = fieldTarget(node, scope, fields, messages);
139
+ if (target) out.push(target);
140
+ }
141
+ return out;
142
+ }
143
+ function logicScope(document, id, fields, messages) {
144
+ const targets = scopeTargets(document.nodes, "values", fields, messages, []);
145
+ const parent = id ? formNodePlaces(document).get(id)?.parent : void 0;
146
+ const list = scopeOf(document, parent?.id ?? null);
147
+ const paths = targets.map((target) => target.path);
148
+ if (!list) return {
149
+ targets,
150
+ names: paths,
151
+ itemNames: void 0
152
+ };
153
+ const items = scopeTargets(list.children, "item", fields, messages, []);
154
+ return {
155
+ targets: [...items, ...targets],
156
+ names: paths,
157
+ itemNames: items.map((t) => t.path)
158
+ };
159
+ }
160
+ /** Whether two scopes hold the same targets, so settings forms built on the first are kept. */
161
+ function sameLogicScope(a, b) {
162
+ return a.targets.length === b.targets.length && a.targets.every((target, index) => {
163
+ const other = b.targets[index];
164
+ return target === other || JSON.stringify(target) === JSON.stringify(other);
165
+ });
166
+ }
167
+ /** When a node shows, is disabled or required, and the value a field works out. */
168
+ function logicSettings(node, context) {
169
+ const s = context.messages.settings;
170
+ const own = "name" in node ? node.name : void 0;
171
+ const ownScope = context.scope.itemNames ? "item" : "values";
172
+ const targets = context.scope.targets.filter((target) => target.path !== own || target.scope !== ownScope);
173
+ const condition = (name) => field(CONDITION_TYPE, name, s[name], {
174
+ help: s[`${name}Help`],
175
+ props: { targets }
176
+ });
177
+ const result = [condition("visibleWhen")];
178
+ const display = context.type?.kind === "display";
179
+ if (!display) result.push(condition("disabledWhen"));
180
+ if (isFieldNode(node) && !display) {
181
+ result.push(condition("requiredWhen"));
182
+ if (node.type !== "upload") result.push(field(EXPRESSION_TYPE, "formula", s.formula, {
183
+ help: s.formulaHelp,
184
+ props: {
185
+ names: names(context.scope.targets, "values"),
186
+ itemNames: context.scope.itemNames && names(context.scope.targets, "item"),
187
+ placeholder: "values.price * values.count"
188
+ }
189
+ }));
190
+ }
191
+ return result;
192
+ }
193
+ var isFieldNode = (node) => ![
194
+ "section",
195
+ "tabs",
196
+ "steps",
197
+ "page",
198
+ "list"
199
+ ].includes(node.type);
200
+ function names(targets, scope) {
201
+ return targets.filter((target) => target.scope === scope).map((target) => ({
202
+ path: target.path,
203
+ label: target.label
204
+ }));
205
+ }
206
+ /** The kinds of check the rules editor offers, each writing its own keys of a rule. */
207
+ var ruleKinds = [
208
+ "type",
209
+ "range",
210
+ "pattern",
211
+ "check",
212
+ "validator"
213
+ ];
214
+ /** The checks of a field or a list, as a list of rules. */
215
+ function ruleSettings(context) {
216
+ const messages = context.messages;
217
+ const s = messages.settings;
218
+ return [{
219
+ id: "setting-rules",
220
+ type: "list",
221
+ name: "rules",
222
+ addText: s.addRule,
223
+ columns: 12,
224
+ children: [
225
+ field("select", "kind", s.ruleKind, {
226
+ default: "type",
227
+ props: { options: choices(messages, "ruleKind", ruleKinds) }
228
+ }),
229
+ field("select", "type", s.ruleType, {
230
+ default: "email",
231
+ visibleWhen: when("type"),
232
+ props: { options: choices(messages, "ruleType", [
233
+ "email",
234
+ "url",
235
+ "number",
236
+ "integer",
237
+ "string"
238
+ ]) }
239
+ }),
240
+ number("min", s.ruleMin, {}, {
241
+ span: 6,
242
+ visibleWhen: when("range")
243
+ }),
244
+ number("max", s.ruleMax, {}, {
245
+ span: 6,
246
+ visibleWhen: when("range")
247
+ }),
248
+ {
249
+ id: "setting-rangeHelp",
250
+ type: "text",
251
+ visibleWhen: when("range"),
252
+ props: {
253
+ content: s.ruleRangeHelp,
254
+ variant: "caption"
255
+ }
256
+ },
257
+ text("pattern", s.rulePattern, {
258
+ span: 8,
259
+ visibleWhen: when("pattern"),
260
+ props: { placeholder: "^\\d{6}$" }
261
+ }),
262
+ text("flags", s.ruleFlags, {
263
+ span: 4,
264
+ visibleWhen: when("pattern"),
265
+ props: { placeholder: "i" }
266
+ }),
267
+ field(EXPRESSION_TYPE, "check", s.ruleCheck, {
268
+ help: s.ruleCheckHelp,
269
+ visibleWhen: when("check"),
270
+ props: {
271
+ names: names(context.scope.targets, "values"),
272
+ itemNames: context.scope.itemNames && names(context.scope.targets, "item"),
273
+ readsValue: true,
274
+ placeholder: "value >= values.start"
275
+ }
276
+ }),
277
+ field("select", "validator", s.ruleValidator, {
278
+ help: s.ruleValidatorHelp,
279
+ visibleWhen: when("validator"),
280
+ props: {
281
+ options: [...context.validators ?? []],
282
+ creatable: !context.validators
283
+ }
284
+ }),
285
+ text("message", s.ruleMessage),
286
+ field("select", "trigger", s.ruleTrigger, {
287
+ default: "auto",
288
+ props: { options: choices(messages, "ruleTrigger", [
289
+ "auto",
290
+ "change",
291
+ "blur"
292
+ ]) }
293
+ })
294
+ ]
295
+ }];
296
+ }
297
+ var when = (kind) => `item.kind == '${kind}'`;
298
+ /** A rule as a row of the rules editor: its keys, and which kind of check it is. */
299
+ function ruleToItem(rule) {
300
+ const kind = rule.check !== void 0 ? "check" : rule.validator !== void 0 ? "validator" : rule.pattern !== void 0 ? "pattern" : rule.type !== void 0 ? "type" : rule.min !== void 0 || rule.max !== void 0 ? "range" : "type";
301
+ return {
302
+ ...rule,
303
+ kind
304
+ };
305
+ }
306
+ var KIND_KEYS = {
307
+ type: ["type"],
308
+ range: ["min", "max"],
309
+ pattern: ["pattern", "flags"],
310
+ check: ["check"],
311
+ validator: ["validator"]
312
+ };
313
+ /** A row of the rules editor as a rule: only the keys of its kind, and the message and trigger. */
314
+ function itemToRule(item) {
315
+ const kind = item.kind ?? "type";
316
+ const rule = {};
317
+ for (const key of [
318
+ ...KIND_KEYS[kind],
319
+ "message",
320
+ "trigger"
321
+ ]) {
322
+ const value = item[key];
323
+ if (value === void 0 || value === null || value === "") continue;
324
+ if (key === "trigger" && value === "auto") continue;
325
+ rule[key] = value;
326
+ }
327
+ if (kind === "type" && rule.type === void 0) rule.type = "email";
328
+ return rule;
329
+ }
330
+ export { itemToRule, logicScope, logicSettings, operatorsOf, ruleKinds, ruleSettings, ruleToItem, sameLogicScope };
331
+
332
+ //# sourceMappingURL=logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logic.js","names":[],"sources":["../../src/builder/logic.ts"],"sourcesContent":["import { isContainer, isField, isList } from '../core/document'\nimport type {\n FormDocument,\n FormFieldNode,\n FormListNode,\n FormNode,\n FormRuleSpec,\n} from '../core/types'\nimport { normalizeOptions } from '../fields/components'\nimport type { FormFieldType } from '../fields/define'\nimport type { ConditionLiteral, ConditionOperator } from './condition'\nimport { scopeOf } from './core/commands'\nimport { formNodePlaces } from './core/transaction'\nimport type { FormBuilderMessages } from './locale'\nimport {\n choices,\n CONDITION_TYPE,\n EXPRESSION_TYPE,\n field,\n nodeTitle,\n number,\n text,\n} from './settings'\n\n/** What a value is like, for the operators and the value input a condition row offers. */\nexport type TargetKind = 'text' | 'number' | 'date' | 'boolean' | 'choice' | 'choices' | 'list'\n\n/** A field a condition or an expression can read. */\nexport interface LogicTarget {\n scope: 'values' | 'item'\n path: string\n label: string\n kind: TargetKind\n /** The field's own options, for `choice` and `choices`. */\n options?: { label: string; value: ConditionLiteral }[]\n}\n\nexport const operatorsOf: Record<TargetKind, ConditionOperator[]> = {\n text: ['eq', 'ne', 'contains', 'empty', 'filled'],\n number: ['eq', 'ne', 'gt', 'ge', 'lt', 'le', 'empty', 'filled'],\n date: ['eq', 'ne', 'gt', 'ge', 'lt', 'le', 'empty', 'filled'],\n boolean: ['eq', 'ne'],\n choice: ['eq', 'ne', 'in', 'empty', 'filled'],\n choices: ['contains', 'empty', 'filled'],\n list: ['empty', 'filled'],\n}\n\nconst KINDS: Record<string, TargetKind> = {\n switch: 'boolean',\n checkbox: 'boolean',\n 'input-number': 'number',\n rate: 'number',\n 'date-picker': 'date',\n 'time-picker': 'date',\n 'radio-group': 'choice',\n 'segmented-control': 'choice',\n 'checkbox-group': 'choices',\n 'input-tag': 'choices',\n upload: 'list',\n}\n\nfunction kindOf(node: FormFieldNode, type: FormFieldType | undefined): TargetKind {\n const props = node.props ?? {}\n const own = KINDS[node.type]\n if (own === 'date' || own === 'number') return props.range ? 'list' : own\n if (own) return own\n if (node.type === 'slider') return props.range ? 'list' : 'number'\n if (type?.optionsProp) return props.multiple ? 'choices' : 'choice'\n const empty = type?.empty?.({ ...type.defaultProps, ...props } as never)\n if (typeof empty === 'boolean') return 'boolean'\n if (typeof empty === 'number') return 'number'\n if (Array.isArray(empty)) return 'choices'\n return 'text'\n}\n\nfunction optionsOf(node: FormFieldNode, type: FormFieldType | undefined) {\n const prop = type?.optionsProp\n const list = prop ? (node.props?.[prop] ?? type?.defaultProps?.[prop]) : undefined\n if (!Array.isArray(list)) return undefined\n return normalizeOptions(list)\n .filter(({ value }) => value === null || ['string', 'number', 'boolean'].includes(typeof value))\n .map(({ label, value }) => ({\n label: String(label ?? value),\n value: value as ConditionLiteral,\n }))\n}\n\n/**\n * The target of one field, kept per node: a change to one field of a large\n * form makes a new object only for that field, so scopes built before and\n * after can be told apart without comparing their contents.\n */\nconst targetCache = new WeakMap<\n FormNode,\n {\n scope: string\n fields: ReadonlyMap<string, FormFieldType>\n messages: FormBuilderMessages\n target: LogicTarget | null\n }\n>()\nfunction fieldTarget(\n node: FormFieldNode,\n scope: 'values' | 'item',\n fields: ReadonlyMap<string, FormFieldType>,\n messages: FormBuilderMessages,\n): LogicTarget | null {\n const cached = targetCache.get(node)\n if (cached && cached.scope === scope && cached.fields === fields && cached.messages === messages)\n return cached.target\n const type = fields.get(node.type)\n let target: LogicTarget | null = null\n if (type?.kind !== 'display') {\n const kind = kindOf(node, type)\n target = { scope, path: node.name!, label: nodeTitle(node, fields, messages), kind }\n if (kind === 'choice' || kind === 'choices') target.options = optionsOf(node, type)\n }\n targetCache.set(node, { scope, fields, messages, target })\n return target\n}\n\n/** The value nodes of one scope, groups and pages included, lists as one value. */\nfunction scopeTargets(\n nodes: readonly FormNode[],\n scope: 'values' | 'item',\n fields: ReadonlyMap<string, FormFieldType>,\n messages: FormBuilderMessages,\n out: LogicTarget[],\n) {\n for (const node of nodes) {\n if (isList(node)) {\n if (node.name)\n out.push({ scope, path: node.name, label: nodeTitle(node, fields, messages), kind: 'list' })\n continue\n }\n if (isContainer(node)) {\n scopeTargets(node.children, scope, fields, messages, out)\n continue\n }\n if (!isField(node) || !node.name) continue\n const target = fieldTarget(node, scope, fields, messages)\n if (target) out.push(target)\n }\n return out\n}\n\n/** What the logic of a node can read: the form's fields, and those of the list item around it. */\nexport interface LogicScope {\n targets: LogicTarget[]\n /** The names `values` can read. */\n names: string[]\n /** The names `item` can read; `undefined` outside lists. */\n itemNames: string[] | undefined\n}\n\nexport function logicScope(\n document: FormDocument,\n id: string | undefined,\n fields: ReadonlyMap<string, FormFieldType>,\n messages: FormBuilderMessages,\n): LogicScope {\n const targets = scopeTargets(document.nodes, 'values', fields, messages, [])\n const parent = id ? formNodePlaces(document).get(id)?.parent : undefined\n const list = scopeOf(document, parent?.id ?? null)\n const paths = targets.map((target) => target.path)\n if (!list) return { targets, names: paths, itemNames: undefined }\n const items = scopeTargets(list.children, 'item', fields, messages, [])\n return { targets: [...items, ...targets], names: paths, itemNames: items.map((t) => t.path) }\n}\n\n/** Whether two scopes hold the same targets, so settings forms built on the first are kept. */\nexport function sameLogicScope(a: LogicScope, b: LogicScope): boolean {\n return (\n a.targets.length === b.targets.length &&\n a.targets.every((target, index) => {\n const other = b.targets[index]!\n return target === other || JSON.stringify(target) === JSON.stringify(other)\n })\n )\n}\n\n// Settings of logic and checks -----------------------------------------------------\n\nexport interface LogicSettingsContext {\n messages: FormBuilderMessages\n /** What the node's expressions can read. */\n scope: LogicScope\n /** The node's type, for a field. */\n type?: FormFieldType\n /**\n * The names of the validators given to the builder, offered by a\n * `validator` rule; left out, any name can be typed.\n */\n validators?: readonly string[]\n}\n\n/** When a node shows, is disabled or required, and the value a field works out. */\nexport function logicSettings(node: FormNode, context: LogicSettingsContext): FormNode[] {\n const s = context.messages.settings as Record<string, string>\n // A node's conditions do not read the node itself.\n const own = 'name' in node ? node.name : undefined\n const ownScope = context.scope.itemNames ? 'item' : 'values'\n const targets = context.scope.targets.filter(\n (target) => target.path !== own || target.scope !== ownScope,\n )\n const condition = (name: string) =>\n field(CONDITION_TYPE, name, s[name]!, { help: s[`${name}Help`], props: { targets } })\n const result = [condition('visibleWhen')]\n const display = context.type?.kind === 'display'\n if (!display) result.push(condition('disabledWhen'))\n if (isFieldNode(node) && !display) {\n result.push(condition('requiredWhen'))\n if (node.type !== 'upload')\n result.push(\n field(EXPRESSION_TYPE, 'formula', s.formula!, {\n help: s.formulaHelp,\n props: {\n names: names(context.scope.targets, 'values'),\n itemNames: context.scope.itemNames && names(context.scope.targets, 'item'),\n placeholder: 'values.price * values.count',\n },\n }),\n )\n }\n return result\n}\n\nconst isFieldNode = (node: FormNode): node is FormFieldNode =>\n !['section', 'tabs', 'steps', 'page', 'list'].includes(node.type)\n\nfunction names(targets: LogicSettingsContext['scope']['targets'], scope: 'values' | 'item') {\n return targets\n .filter((target) => target.scope === scope)\n .map((target) => ({ path: target.path, label: target.label }))\n}\n\n/** The kinds of check the rules editor offers, each writing its own keys of a rule. */\nexport const ruleKinds = ['type', 'range', 'pattern', 'check', 'validator'] as const\nexport type RuleKind = (typeof ruleKinds)[number]\n\n/** The checks of a field or a list, as a list of rules. */\nexport function ruleSettings(context: LogicSettingsContext): FormNode[] {\n const messages = context.messages\n const s = messages.settings as Record<string, string>\n const list: FormListNode = {\n id: 'setting-rules',\n type: 'list',\n name: 'rules',\n addText: s.addRule,\n columns: 12,\n children: [\n field('select', 'kind', s.ruleKind!, {\n default: 'type',\n props: { options: choices(messages, 'ruleKind', ruleKinds) },\n }),\n field('select', 'type', s.ruleType!, {\n default: 'email',\n visibleWhen: when('type'),\n props: {\n options: choices(messages, 'ruleType', ['email', 'url', 'number', 'integer', 'string']),\n },\n }),\n number('min', s.ruleMin!, {}, { span: 6, visibleWhen: when('range') }),\n number('max', s.ruleMax!, {}, { span: 6, visibleWhen: when('range') }),\n {\n id: 'setting-rangeHelp',\n type: 'text',\n visibleWhen: when('range'),\n props: { content: s.ruleRangeHelp, variant: 'caption' },\n } as FormFieldNode,\n text('pattern', s.rulePattern!, {\n span: 8,\n visibleWhen: when('pattern'),\n props: { placeholder: '^\\\\d{6}$' },\n }),\n text('flags', s.ruleFlags!, {\n span: 4,\n visibleWhen: when('pattern'),\n props: { placeholder: 'i' },\n }),\n field(EXPRESSION_TYPE, 'check', s.ruleCheck!, {\n help: s.ruleCheckHelp,\n visibleWhen: when('check'),\n props: {\n names: names(context.scope.targets, 'values'),\n itemNames: context.scope.itemNames && names(context.scope.targets, 'item'),\n readsValue: true,\n placeholder: 'value >= values.start',\n },\n }),\n field('select', 'validator', s.ruleValidator!, {\n help: s.ruleValidatorHelp,\n visibleWhen: when('validator'),\n // Given validators, only their names can be picked, so none is mistyped.\n props: { options: [...(context.validators ?? [])], creatable: !context.validators },\n }),\n text('message', s.ruleMessage!),\n field('select', 'trigger', s.ruleTrigger!, {\n default: 'auto',\n props: { options: choices(messages, 'ruleTrigger', ['auto', 'change', 'blur']) },\n }),\n ],\n }\n return [list]\n}\n\nconst when = (kind: RuleKind) => `item.kind == '${kind}'`\n\ntype RuleItem = Record<string, unknown> & { kind?: RuleKind }\n\n/** A rule as a row of the rules editor: its keys, and which kind of check it is. */\nexport function ruleToItem(rule: FormRuleSpec): RuleItem {\n const kind: RuleKind =\n rule.check !== undefined\n ? 'check'\n : rule.validator !== undefined\n ? 'validator'\n : rule.pattern !== undefined\n ? 'pattern'\n : rule.type !== undefined\n ? 'type'\n : rule.min !== undefined || rule.max !== undefined\n ? 'range'\n : 'type'\n return { ...rule, kind }\n}\n\nconst KIND_KEYS: Record<RuleKind, (keyof FormRuleSpec)[]> = {\n type: ['type'],\n range: ['min', 'max'],\n pattern: ['pattern', 'flags'],\n check: ['check'],\n validator: ['validator'],\n}\n\n/** A row of the rules editor as a rule: only the keys of its kind, and the message and trigger. */\nexport function itemToRule(item: RuleItem): FormRuleSpec {\n const kind = item.kind ?? 'type'\n const rule: Record<string, unknown> = {}\n for (const key of [...KIND_KEYS[kind], 'message', 'trigger'] as const) {\n const value = item[key]\n if (value === undefined || value === null || value === '') continue\n if (key === 'trigger' && value === 'auto') continue\n rule[key] = value\n }\n if (kind === 'type' && rule.type === undefined) rule.type = 'email'\n return rule as FormRuleSpec\n}\n"],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import { formNodePlaces } from "./core/transaction.js";
2
+ import { DouDropdownItem } from "dou-ui";
3
+ import { h } from "vue";
4
+ import { ArrowDownIcon, ArrowUpIcon, CopyIcon, CornerLeftUpIcon, SquareDashedIcon, TrashIcon } from "@dou-ui/icons";
5
+ // src/builder/menu.ts
6
+ /**
7
+ * The menu of some nodes: move, copy, group and delete them, then the
8
+ * extensions' items. A read-only builder keeps only going to the parent
9
+ * and the extensions' items.
10
+ */
11
+ function nodeMenu(state, ids) {
12
+ const messages = state.messages;
13
+ const map = formNodePlaces(state.document);
14
+ const places = ids.flatMap((id) => {
15
+ const place = map.get(id);
16
+ return place ? [place] : [];
17
+ });
18
+ if (!places.length) return [];
19
+ const parents = new Set(places.map((place) => place.parent?.id ?? null));
20
+ const one = places.length === 1 ? places[0] : void 0;
21
+ const siblings = one?.parent ? one.parent.children.length : state.document.nodes.length;
22
+ const pages = places.some((place) => place.node.type === "page");
23
+ const entries = [];
24
+ if (one?.parent) entries.push({
25
+ key: "parent",
26
+ label: messages.actions.parent,
27
+ shortcut: "escape",
28
+ icon: CornerLeftUpIcon,
29
+ run: () => state.selectParent()
30
+ });
31
+ if (!state.readonly) {
32
+ entries.push({
33
+ key: "up",
34
+ label: messages.actions.up,
35
+ shortcut: "mod+arrowup",
36
+ icon: ArrowUpIcon,
37
+ run: () => state.moveBy(-1, ids),
38
+ disabled: !!one && !one.index
39
+ }, {
40
+ key: "down",
41
+ label: messages.actions.down,
42
+ shortcut: "mod+arrowdown",
43
+ icon: ArrowDownIcon,
44
+ run: () => state.moveBy(1, ids),
45
+ disabled: !!one && one.index >= siblings - 1
46
+ }, {
47
+ key: "duplicate",
48
+ label: messages.actions.duplicate,
49
+ shortcut: "mod+d",
50
+ icon: CopyIcon,
51
+ run: () => state.duplicate(ids)
52
+ });
53
+ if (parents.size === 1 && !pages) entries.push({
54
+ key: "wrap",
55
+ label: messages.actions.wrap,
56
+ shortcut: "mod+g",
57
+ icon: SquareDashedIcon,
58
+ run: () => state.wrap(ids)
59
+ });
60
+ entries.push({
61
+ key: "remove",
62
+ label: messages.actions.remove,
63
+ shortcut: "delete",
64
+ icon: TrashIcon,
65
+ run: () => state.remove(ids),
66
+ tone: "danger"
67
+ });
68
+ }
69
+ const nodes = places.map((place) => place.node);
70
+ state.extensions().menus.flatMap((menu) => menu(state, nodes)).forEach((item, index) => entries.push({
71
+ ...item,
72
+ divided: index === 0
73
+ }));
74
+ return entries;
75
+ }
76
+ /** The entries as items of a dropdown or a context menu. */
77
+ function menuItems(entries) {
78
+ return entries.map((entry) => h(DouDropdownItem, {
79
+ key: entry.key,
80
+ disabled: entry.disabled,
81
+ tone: entry.tone ?? "neutral",
82
+ divided: entry.divided,
83
+ shortcut: entry.shortcut,
84
+ onClick: entry.run
85
+ }, {
86
+ prefix: entry.icon ? () => h(entry.icon) : void 0,
87
+ default: () => entry.label
88
+ }));
89
+ }
90
+ export { menuItems, nodeMenu };
91
+
92
+ //# sourceMappingURL=menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu.js","names":[],"sources":["../../src/builder/menu.ts"],"sourcesContent":["import { h } from 'vue'\nimport type { Component, VNode } from 'vue'\nimport { DouDropdownItem } from 'dou-ui'\nimport {\n ArrowDownIcon,\n ArrowUpIcon,\n CopyIcon,\n CornerLeftUpIcon,\n SquareDashedIcon,\n TrashIcon,\n} from '@dou-ui/icons'\nimport type { FormNode } from '../core/types'\nimport type { BuilderState } from './context'\nimport { formNodePlaces } from './core/transaction'\n\n/** An item of a node's menu, built in or from an extension. */\nexport interface NodeMenuEntry {\n key: string\n label: string\n icon?: Component\n run: () => void\n disabled?: boolean\n tone?: 'neutral' | 'danger'\n /** The key that does the same, shown at the end of the item. */\n shortcut?: string\n /** A line above it, between the built-in items and an extension's. */\n divided?: boolean\n}\n\n/**\n * The menu of some nodes: move, copy, group and delete them, then the\n * extensions' items. A read-only builder keeps only going to the parent\n * and the extensions' items.\n */\nexport function nodeMenu(state: BuilderState, ids: readonly string[]): NodeMenuEntry[] {\n const messages = state.messages\n const map = formNodePlaces(state.document)\n const places = ids.flatMap((id) => {\n const place = map.get(id)\n return place ? [place] : []\n })\n if (!places.length) return []\n const parents = new Set(places.map((place) => place.parent?.id ?? null))\n const one = places.length === 1 ? places[0]! : undefined\n const siblings = one?.parent ? one.parent.children.length : state.document.nodes.length\n const pages = places.some((place) => place.node.type === 'page')\n const entries: NodeMenuEntry[] = []\n if (one?.parent)\n entries.push({\n key: 'parent',\n label: messages.actions.parent,\n shortcut: 'escape',\n icon: CornerLeftUpIcon,\n run: () => state.selectParent(),\n })\n if (!state.readonly) {\n entries.push(\n {\n key: 'up',\n label: messages.actions.up,\n shortcut: 'mod+arrowup',\n icon: ArrowUpIcon,\n run: () => state.moveBy(-1, ids),\n disabled: !!one && !one.index,\n },\n {\n key: 'down',\n label: messages.actions.down,\n shortcut: 'mod+arrowdown',\n icon: ArrowDownIcon,\n run: () => state.moveBy(1, ids),\n disabled: !!one && one.index >= siblings - 1,\n },\n {\n key: 'duplicate',\n label: messages.actions.duplicate,\n shortcut: 'mod+d',\n icon: CopyIcon,\n run: () => state.duplicate(ids),\n },\n )\n if (parents.size === 1 && !pages)\n entries.push({\n key: 'wrap',\n label: messages.actions.wrap,\n shortcut: 'mod+g',\n icon: SquareDashedIcon,\n run: () => state.wrap(ids),\n })\n entries.push({\n key: 'remove',\n label: messages.actions.remove,\n shortcut: 'delete',\n icon: TrashIcon,\n run: () => state.remove(ids),\n tone: 'danger',\n })\n }\n const nodes: FormNode[] = places.map((place) => place.node)\n const extra = state.extensions().menus.flatMap((menu) => menu(state, nodes))\n extra.forEach((item, index) => entries.push({ ...item, divided: index === 0 }))\n return entries\n}\n\n/** The entries as items of a dropdown or a context menu. */\nexport function menuItems(entries: readonly NodeMenuEntry[]): VNode[] {\n return entries.map((entry) =>\n h(\n DouDropdownItem,\n {\n key: entry.key,\n disabled: entry.disabled,\n tone: entry.tone ?? 'neutral',\n divided: entry.divided,\n shortcut: entry.shortcut,\n onClick: entry.run,\n },\n { prefix: entry.icon ? () => h(entry.icon!) : undefined, default: () => entry.label },\n ),\n )\n}\n"],"mappings":";;;;;;;;;;AAkCA,SAAgB,SAAS,OAAqB,KAAyC;CACrF,MAAM,WAAW,MAAM;CACvB,MAAM,MAAM,eAAe,MAAM,QAAQ;CACzC,MAAM,SAAS,IAAI,SAAS,OAAO;EACjC,MAAM,QAAQ,IAAI,IAAI,EAAE;EACxB,OAAO,QAAQ,CAAC,KAAK,IAAI,CAAC;CAC5B,CAAC;CACD,IAAI,CAAC,OAAO,QAAQ,OAAO,CAAC;CAC5B,MAAM,UAAU,IAAI,IAAI,OAAO,KAAK,UAAU,MAAM,QAAQ,MAAM,IAAI,CAAC;CACvE,MAAM,MAAM,OAAO,WAAW,IAAI,OAAO,KAAM,KAAA;CAC/C,MAAM,WAAW,KAAK,SAAS,IAAI,OAAO,SAAS,SAAS,MAAM,SAAS,MAAM;CACjF,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,KAAK,SAAS,MAAM;CAC/D,MAAM,UAA2B,CAAC;CAClC,IAAI,KAAK,QACP,QAAQ,KAAK;EACX,KAAK;EACL,OAAO,SAAS,QAAQ;EACxB,UAAU;EACV,MAAM;EACN,WAAW,MAAM,aAAa;CAChC,CAAC;CACH,IAAI,CAAC,MAAM,UAAU;EACnB,QAAQ,KACN;GACE,KAAK;GACL,OAAO,SAAS,QAAQ;GACxB,UAAU;GACV,MAAM;GACN,WAAW,MAAM,OAAO,IAAI,GAAG;GAC/B,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI;EAC1B,GACA;GACE,KAAK;GACL,OAAO,SAAS,QAAQ;GACxB,UAAU;GACV,MAAM;GACN,WAAW,MAAM,OAAO,GAAG,GAAG;GAC9B,UAAU,CAAC,CAAC,OAAO,IAAI,SAAS,WAAW;EAC7C,GACA;GACE,KAAK;GACL,OAAO,SAAS,QAAQ;GACxB,UAAU;GACV,MAAM;GACN,WAAW,MAAM,UAAU,GAAG;EAChC,CACF;EACA,IAAI,QAAQ,SAAS,KAAK,CAAC,OACzB,QAAQ,KAAK;GACX,KAAK;GACL,OAAO,SAAS,QAAQ;GACxB,UAAU;GACV,MAAM;GACN,WAAW,MAAM,KAAK,GAAG;EAC3B,CAAC;EACH,QAAQ,KAAK;GACX,KAAK;GACL,OAAO,SAAS,QAAQ;GACxB,UAAU;GACV,MAAM;GACN,WAAW,MAAM,OAAO,GAAG;GAC3B,MAAM;EACR,CAAC;CACH;CACA,MAAM,QAAoB,OAAO,KAAK,UAAU,MAAM,IAAI;CAE1D,MADoB,WAAW,CAAC,CAAC,MAAM,SAAS,SAAS,KAAK,OAAO,KAAK,CAC1E,CAAA,CAAM,SAAS,MAAM,UAAU,QAAQ,KAAK;EAAE,GAAG;EAAM,SAAS,UAAU;CAAE,CAAC,CAAC;CAC9E,OAAO;AACT;;AAGA,SAAgB,UAAU,SAA4C;CACpE,OAAO,QAAQ,KAAK,UAClB,EACE,iBACA;EACE,KAAK,MAAM;EACX,UAAU,MAAM;EAChB,MAAM,MAAM,QAAQ;EACpB,SAAS,MAAM;EACf,UAAU,MAAM;EAChB,SAAS,MAAM;CACjB,GACA;EAAE,QAAQ,MAAM,aAAa,EAAE,MAAM,IAAK,IAAI,KAAA;EAAW,eAAe,MAAM;CAAM,CACtF,CACF;AACF"}