@rytass/bpm-core-react 0.8.0 → 0.9.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.
- package/CHANGELOG.md +82 -0
- package/README.md +18 -2
- package/dist/chunks/FormBuilderView-BPLwAJGv.cjs +3 -0
- package/dist/chunks/FormBuilderView-BPLwAJGv.cjs.map +1 -0
- package/dist/chunks/FormBuilderView-Do9-MIAe.js +1477 -0
- package/dist/chunks/FormBuilderView-Do9-MIAe.js.map +1 -0
- package/dist/chunks/FormRendererView-C5POZbWz.js +492 -0
- package/dist/chunks/FormRendererView-C5POZbWz.js.map +1 -0
- package/dist/chunks/FormRendererView-DNtNodNl.cjs +2 -0
- package/dist/chunks/FormRendererView-DNtNodNl.cjs.map +1 -0
- package/dist/chunks/{approval-instance-list-page-YZcGGDD8.js → approval-instance-list-page-BjX2kaoF.js} +56 -54
- package/dist/chunks/approval-instance-list-page-BjX2kaoF.js.map +1 -0
- package/dist/chunks/approval-instance-list-page-C408vxE2.cjs +2 -0
- package/dist/chunks/approval-instance-list-page-C408vxE2.cjs.map +1 -0
- package/dist/chunks/{categories-DBPoSrsi.js → categories-DGlxuC6X.js} +5 -5
- package/dist/chunks/{categories-DBPoSrsi.js.map → categories-DGlxuC6X.js.map} +1 -1
- package/dist/chunks/{categories-B6QZKZRt.cjs → categories-DUfldZ_9.cjs} +2 -2
- package/dist/chunks/{categories-B6QZKZRt.cjs.map → categories-DUfldZ_9.cjs.map} +1 -1
- package/dist/chunks/compose-CULMDsLS.cjs +2 -0
- package/dist/chunks/compose-CULMDsLS.cjs.map +1 -0
- package/dist/chunks/{compose-CQHDT7vh.js → compose-DJBlA5PD.js} +60 -58
- package/dist/chunks/compose-DJBlA5PD.js.map +1 -0
- package/dist/chunks/{delegations-DDEk-WI6.cjs → delegations-CGj-tZNO.cjs} +2 -2
- package/dist/chunks/{delegations-DDEk-WI6.cjs.map → delegations-CGj-tZNO.cjs.map} +1 -1
- package/dist/chunks/{delegations-iVnRi3QE.js → delegations-DLEEFBlH.js} +231 -231
- package/dist/chunks/{delegations-iVnRi3QE.js.map → delegations-DLEEFBlH.js.map} +1 -1
- package/dist/chunks/{delegations-ZNtodFaD.js → delegations-DqMpI_Nk.js} +168 -167
- package/dist/chunks/delegations-DqMpI_Nk.js.map +1 -0
- package/dist/chunks/delegations-kbMOSEif.cjs +2 -0
- package/dist/chunks/delegations-kbMOSEif.cjs.map +1 -0
- package/dist/chunks/{designer-CUbVXEtS.js → designer-BszXJ5RO.js} +1227 -990
- package/dist/chunks/designer-BszXJ5RO.js.map +1 -0
- package/dist/chunks/designer-CmqAU92b.cjs +65 -0
- package/dist/chunks/designer-CmqAU92b.cjs.map +1 -0
- package/dist/chunks/detail-CDexqBoU.cjs +2 -0
- package/dist/chunks/detail-CDexqBoU.cjs.map +1 -0
- package/dist/chunks/{detail-Cts5_gVp.js → detail-DAak2OXS.js} +704 -622
- package/dist/chunks/detail-DAak2OXS.js.map +1 -0
- package/dist/chunks/notifications--hwl-DR0.cjs +2 -0
- package/dist/chunks/{notifications-BKs4--96.cjs.map → notifications--hwl-DR0.cjs.map} +1 -1
- package/dist/chunks/{notifications-CSulztkU.js → notifications-DJ5wzCye.js} +7 -7
- package/dist/chunks/{notifications-CSulztkU.js.map → notifications-DJ5wzCye.js.map} +1 -1
- package/dist/chunks/{orgs-CrNxqlwp.js → orgs-DytLvZ_X.js} +243 -241
- package/dist/chunks/{orgs-CrNxqlwp.js.map → orgs-DytLvZ_X.js.map} +1 -1
- package/dist/chunks/orgs-Ni22buHs.cjs +2 -0
- package/dist/chunks/orgs-Ni22buHs.cjs.map +1 -0
- package/dist/chunks/providers-DEqcuXw9.js +506 -0
- package/dist/chunks/providers-DEqcuXw9.js.map +1 -0
- package/dist/chunks/providers-D_zTbkQH.cjs +2 -0
- package/dist/chunks/providers-D_zTbkQH.cjs.map +1 -0
- package/dist/chunks/{users-qghSMtLn.cjs → users-0HqlM_VQ.cjs} +2 -2
- package/dist/chunks/{users-qghSMtLn.cjs.map → users-0HqlM_VQ.cjs.map} +1 -1
- package/dist/chunks/{users-CUY139DF.js → users-FWrb3ehW.js} +5 -5
- package/dist/chunks/{users-CUY139DF.js.map → users-FWrb3ehW.js.map} +1 -1
- package/dist/components/notification-drawer.d.ts +4 -3
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +21 -428
- package/dist/index.js.map +1 -1
- package/dist/next/index.cjs +1 -1
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.js +16 -15
- package/dist/next/index.js.map +1 -1
- package/dist/pages/admin/delegations/index.cjs +1 -1
- package/dist/pages/admin/delegations/index.js +1 -1
- package/dist/pages/admin/orgs/index.cjs +1 -1
- package/dist/pages/admin/orgs/index.js +1 -1
- package/dist/pages/admin/users/index.cjs +1 -1
- package/dist/pages/admin/users/index.js +1 -1
- package/dist/pages/delegations/index.cjs +1 -1
- package/dist/pages/delegations/index.js +1 -1
- package/dist/pages/instances/detail/index.cjs +1 -1
- package/dist/pages/instances/detail/index.js +1 -1
- package/dist/pages/settings/notifications/index.cjs +1 -1
- package/dist/pages/settings/notifications/index.js +1 -1
- package/dist/pages/templates/categories/index.cjs +1 -1
- package/dist/pages/templates/categories/index.js +1 -1
- package/dist/pages/templates/compose/index.cjs +1 -1
- package/dist/pages/templates/compose/index.js +1 -1
- package/dist/pages/templates/designer/index.cjs +1 -1
- package/dist/pages/templates/designer/index.js +1 -1
- package/dist/views/admin/delegations/index.cjs +1 -1
- package/dist/views/admin/delegations/index.js +1 -1
- package/dist/views/admin/index.cjs +1 -1
- package/dist/views/admin/index.js +3 -3
- package/dist/views/admin/orgs/index.cjs +1 -1
- package/dist/views/admin/orgs/index.js +1 -1
- package/dist/views/admin/users/index.cjs +1 -1
- package/dist/views/admin/users/index.js +1 -1
- package/dist/views/cc/index.cjs +1 -1
- package/dist/views/cc/index.js +1 -1
- package/dist/views/delegations/index.cjs +1 -1
- package/dist/views/delegations/index.js +1 -1
- package/dist/views/forms/builder/index.cjs +1 -1
- package/dist/views/forms/builder/index.js +1 -1
- package/dist/views/forms/renderer/FormRendererView.d.ts +7 -2
- package/dist/views/forms/renderer/form-data-source-field.d.ts +34 -0
- package/dist/views/forms/renderer/index.cjs +1 -1
- package/dist/views/forms/renderer/index.d.ts +1 -0
- package/dist/views/forms/renderer/index.js +2 -2
- package/dist/views/instances/detail/index.cjs +1 -1
- package/dist/views/instances/detail/index.js +1 -1
- package/dist/views/instances/detail/sections/InstanceFormSection.d.ts +4 -1
- package/dist/views/instances/detail/sections/InstanceTasksSection.d.ts +5 -1
- package/dist/views/instances/new/index.cjs +1 -1
- package/dist/views/instances/new/index.cjs.map +1 -1
- package/dist/views/instances/new/index.js +105 -86
- package/dist/views/instances/new/index.js.map +1 -1
- package/dist/views/search/index.cjs +1 -1
- package/dist/views/search/index.js +1 -1
- package/dist/views/sent/index.cjs +1 -1
- package/dist/views/sent/index.js +1 -1
- package/dist/views/settings/index.cjs +1 -1
- package/dist/views/settings/index.js +1 -1
- package/dist/views/settings/notifications/index.cjs +1 -1
- package/dist/views/settings/notifications/index.js +1 -1
- package/dist/views/templates/categories/index.cjs +1 -1
- package/dist/views/templates/categories/index.js +1 -1
- package/dist/views/templates/compose/TemplateComposeWizardView.d.ts +3 -2
- package/dist/views/templates/compose/index.cjs +1 -1
- package/dist/views/templates/compose/index.js +1 -1
- package/dist/views/templates/designer/index.cjs +1 -1
- package/dist/views/templates/designer/index.js +1 -1
- package/dist/views/templates/index.cjs +1 -1
- package/dist/views/templates/index.cjs.map +1 -1
- package/dist/views/templates/index.js +153 -112
- package/dist/views/templates/index.js.map +1 -1
- package/package.json +41 -5
- package/dist/chunks/FormBuilderView-B_KGPjlp.cjs +0 -3
- package/dist/chunks/FormBuilderView-B_KGPjlp.cjs.map +0 -1
- package/dist/chunks/FormBuilderView-D8DrQOXD.js +0 -1090
- package/dist/chunks/FormBuilderView-D8DrQOXD.js.map +0 -1
- package/dist/chunks/FormRendererView-BwVsH2eX.cjs +0 -2
- package/dist/chunks/FormRendererView-BwVsH2eX.cjs.map +0 -1
- package/dist/chunks/FormRendererView-DrHsuSVo.js +0 -220
- package/dist/chunks/FormRendererView-DrHsuSVo.js.map +0 -1
- package/dist/chunks/approval-instance-list-page-BMUKxzcz.cjs +0 -2
- package/dist/chunks/approval-instance-list-page-BMUKxzcz.cjs.map +0 -1
- package/dist/chunks/approval-instance-list-page-YZcGGDD8.js.map +0 -1
- package/dist/chunks/compose-CQHDT7vh.js.map +0 -1
- package/dist/chunks/compose-Ds_cAefe.cjs +0 -2
- package/dist/chunks/compose-Ds_cAefe.cjs.map +0 -1
- package/dist/chunks/delegations-C2wLWsDQ.cjs +0 -2
- package/dist/chunks/delegations-C2wLWsDQ.cjs.map +0 -1
- package/dist/chunks/delegations-ZNtodFaD.js.map +0 -1
- package/dist/chunks/designer-CQ9hxSdD.cjs +0 -65
- package/dist/chunks/designer-CQ9hxSdD.cjs.map +0 -1
- package/dist/chunks/designer-CUbVXEtS.js.map +0 -1
- package/dist/chunks/detail-B-Q4W-iw.cjs +0 -2
- package/dist/chunks/detail-B-Q4W-iw.cjs.map +0 -1
- package/dist/chunks/detail-Cts5_gVp.js.map +0 -1
- package/dist/chunks/notifications-BKs4--96.cjs +0 -2
- package/dist/chunks/orgs-iNJ0QEcK.cjs +0 -2
- package/dist/chunks/orgs-iNJ0QEcK.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FormBuilderView-D8DrQOXD.js","names":[],"sources":["../../src/views/forms/builder/json-code-editor.tsx","../../src/views/forms/builder/FormBuilderView.tsx"],"sourcesContent":["'use client';\n\nimport { CSSProperties, ReactElement } from 'react';\nimport dynamic from 'next/dynamic';\nimport { json } from '@codemirror/lang-json';\nimport { EditorView } from '@codemirror/view';\nimport type { Extension, ReactCodeMirrorProps } from '@uiw/react-codemirror';\n\nconst EDITOR_FALLBACK_STYLE: CSSProperties = {\n alignItems: 'center',\n border: '1px solid var(--mzn-color-border-neutral)',\n borderRadius: 4,\n color: 'var(--mzn-color-text-neutral)',\n display: 'flex',\n minHeight: 160,\n padding: 12,\n width: '100%',\n};\n\nconst JSON_EDITOR_EXTENSIONS: readonly Extension[] = [\n json(),\n EditorView.lineWrapping,\n EditorView.theme({\n '&': {\n border: '1px solid var(--mzn-color-border-neutral)',\n borderRadius: '4px',\n fontSize: '13px',\n width: '100%',\n },\n '&.cm-focused': {\n outline: '1px solid var(--mzn-color-border-primary)',\n },\n '.cm-content': {\n fontFamily:\n 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", monospace',\n minHeight: '100%',\n },\n '.cm-editor': {\n width: '100%',\n },\n '.cm-gutters': {\n borderRight: '1px solid var(--mzn-color-border-neutral)',\n },\n '.cm-scroller': {\n fontFamily:\n 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", monospace',\n },\n }),\n];\n\nconst CodeMirror = dynamic<ReactCodeMirrorProps>(\n () => import('@uiw/react-codemirror'),\n {\n loading: (): ReactElement => (\n <div style={EDITOR_FALLBACK_STYLE}>載入 JSON 編輯器</div>\n ),\n ssr: false,\n },\n);\n\ninterface JsonCodeEditorProps {\n readonly disabled?: boolean;\n readonly height: string;\n readonly name: string;\n readonly onChange: (value: string) => void;\n readonly placeholder: string;\n readonly value: string;\n}\n\nexport function JsonCodeEditor({\n disabled = false,\n height,\n name,\n onChange,\n placeholder,\n value,\n}: JsonCodeEditorProps): ReactElement {\n return (\n <CodeMirror\n aria-label={name}\n basicSetup={{\n autocompletion: true,\n bracketMatching: true,\n closeBrackets: true,\n defaultKeymap: true,\n foldGutter: true,\n highlightActiveLine: true,\n highlightSelectionMatches: true,\n lineNumbers: true,\n syntaxHighlighting: true,\n }}\n editable={!disabled}\n extensions={[...JSON_EDITOR_EXTENSIONS]}\n height={height}\n indentWithTab={false}\n onChange={onChange}\n placeholder={placeholder}\n readOnly={disabled}\n theme=\"light\"\n value={value}\n width=\"100%\"\n />\n );\n}\n","'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n Key,\n MouseEvent,\n ReactElement,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n DragDropContext,\n Draggable,\n DraggableProvided,\n Droppable,\n DropResult,\n} from '@hello-pangea/dnd';\nimport {\n Accordion,\n BaseCard,\n Badge,\n Button,\n DatePicker,\n DateTimePicker,\n Icon,\n Input,\n Section,\n SectionGroup,\n Select,\n Tab,\n TabItem,\n Table,\n Textarea,\n Toggle,\n Typography,\n} from '@mezzanine-ui/react';\nimport {\n AlignLeftIcon,\n CalendarIcon,\n CheckedIcon,\n CheckedOutlineIcon,\n CurrencyDollarIcon,\n DotDragVerticalIcon,\n DotGridIcon,\n FileAttachmentIcon,\n FileIcon,\n ListIcon,\n PlusIcon,\n TrashIcon,\n} from '@mezzanine-ui/icons';\nimport type { IconDefinition } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport {\n BooleanFieldDefinition,\n DateFieldDefinition,\n FileUploadFieldDefinition,\n FormDefinitionSchema,\n FormFieldDefinition,\n FormFieldOption,\n FormUiSchema,\n NumberFieldDefinition,\n SelectFieldDefinition,\n TextFieldDefinition,\n} from '@rytass/bpm-core-shared/form';\nimport { createFieldDefinition } from '@rytass/bpm-core-client/form';\nimport {\n buildConditionExpression,\n buildFormRendererValues,\n clampOptionalNumber,\n formatDatePickerValue,\n formatDateTimePickerValue,\n FormRendererValues,\n isDateFieldDefinition,\n isNumberFieldDefinition,\n isSelectFieldDefinition,\n parseConditionRule,\n parseOptionalNumberInput,\n readConditionOperatorOption,\n readConditionOperatorOptions,\n readDatePickerValue,\n readDefaultConditionOperator,\n readDefaultConditionValue,\n readFieldOptionAsSelectOption,\n readSelectOption,\n} from '@rytass/bpm-core-client/form';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { FormRenderer } from '../renderer/FormRendererView';\nimport { JsonCodeEditor } from './json-code-editor';\n\ntype FieldType = FormFieldDefinition['type'];\ntype BuilderTabKey = 'design' | 'preview' | 'advanced';\ntype FieldOptionRow = Readonly<\n Record<string, unknown> & {\n index: number;\n key: string;\n label: string;\n value: string;\n }\n>;\n\ntype FieldTypeOption = Readonly<{\n description: string;\n icon: IconDefinition;\n label: string;\n type: FieldType;\n}>;\n\ntype ConditionRuleTarget = 'readonlyWhen' | 'requiredWhen' | 'visibleWhen';\n\ntype ConditionRuleConfig = Readonly<{\n label: string;\n name: string;\n supportingText: string;\n target: ConditionRuleTarget;\n}>;\n\nconst FIELD_TYPE_OPTIONS: readonly FieldTypeOption[] = [\n {\n description: '單行文字、姓名、編號',\n icon: AlignLeftIcon,\n label: '文字',\n type: 'text',\n },\n {\n description: '多行補充內容',\n icon: FileIcon,\n label: '長文字',\n type: 'textarea',\n },\n {\n description: '金額、數量、分數',\n icon: CurrencyDollarIcon,\n label: '數字',\n type: 'number',\n },\n {\n description: '金額與費用',\n icon: CurrencyDollarIcon,\n label: '金額',\n type: 'money',\n },\n {\n description: '日期或到期日',\n icon: CalendarIcon,\n label: '日期',\n type: 'date',\n },\n {\n description: '日期與時間',\n icon: CalendarIcon,\n label: '日期時間',\n type: 'datetime',\n },\n {\n description: '是 / 否狀態',\n icon: CheckedIcon,\n label: '開關',\n type: 'boolean',\n },\n {\n description: '固定選項擇一',\n icon: ListIcon,\n label: '下拉選單',\n type: 'select',\n },\n {\n description: '固定選項單選',\n icon: DotGridIcon,\n label: '單選',\n type: 'radio',\n },\n {\n description: '固定選項複選',\n icon: CheckedOutlineIcon,\n label: '複選',\n type: 'checkbox',\n },\n {\n description: '附件或佐證資料',\n icon: FileAttachmentIcon,\n label: '附件',\n type: 'file_upload',\n },\n];\n\nconst WORKSPACE_GRID_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'flex',\n flexWrap: 'wrap',\n gap: 16,\n};\n\nconst CANVAS_COLUMN_STYLE: CSSProperties = {\n flex: '0.55 1 300px',\n minWidth: 0,\n};\n\nconst SETTINGS_COLUMN_STYLE: CSSProperties = {\n flex: '1.45 1 720px',\n minWidth: 620,\n};\n\nconst STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 12,\n};\n\nconst FIELD_LIBRARY_STYLE: CSSProperties = {\n display: 'flex',\n flexWrap: 'wrap',\n gap: 6,\n};\n\nconst FIELD_LIBRARY_BUTTON_STYLE: CSSProperties = {\n flex: '0 0 auto',\n whiteSpace: 'nowrap',\n};\n\nconst FIELD_LIBRARY_HEADER_STYLE: CSSProperties = {\n display: 'grid',\n gap: 8,\n};\n\nconst FIELD_BLOCK_ROW_STYLE: CSSProperties = {\n alignItems: 'center',\n cursor: 'grab',\n display: 'flex',\n gap: 12,\n touchAction: 'none',\n};\n\nconst FIELD_BLOCK_TEXT_STYLE: CSSProperties = {\n display: 'grid',\n flex: '1 1 auto',\n gap: 2,\n minWidth: 0,\n};\n\nconst FIELD_BLOCK_ACTIONS_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n flex: '0 0 auto',\n gap: 4,\n};\n\nconst FIELD_BLOCK_REQUIRED_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n gap: 6,\n};\n\nconst FIELD_BLOCK_STYLE: CSSProperties = {\n cursor: 'pointer',\n userSelect: 'none',\n};\n\nconst FIELD_BLOCK_DRAGGING_STYLE: CSSProperties = {\n filter: 'drop-shadow(0 8px 18px rgba(0, 0, 0, 0.12))',\n};\n\n// Selected field: tint the whole card with a light brand fill over the surface\n// so the active row is obvious without relying on the (removed) edit button.\nconst FIELD_BLOCK_SELECTED_CARD_STYLE: CSSProperties = {\n backgroundColor:\n 'color-mix(in srgb, var(--mzn-color-primary) 8%, var(--mzn-color-bg-surface))',\n boxShadow: 'inset 0 0 0 1px var(--mzn-color-border-primary)',\n};\n\nconst EMPTY_CANVAS_STYLE: CSSProperties = {\n alignItems: 'center',\n border: '1px dashed var(--mzn-color-border-neutral)',\n borderRadius: 6,\n display: 'grid',\n gap: 12,\n minHeight: 240,\n padding: 32,\n textAlign: 'center',\n};\n\nconst EMPTY_CANVAS_ACTIONS_STYLE: CSSProperties = {\n display: 'flex',\n gap: 8,\n justifyContent: 'center',\n};\n\nconst FIELD_SETTINGS_FORM_STYLE: CSSProperties = {\n display: 'grid',\n gap: 14,\n};\n\nconst FIELD_SETTINGS_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n columnGap: 16,\n gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',\n rowGap: 8,\n};\n\nconst FIELD_SETTINGS_SECTION_TITLE_STYLE: CSSProperties = {\n gridColumn: '1 / -1',\n};\n\nconst FIELD_SETTINGS_BADGE_ROW_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n gap: 8,\n gridColumn: '1 / -1',\n justifyContent: 'flex-end',\n};\n\nconst FIELD_SETTINGS_HINT_STYLE: CSSProperties = {\n gridColumn: '1 / -1',\n};\n\nconst FIELD_SETTINGS_ROW_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'block',\n width: '100%',\n};\n\nconst FIELD_SETTINGS_ROW_WIDE_STYLE: CSSProperties = {\n ...FIELD_SETTINGS_ROW_STYLE,\n gridColumn: '1 / -1',\n};\n\nconst FIELD_SETTINGS_VALUE_STYLE: CSSProperties = {\n minWidth: 0,\n width: '100%',\n};\n\nconst FIELD_SETTINGS_TEXTAREA_STYLE: CSSProperties = {\n minWidth: '100%',\n width: '100%',\n};\n\nconst ADVANCED_SCHEMA_FORM_STYLE: CSSProperties = {\n display: 'grid',\n gap: 14,\n};\n\nconst ADVANCED_SCHEMA_ROW_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'block',\n width: '100%',\n};\n\nconst ADVANCED_SCHEMA_VALUE_STYLE: CSSProperties = {\n minWidth: 0,\n width: '100%',\n};\n\nconst ADVANCED_SCHEMA_MESSAGE_STYLE: CSSProperties = {\n gridColumn: '2 / -1',\n};\n\nconst CONDITION_RULE_CONTROL_STYLE: CSSProperties = {\n display: 'grid',\n gap: 10,\n width: '100%',\n};\n\nconst CONDITION_RULE_GRID_STYLE: CSSProperties = {\n display: 'grid',\n gap: 8,\n gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))',\n};\n\nconst DRAG_HANDLE_STYLE: CSSProperties = {\n display: 'inline-flex',\n};\n\nconst WORKBENCH_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\nconst COMPACT_STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 8,\n};\n\nconst OPTION_ACTIONS_STYLE: CSSProperties = {\n display: 'flex',\n justifyContent: 'flex-end',\n};\n\nconst REQUIRED_ASTERISK_STYLE: CSSProperties = {\n color: 'var(--mzn-color-text-error)',\n fontSize: '0.72em',\n lineHeight: 0,\n marginLeft: 2,\n verticalAlign: 'super',\n};\n\nfunction applyFullWidthTextareaHost(element: HTMLDivElement | null): void {\n if (!element) {\n return;\n }\n\n element.style.width = '100%';\n}\n\nconst EMPTY_SCHEMA: FormDefinitionSchema = {\n fields: [],\n schemaVersion: 1,\n};\n\nconst EMPTY_UI_SCHEMA: FormUiSchema = {\n layout: [],\n schemaVersion: 1,\n};\n\nconst BOOLEAN_DEFAULT_OPTIONS: readonly {\n readonly id: string;\n readonly name: string;\n}[] = [\n { id: 'unset', name: '不預設' },\n { id: 'true', name: '是' },\n { id: 'false', name: '否' },\n];\n\nconst BOOLEAN_CONDITION_VALUE_OPTIONS: readonly {\n readonly id: string;\n readonly name: string;\n}[] = [\n { id: 'true', name: '是' },\n { id: 'false', name: '否' },\n];\n\nconst CONDITION_RULE_CONFIGS: readonly ConditionRuleConfig[] = [\n {\n label: '顯示',\n name: 'fieldVisibleWhen',\n supportingText: '符合條件時才顯示這個欄位。',\n target: 'visibleWhen',\n },\n {\n label: '必填',\n name: 'fieldRequiredWhen',\n supportingText: '符合條件時才要求填寫這個欄位。',\n target: 'requiredWhen',\n },\n {\n label: '唯讀',\n name: 'fieldReadonlyWhen',\n supportingText: '符合條件時不允許修改這個欄位。',\n target: 'readonlyWhen',\n },\n];\n\nexport interface FormBuilderViewProps {\n /**\n * Initial (or controlled) schema value.\n * If omitted, the builder starts with empty schema / uiSchema.\n */\n readonly value?: {\n readonly schema: FormDefinitionSchema;\n readonly uiSchema: FormUiSchema;\n };\n\n /** Called whenever the schema or uiSchema changes. */\n readonly onChange?: (next: {\n readonly schema: FormDefinitionSchema;\n readonly uiSchema: FormUiSchema;\n }) => void;\n}\n\nexport function FormBuilderView({\n onChange,\n value,\n}: FormBuilderViewProps): ReactElement {\n const initialSchema = value?.schema ?? EMPTY_SCHEMA;\n const initialUiSchema = value?.uiSchema ?? EMPTY_UI_SCHEMA;\n const [schema, setSchema] = useState<FormDefinitionSchema>(initialSchema);\n const [uiSchema, setUiSchema] = useState<FormUiSchema>(initialUiSchema);\n const [schemaJsonText, setSchemaJsonText] = useState(\n stringifyJson(initialSchema),\n );\n const [uiSchemaJsonText, setUiSchemaJsonText] = useState(\n stringifyJson(initialUiSchema),\n );\n const [previewValues, setPreviewValues] = useState<FormRendererValues>({});\n const [advancedSchemaMessage, setAdvancedSchemaMessage] = useState<\n string | null\n >(null);\n const [activeTab, setActiveTab] = useState<BuilderTabKey>('design');\n const [selectedFieldKey, setSelectedFieldKey] = useState<string | null>(null);\n useEffect((): void => {\n const hasSelectedField = schema.fields.some(\n (field) => field.fieldKey === selectedFieldKey,\n );\n\n if (hasSelectedField) {\n return;\n }\n\n setSelectedFieldKey(schema.fields[0]?.fieldKey ?? null);\n }, [schema.fields, selectedFieldKey]);\n\n useEffect((): void => {\n setPreviewValues((currentValues) =>\n buildFormRendererValues(schema.fields, currentValues),\n );\n }, [schema.fields]);\n\n useEffect((): void => {\n if (activeTab === 'advanced') {\n return;\n }\n\n setSchemaJsonText(stringifyJson(schema));\n setUiSchemaJsonText(stringifyJson(uiSchema));\n }, [activeTab, schema, uiSchema]);\n\n const selectedField = useMemo(\n (): FormFieldDefinition | null =>\n schema.fields.find((field) => field.fieldKey === selectedFieldKey) ??\n schema.fields[0] ??\n null,\n [schema.fields, selectedFieldKey],\n );\n useEffect((): void => {\n onChange?.({ schema, uiSchema });\n }, [schema, uiSchema]);\n\n function handleAddField(type: FieldType): void {\n const nextIndex = schema.fields.length + 1;\n const field = createFieldDefinition(type, nextIndex);\n\n setSchema({\n ...schema,\n fields: [...schema.fields, field],\n });\n setUiSchema({\n ...uiSchema,\n layout: [\n ...uiSchema.layout,\n {\n fieldKey: field.fieldKey,\n width:\n type === 'textarea' || type === 'file_upload' ? 'FULL' : 'HALF',\n },\n ],\n });\n setSelectedFieldKey(field.fieldKey);\n setActiveTab('design');\n setAdvancedSchemaMessage(null);\n }\n\n function handleTabChange(activeKey: Key): void {\n const nextTab = activeKey as BuilderTabKey;\n\n if (nextTab === 'advanced' && activeTab !== 'advanced') {\n setSchemaJsonText(stringifyJson(schema));\n setUiSchemaJsonText(stringifyJson(uiSchema));\n }\n\n setActiveTab(nextTab);\n }\n\n function handleRemoveField(fieldKey: string): void {\n const remainingFields = schema.fields.filter(\n (field) => field.fieldKey !== fieldKey,\n );\n\n setSchema({\n ...schema,\n fields: remainingFields,\n });\n setUiSchema({\n ...uiSchema,\n layout: uiSchema.layout.filter((item) => item.fieldKey !== fieldKey),\n });\n setSelectedFieldKey(\n selectedFieldKey === fieldKey\n ? (remainingFields[0]?.fieldKey ?? null)\n : selectedFieldKey,\n );\n setAdvancedSchemaMessage(null);\n }\n\n function handleFieldDragEnd(result: DropResult): void {\n const destination = result.destination;\n\n if (!destination) {\n return;\n }\n\n if (result.source.index === destination.index) {\n return;\n }\n\n setSchema((currentSchema) => ({\n ...currentSchema,\n fields: moveItemByIndex(\n currentSchema.fields,\n result.source.index,\n destination.index,\n ),\n }));\n setUiSchema((currentUiSchema) => ({\n ...currentUiSchema,\n layout: moveItemByIndex(\n currentUiSchema.layout,\n result.source.index,\n destination.index,\n ),\n }));\n setAdvancedSchemaMessage(null);\n }\n\n function updateSelectedField(\n patch: Partial<\n Pick<\n FormFieldDefinition,\n | 'defaultValue'\n | 'fieldKey'\n | 'label'\n | 'placeholder'\n | 'readonlyWhen'\n | 'required'\n | 'requiredWhen'\n | 'visibleWhen'\n >\n >,\n ): void {\n updateSelectedFieldWith(\n (field) => ({ ...field, ...patch }) as FormFieldDefinition,\n );\n }\n\n function updateSelectedFieldWith(\n updater: (field: FormFieldDefinition) => FormFieldDefinition,\n ): void {\n if (!selectedField) {\n return;\n }\n\n const previousFieldKey = selectedField.fieldKey;\n const nextField = updater(selectedField);\n const nextFieldKey = nextField.fieldKey;\n\n setSchema({\n ...schema,\n fields: schema.fields.map(\n (field): FormFieldDefinition =>\n field.fieldKey === previousFieldKey ? nextField : field,\n ),\n });\n setUiSchema({\n ...uiSchema,\n layout: uiSchema.layout.map((item) =>\n item.fieldKey === previousFieldKey\n ? { ...item, fieldKey: nextFieldKey }\n : item,\n ),\n });\n setSelectedFieldKey(nextFieldKey);\n setAdvancedSchemaMessage(null);\n }\n\n function updateSelectedTextField(\n patch: Partial<\n Pick<TextFieldDefinition, 'defaultValue' | 'maxLength' | 'minLength'>\n >,\n ): void {\n updateSelectedFieldWith((field) =>\n isTextFieldDefinition(field) ? { ...field, ...patch } : field,\n );\n }\n\n function updateSelectedNumberField(\n patch: Partial<\n Pick<NumberFieldDefinition, 'defaultValue' | 'maximum' | 'minimum'>\n >,\n ): void {\n updateSelectedFieldWith((field) =>\n isNumberFieldDefinition(field) ? { ...field, ...patch } : field,\n );\n }\n\n function updateSelectedDateField(\n patch: Partial<Pick<DateFieldDefinition, 'defaultValue'>>,\n ): void {\n updateSelectedFieldWith((field) =>\n isDateFieldDefinition(field) ? { ...field, ...patch } : field,\n );\n }\n\n function updateSelectedSelectField(\n patch: Partial<Pick<SelectFieldDefinition, 'defaultValue' | 'options'>>,\n ): void {\n updateSelectedFieldWith((field) =>\n isSelectFieldDefinition(field) ? { ...field, ...patch } : field,\n );\n }\n\n function updateSelectedBooleanField(\n patch: Partial<Pick<BooleanFieldDefinition, 'defaultValue'>>,\n ): void {\n updateSelectedFieldWith((field) =>\n field.type === 'boolean' ? { ...field, ...patch } : field,\n );\n }\n\n function updateSelectedFileUploadField(\n patch: Partial<\n Pick<\n FileUploadFieldDefinition,\n 'acceptedMimeTypes' | 'defaultValue' | 'maxFiles'\n >\n >,\n ): void {\n updateSelectedFieldWith((field) =>\n field.type === 'file_upload' ? { ...field, ...patch } : field,\n );\n }\n\n function updatePreviewValues(values: FormRendererValues): void {\n setPreviewValues(values);\n }\n\n function updateFieldRequired(fieldKey: string, required: boolean): void {\n setSchema((currentSchema) => ({\n ...currentSchema,\n fields: currentSchema.fields.map(\n (field): FormFieldDefinition =>\n field.fieldKey === fieldKey\n ? ({ ...field, required } as FormFieldDefinition)\n : field,\n ),\n }));\n setAdvancedSchemaMessage(null);\n }\n\n function updateSchemaJson(value: string): void {\n setSchemaJsonText(value);\n\n try {\n setSchema(JSON.parse(value) as FormDefinitionSchema);\n setAdvancedSchemaMessage(null);\n } catch {\n setAdvancedSchemaMessage('Form Schema JSON 格式不正確');\n }\n }\n\n function updateUiSchemaJson(value: string): void {\n setUiSchemaJsonText(value);\n\n try {\n setUiSchema(JSON.parse(value) as FormUiSchema);\n setAdvancedSchemaMessage(null);\n } catch {\n setAdvancedSchemaMessage('UI Schema JSON 格式不正確');\n }\n }\n\n return (\n <>\n <>\n <SectionGroup>\n <Section>\n <div style={WORKBENCH_STYLE}>\n <Tab\n activeKey={activeTab}\n onChange={handleTabChange}\n size=\"sub\"\n >\n <TabItem key=\"design\">設計</TabItem>\n <TabItem key=\"preview\">預覽</TabItem>\n <TabItem key=\"advanced\">進階</TabItem>\n </Tab>\n\n {activeTab === 'design' ? renderDesignTab() : null}\n {activeTab === 'preview' ? renderPreviewTab() : null}\n {activeTab === 'advanced' ? renderAdvancedTab() : null}\n </div>\n </Section>\n </SectionGroup>\n </>\n\n </>\n );\n\n function renderDesignTab(): ReactElement {\n return (\n <div style={STACK_STYLE}>\n <div style={FIELD_LIBRARY_HEADER_STYLE}>\n <Typography component=\"h2\" variant=\"label-primary\">\n 新增欄位\n </Typography>\n <div style={FIELD_LIBRARY_STYLE}>\n {FIELD_TYPE_OPTIONS.map((option) => (\n <Button\n icon={option.icon}\n iconType=\"leading\"\n key={option.type}\n onClick={(): void => handleAddField(option.type)}\n size=\"sub\"\n style={FIELD_LIBRARY_BUTTON_STYLE}\n type=\"button\"\n variant=\"base-secondary\"\n >\n {option.label}\n </Button>\n ))}\n </div>\n </div>\n\n <div style={WORKSPACE_GRID_STYLE}>\n <div style={{ ...STACK_STYLE, ...CANVAS_COLUMN_STYLE }}>\n <Typography component=\"h2\" variant=\"label-primary\">\n 表單畫布\n </Typography>\n {schema.fields.length > 0 ? (\n <DragDropContext onDragEnd={handleFieldDragEnd}>\n <Droppable droppableId=\"form-builder-fields\">\n {(droppableProvided): ReactElement => (\n <div\n {...droppableProvided.droppableProps}\n ref={droppableProvided.innerRef}\n style={STACK_STYLE}\n >\n {schema.fields.map((field, index) => (\n <Draggable\n draggableId={field.fieldKey}\n index={index}\n key={field.fieldKey}\n >\n {(draggableProvided, snapshot): ReactElement =>\n renderFieldBlock(\n field,\n draggableProvided,\n snapshot.isDragging,\n )\n }\n </Draggable>\n ))}\n {droppableProvided.placeholder}\n </div>\n )}\n </Droppable>\n </DragDropContext>\n ) : (\n <div style={EMPTY_CANVAS_STYLE}>\n <div style={STACK_STYLE}>\n <Typography component=\"h3\" variant=\"h3\">\n 尚未建立欄位\n </Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n 從上方新增第一個欄位,或直接建立常用文字欄位開始設計。\n </Typography>\n </div>\n <div style={EMPTY_CANVAS_ACTIONS_STYLE}>\n <Button\n onClick={(): void => handleAddField('text')}\n variant=\"base-primary\"\n >\n 新增文字欄位\n </Button>\n <Button\n onClick={(): void => handleAddField('textarea')}\n variant=\"base-secondary\"\n >\n 新增長文字\n </Button>\n </div>\n </div>\n )}\n </div>\n\n <div style={{ ...STACK_STYLE, ...SETTINGS_COLUMN_STYLE }}>\n <Typography component=\"h2\" variant=\"label-primary\">\n 欄位設定\n </Typography>\n {selectedField ? (\n renderFieldSettings(selectedField)\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 請先新增或選取欄位。\n </Typography>\n )}\n </div>\n </div>\n </div>\n );\n }\n\n function renderFieldSettings(field: FormFieldDefinition): ReactElement {\n return (\n <div style={FIELD_SETTINGS_FORM_STYLE}>\n {renderMainFieldSettings(field)}\n {renderAdvancedFieldSettings(field)}\n </div>\n );\n }\n\n function renderMainFieldSettings(field: FormFieldDefinition): ReactElement {\n return (\n <div style={FIELD_SETTINGS_SECTION_STYLE}>\n <div style={FIELD_SETTINGS_BADGE_ROW_STYLE}>\n <Badge\n size=\"main\"\n text={readFieldTypeLabel(field.type)}\n variant=\"text-info\"\n />\n </div>\n {renderSettingsFormRow(\n '標題',\n 'fieldLabel',\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedField({ label: event.target.value })\n }\n placeholder=\"例如:申請金額\"\n value={field.label}\n variant=\"base\"\n />,\n )}\n {renderSettingsFormRow(\n '欄位 Key',\n 'fieldKey',\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedField({ fieldKey: event.target.value })\n }\n placeholder=\"例如:amount\"\n value={field.fieldKey}\n variant=\"base\"\n />,\n )}\n {renderSettingsFormRow(\n '提示文字',\n 'fieldPlaceholder',\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedField({\n placeholder: event.target.value || undefined,\n })\n }\n placeholder=\"例如:請輸入申請金額\"\n value={field.placeholder ?? ''}\n variant=\"base\"\n />,\n )}\n {renderTypeSpecificSettings(field)}\n </div>\n );\n }\n\n function renderAdvancedFieldSettings(\n field: FormFieldDefinition,\n ): ReactElement {\n return (\n <Accordion\n defaultExpanded={hasConditionRules(field)}\n size=\"sub\"\n title=\"進階設定\"\n >\n <div style={FIELD_SETTINGS_SECTION_STYLE}>\n <Typography\n component=\"h3\"\n style={FIELD_SETTINGS_SECTION_TITLE_STYLE}\n variant=\"label-primary\"\n >\n 條件規則\n </Typography>\n <Typography\n color=\"text-neutral\"\n style={FIELD_SETTINGS_HINT_STYLE}\n variant=\"body\"\n >\n 只有需要根據其他欄位改變顯示、必填或唯讀狀態時才需要設定。\n </Typography>\n {renderConditionSettings(field)}\n </div>\n </Accordion>\n );\n }\n\n function renderTypeSpecificSettings(\n field: FormFieldDefinition,\n ): ReactElement {\n if (isTextFieldDefinition(field)) {\n return renderTextFieldSettings(field);\n }\n\n if (isNumberFieldDefinition(field)) {\n return renderNumberFieldSettings(field);\n }\n\n if (isDateFieldDefinition(field)) {\n return renderDateFieldSettings(field);\n }\n\n if (isSelectFieldDefinition(field)) {\n return renderSelectFieldSettings(field);\n }\n\n if (field.type === 'boolean') {\n return renderBooleanFieldSettings(field);\n }\n\n return renderFileUploadFieldSettings(field);\n }\n\n function renderTextFieldSettings(field: TextFieldDefinition): ReactElement {\n return (\n <>\n {renderSettingsFormRow(\n '預設值',\n 'fieldDefaultValue',\n field.type === 'textarea' ? (\n renderSettingsTextarea({\n name: 'fieldDefaultValue',\n onChange: (value): void =>\n updateSelectedTextField({ defaultValue: value || undefined }),\n placeholder: '輸入此欄位的預設文字',\n rows: 3,\n value: readStringDefaultValue(field.defaultValue),\n })\n ) : (\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedTextField({\n defaultValue: event.target.value || undefined,\n })\n }\n placeholder=\"輸入此欄位的預設文字\"\n value={readStringDefaultValue(field.defaultValue)}\n variant=\"base\"\n />\n ),\n )}\n {renderSettingsFormRow(\n '最小長度',\n 'fieldMinLength',\n renderNumberInput(\n field.minLength,\n (value): void => updateSelectedTextField({ minLength: value }),\n '例如:2',\n { min: 0 },\n ),\n )}\n {renderSettingsFormRow(\n '最大長度',\n 'fieldMaxLength',\n renderNumberInput(\n field.maxLength,\n (value): void => updateSelectedTextField({ maxLength: value }),\n '例如:100',\n { min: 1 },\n ),\n )}\n </>\n );\n }\n\n function renderNumberFieldSettings(\n field: NumberFieldDefinition,\n ): ReactElement {\n return (\n <>\n {renderSettingsFormRow(\n '預設值',\n 'fieldDefaultValue',\n renderNumberInput(\n typeof field.defaultValue === 'number'\n ? field.defaultValue\n : undefined,\n (value): void => updateSelectedNumberField({ defaultValue: value }),\n field.type === 'money' ? '例如:1000' : '輸入預設數值',\n { max: field.maximum, min: field.minimum },\n ),\n )}\n {renderSettingsFormRow(\n '最小值',\n 'fieldMinimum',\n renderNumberInput(\n field.minimum,\n (value): void => updateSelectedNumberField({ minimum: value }),\n '例如:0',\n ),\n )}\n {renderSettingsFormRow(\n '最大值',\n 'fieldMaximum',\n renderNumberInput(\n field.maximum,\n (value): void => updateSelectedNumberField({ maximum: value }),\n '例如:999999',\n ),\n )}\n </>\n );\n }\n\n function renderDateFieldSettings(field: DateFieldDefinition): ReactElement {\n return renderSettingsFormRow(\n '預設值',\n 'fieldDefaultValue',\n renderDateValuePicker(\n field,\n readStringDefaultValue(field.defaultValue),\n (value): void => updateSelectedDateField({ defaultValue: value }),\n ),\n );\n }\n\n function renderSelectFieldSettings(\n field: SelectFieldDefinition,\n ): ReactElement {\n const defaultValues = Array.isArray(field.defaultValue)\n ? field.defaultValue\n : [];\n const selectedValues = field.options\n .filter((option) => defaultValues.includes(option.value))\n .map(readFieldOptionAsSelectOption);\n\n return (\n <>\n {renderSettingsFormRow(\n '預設值',\n 'fieldDefaultValue',\n field.type === 'checkbox' ? (\n <Select\n clearable\n mode=\"multiple\"\n onChange={(options): void =>\n updateSelectedSelectField({\n defaultValue: options.length\n ? options.map((option) => option.id)\n : undefined,\n })\n }\n options={field.options.map(readFieldOptionAsSelectOption)}\n placeholder=\"選擇一或多個預設選項\"\n value={selectedValues}\n />\n ) : (\n <Select\n clearable\n onChange={(option): void =>\n updateSelectedSelectField({\n defaultValue: option?.id || undefined,\n })\n }\n options={field.options.map(readFieldOptionAsSelectOption)}\n placeholder=\"選擇預設選項\"\n value={\n typeof field.defaultValue === 'string'\n ? readSelectOption(\n field.options.map(readFieldOptionAsSelectOption),\n field.defaultValue,\n )\n : null\n }\n />\n ),\n )}\n {renderSettingsFormRow(\n '選項',\n 'fieldOptions',\n renderFieldOptionsTable(field),\n true,\n )}\n </>\n );\n }\n\n function renderBooleanFieldSettings(\n field: BooleanFieldDefinition,\n ): ReactElement {\n const defaultValue =\n typeof field.defaultValue === 'boolean'\n ? String(field.defaultValue)\n : 'unset';\n\n return renderSettingsFormRow(\n '預設值',\n 'fieldDefaultValue',\n <Select\n clearable={false}\n onChange={(option): void =>\n updateSelectedBooleanField({\n defaultValue:\n option?.id === 'true'\n ? true\n : option?.id === 'false'\n ? false\n : undefined,\n })\n }\n options={[...BOOLEAN_DEFAULT_OPTIONS]}\n placeholder=\"選擇預設狀態\"\n value={readSelectOption(BOOLEAN_DEFAULT_OPTIONS, defaultValue)}\n />,\n );\n }\n\n function renderFileUploadFieldSettings(\n field: FileUploadFieldDefinition,\n ): ReactElement {\n return (\n <>\n {renderSettingsFormRow(\n '檔案數',\n 'fieldMaxFiles',\n renderNumberInput(\n field.maxFiles,\n (value): void => updateSelectedFileUploadField({ maxFiles: value }),\n '例如:1',\n { min: 1 },\n ),\n )}\n {renderSettingsFormRow(\n 'MIME',\n 'fieldAcceptedMimeTypes',\n renderSettingsTextarea({\n name: 'fieldAcceptedMimeTypes',\n onChange: (value): void =>\n updateSelectedFileUploadField({\n acceptedMimeTypes: parseStringList(value),\n }),\n placeholder: '每行一個 MIME type,例如:application/pdf',\n rows: 3,\n value: readStringListInput(field.acceptedMimeTypes),\n }),\n false,\n )}\n </>\n );\n }\n\n function renderConditionSettings(field: FormFieldDefinition): ReactElement {\n const conditionFieldOptions = schema.fields.filter(\n (schemaField) => schemaField.fieldKey !== field.fieldKey,\n );\n\n if (!conditionFieldOptions.length) {\n return (\n <Typography\n color=\"text-neutral\"\n style={FIELD_SETTINGS_HINT_STYLE}\n variant=\"body\"\n >\n 目前沒有其他欄位可作為條件來源。新增更多欄位後即可設定條件規則。\n </Typography>\n );\n }\n\n return (\n <>\n {CONDITION_RULE_CONFIGS.map((config) =>\n renderConditionRule(field, config, conditionFieldOptions),\n )}\n </>\n );\n }\n\n function renderConditionRule(\n field: FormFieldDefinition,\n config: ConditionRuleConfig,\n conditionFieldOptions: readonly FormFieldDefinition[],\n ): ReactElement {\n const expression = field[config.target];\n const parsedRule = expression ? parseConditionRule(expression) : null;\n const parsedConditionField = conditionFieldOptions.find(\n (conditionField) => conditionField.fieldKey === parsedRule?.fieldKey,\n );\n const selectedConditionField =\n parsedConditionField ?? conditionFieldOptions[0];\n const conditionFieldSelectOptions = conditionFieldOptions.map(\n readFieldAsConditionSelectOption,\n );\n const conditionOperatorOptions = readConditionOperatorOptions(\n selectedConditionField,\n );\n const selectedOperator =\n parsedRule &&\n conditionOperatorOptions.some(\n (option) => option.id === parsedRule.operator,\n )\n ? parsedRule.operator\n : readDefaultConditionOperator(selectedConditionField);\n const selectedValue =\n parsedRule?.value ?? readDefaultConditionValue(selectedConditionField);\n const enabled = Boolean(expression);\n const unsupportedRule = enabled && (!parsedRule || !parsedConditionField);\n\n return renderSettingsFormRow(\n config.label,\n config.name,\n <div style={CONDITION_RULE_CONTROL_STYLE}>\n <Toggle\n checked={enabled}\n label={enabled ? '已啟用' : '不啟用'}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedConditionRule(\n config.target,\n event.target.checked\n ? buildConditionExpression(\n selectedConditionField,\n readDefaultConditionOperator(selectedConditionField),\n readDefaultConditionValue(selectedConditionField),\n )\n : undefined,\n )\n }\n size=\"sub\"\n supportingText={config.supportingText}\n />\n {enabled ? (\n unsupportedRule ? (\n <Typography color=\"text-warning\" variant=\"body\">\n 這個規則不是目前 UI 支援的格式。重新選擇條件後會取代既有規則。\n </Typography>\n ) : (\n <div style={CONDITION_RULE_GRID_STYLE}>\n <Select\n clearable={false}\n onChange={(option): void => {\n const nextField =\n conditionFieldOptions.find(\n (conditionField) =>\n conditionField.fieldKey === option?.id,\n ) ?? selectedConditionField;\n\n updateSelectedConditionRule(\n config.target,\n buildConditionExpression(\n nextField,\n readDefaultConditionOperator(nextField),\n readDefaultConditionValue(nextField),\n ),\n );\n }}\n options={conditionFieldSelectOptions}\n placeholder=\"選擇欄位\"\n value={readSelectOption(\n conditionFieldSelectOptions,\n selectedConditionField.fieldKey,\n )}\n />\n <Select\n clearable={false}\n onChange={(option): void =>\n updateSelectedConditionRule(\n config.target,\n buildConditionExpression(\n selectedConditionField,\n readConditionOperatorOption(option?.id) ??\n selectedOperator,\n selectedValue,\n ),\n )\n }\n options={[...conditionOperatorOptions]}\n placeholder=\"判斷方式\"\n value={readSelectOption(\n conditionOperatorOptions,\n selectedOperator,\n )}\n />\n {renderConditionValueControl(\n selectedConditionField,\n selectedValue,\n (nextValue): void =>\n updateSelectedConditionRule(\n config.target,\n buildConditionExpression(\n selectedConditionField,\n selectedOperator,\n nextValue,\n ),\n ),\n )}\n </div>\n )\n ) : null}\n </div>,\n true,\n );\n }\n\n function updateSelectedConditionRule(\n target: ConditionRuleTarget,\n expression: string | undefined,\n ): void {\n updateSelectedField({ [target]: expression });\n }\n\n function renderConditionValueControl(\n conditionField: FormFieldDefinition,\n value: string,\n onChange: (value: string) => void,\n ): ReactElement {\n if (conditionField.type === 'boolean') {\n return (\n <Select\n clearable={false}\n onChange={(option): void => onChange(option?.id ?? 'true')}\n options={[...BOOLEAN_CONDITION_VALUE_OPTIONS]}\n placeholder=\"比較值\"\n value={readSelectOption(\n BOOLEAN_CONDITION_VALUE_OPTIONS,\n value === 'false' ? 'false' : 'true',\n )}\n />\n );\n }\n\n if (isSelectFieldDefinition(conditionField)) {\n const options = conditionField.options.map(readFieldOptionAsSelectOption);\n\n return (\n <Select\n clearable={false}\n onChange={(option): void =>\n onChange(option?.id ?? options[0]?.id ?? '')\n }\n options={options}\n placeholder=\"比較值\"\n value={readSelectOption(options, value)}\n />\n );\n }\n\n if (isNumberFieldDefinition(conditionField)) {\n return renderNumberInput(\n parseOptionalNumberInput(value),\n (nextValue): void => onChange(String(nextValue ?? 0)),\n '比較值',\n );\n }\n\n if (isDateFieldDefinition(conditionField)) {\n return renderDateValuePicker(conditionField, value, (nextValue): void =>\n onChange(nextValue ?? ''),\n );\n }\n\n return (\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(event.target.value)\n }\n placeholder=\"比較值\"\n value={value}\n variant=\"base\"\n />\n );\n }\n\n function renderSettingsTextarea({\n name,\n onChange,\n placeholder,\n rows,\n value,\n }: {\n readonly name: string;\n readonly onChange: (value: string) => void;\n readonly placeholder: string;\n readonly rows: number;\n readonly value: string;\n }): ReactElement {\n return (\n <Textarea\n aria-label={name}\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void =>\n onChange(event.target.value)\n }\n placeholder={placeholder}\n ref={applyFullWidthTextareaHost}\n resize=\"vertical\"\n rows={rows}\n style={FIELD_SETTINGS_TEXTAREA_STYLE}\n value={value}\n />\n );\n }\n\n function renderNumberInput(\n value: number | undefined,\n onChange: (value: number | undefined) => void,\n placeholder: string,\n options: {\n readonly max?: number;\n readonly min?: number;\n readonly step?: number;\n } = {},\n ): ReactElement {\n return (\n <Input\n max={options.max}\n min={options.min}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(\n clampOptionalNumber(\n parseOptionalNumberInput(event.target.value),\n options,\n ),\n )\n }\n placeholder={placeholder}\n showSpinner\n step={options.step ?? 1}\n value={typeof value === 'number' ? String(value) : ''}\n variant=\"measure\"\n />\n );\n }\n\n function renderDateValuePicker(\n field: DateFieldDefinition,\n value: string,\n onChange: (value: string | undefined) => void,\n ): ReactElement {\n if (field.type === 'datetime') {\n return (\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n hideSecond\n onChange={(nextValue): void =>\n onChange(formatDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"選擇日期\"\n placeholderRight=\"選擇時間\"\n value={readDatePickerValue(value)}\n />\n );\n }\n\n return (\n <DatePicker\n format=\"YYYY-MM-DD\"\n onChange={(nextValue): void =>\n onChange(formatDatePickerValue(nextValue))\n }\n placeholder=\"選擇日期\"\n value={readDatePickerValue(value)}\n />\n );\n }\n\n function renderFieldOptionsTable(field: SelectFieldDefinition): ReactElement {\n const optionRows: FieldOptionRow[] = field.options.map((option, index) => ({\n index,\n key: `${field.fieldKey}-${index}`,\n label: option.label,\n value: option.value,\n }));\n const optionColumns: TableColumn<FieldOptionRow>[] = [\n {\n key: 'label',\n render: (row): ReactElement => (\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedSelectField({\n options: updateFieldOption(field.options, row.index, {\n label: event.target.value,\n }),\n })\n }\n placeholder=\"例如:主管\"\n size=\"sub\"\n value={row.label}\n variant=\"base\"\n />\n ),\n title: 'Label',\n },\n {\n key: 'value',\n render: (row): ReactElement => (\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedSelectField({\n options: updateFieldOption(field.options, row.index, {\n value: event.target.value,\n }),\n })\n }\n placeholder=\"例如:manager\"\n size=\"sub\"\n value={row.value}\n variant=\"base\"\n />\n ),\n title: 'Value',\n },\n ];\n const optionActions: TableActions<FieldOptionRow> = {\n render: (row): ReturnType<TableActions<FieldOptionRow>['render']> => [\n {\n disabled: (): boolean => field.options.length <= 1,\n icon: TrashIcon,\n iconType: 'icon-only',\n name: '移除選項',\n onClick: (): void =>\n updateSelectedSelectField({\n options: field.options.filter((_, index) => index !== row.index),\n }),\n variant: 'destructive-ghost',\n },\n ],\n width: 56,\n };\n\n return (\n <div style={COMPACT_STACK_STYLE}>\n <Table\n actions={optionActions}\n columns={optionColumns}\n dataSource={optionRows}\n showHeader\n size=\"sub\"\n />\n <div style={OPTION_ACTIONS_STYLE}>\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void =>\n updateSelectedSelectField({\n options: [\n ...field.options,\n createNextFieldOption(field.options),\n ],\n })\n }\n variant=\"base-secondary\"\n >\n 新增選項\n </Button>\n </div>\n </div>\n );\n }\n\n function renderFieldBlock(\n field: FormFieldDefinition,\n draggableProvided: DraggableProvided,\n isDragging: boolean,\n ): ReactElement {\n return (\n <div\n {...draggableProvided.draggableProps}\n data-form-builder-field-key={field.fieldKey}\n ref={draggableProvided.innerRef}\n style={{\n ...FIELD_BLOCK_STYLE,\n ...(isDragging ? FIELD_BLOCK_DRAGGING_STYLE : null),\n ...draggableProvided.draggableProps.style,\n }}\n >\n <BaseCard\n style={\n field.fieldKey === selectedField?.fieldKey\n ? FIELD_BLOCK_SELECTED_CARD_STYLE\n : undefined\n }\n >\n {renderFieldBlockContent(field, draggableProvided, isDragging)}\n </BaseCard>\n </div>\n );\n }\n\n function renderSettingsFormRow(\n label: string,\n name: string,\n control: ReactElement,\n wide = false,\n ): ReactElement {\n return (\n <div\n style={wide ? FIELD_SETTINGS_ROW_WIDE_STYLE : FIELD_SETTINGS_ROW_STYLE}\n >\n <div style={FIELD_SETTINGS_VALUE_STYLE}>\n <BPMFormField label={label} name={name}>\n {control}\n </BPMFormField>\n </div>\n </div>\n );\n }\n\n function renderFieldBlockContent(\n field: FormFieldDefinition,\n draggableProvided: DraggableProvided,\n isDragging: boolean,\n ): ReactElement {\n return (\n <div\n {...(draggableProvided.dragHandleProps ?? {})}\n aria-label=\"選取或拖曳排序欄位\"\n onClick={(): void => setSelectedFieldKey(field.fieldKey)}\n style={FIELD_BLOCK_ROW_STYLE}\n title=\"點擊選取,拖曳排序\"\n >\n <span\n aria-label=\"拖曳排序\"\n role=\"img\"\n style={DRAG_HANDLE_STYLE}\n title=\"拖曳排序\"\n >\n <Icon icon={DotDragVerticalIcon} size={20} />\n </span>\n <div style={FIELD_BLOCK_TEXT_STYLE}>\n <Typography component=\"span\" ellipsis variant=\"label-primary\">\n {field.label}\n {field.required ? (\n <sup aria-label=\"必填\" style={REQUIRED_ASTERISK_STYLE}>\n *\n </sup>\n ) : null}\n </Typography>\n <Typography\n color=\"text-neutral\"\n component=\"span\"\n ellipsis\n variant=\"caption\"\n >\n {readFieldTypeLabel(field.type)} ·\n {field.required ? ' 必填' : ' 選填'} ·{field.fieldKey}\n </Typography>\n </div>\n <div\n onClick={(event: MouseEvent<HTMLDivElement>): void =>\n event.stopPropagation()\n }\n style={FIELD_BLOCK_ACTIONS_STYLE}\n >\n <div style={FIELD_BLOCK_REQUIRED_STYLE}>\n <Toggle\n checked={Boolean(field.required)}\n disabled={isDragging}\n label=\"必填\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateFieldRequired(field.fieldKey, event.target.checked)\n }\n />\n </div>\n <Button\n disabled={isDragging}\n icon={TrashIcon}\n iconType=\"icon-only\"\n onClick={(): void => handleRemoveField(field.fieldKey)}\n variant=\"destructive-ghost\"\n >\n 移除欄位\n </Button>\n </div>\n </div>\n );\n }\n\n function renderPreviewTab(): ReactElement {\n return (\n <div style={STACK_STYLE}>\n <Typography component=\"h2\" variant=\"h3\">\n 填寫預覽\n </Typography>\n <FormRenderer\n onChange={updatePreviewValues}\n schema={schema}\n uiSchema={uiSchema}\n value={previewValues}\n />\n </div>\n );\n }\n\n function renderAdvancedTab(): ReactElement {\n return (\n <div style={STACK_STYLE}>\n <Typography component=\"h2\" variant=\"h3\">\n Schema\n </Typography>\n <div style={ADVANCED_SCHEMA_FORM_STYLE}>\n {renderAdvancedSchemaRow(\n 'Form Schema',\n 'schemaJson',\n <JsonCodeEditor\n height=\"360px\"\n name=\"schemaJson\"\n onChange={updateSchemaJson}\n placeholder=\"輸入 Form Schema JSON\"\n value={schemaJsonText}\n />,\n )}\n {renderAdvancedSchemaRow(\n 'UI Schema',\n 'uiSchemaJson',\n <JsonCodeEditor\n height=\"240px\"\n name=\"uiSchemaJson\"\n onChange={updateUiSchemaJson}\n placeholder=\"輸入 UI Schema JSON\"\n value={uiSchemaJsonText}\n />,\n )}\n {advancedSchemaMessage ? (\n <Typography\n color=\"text-error\"\n style={ADVANCED_SCHEMA_MESSAGE_STYLE}\n variant=\"body\"\n >\n {advancedSchemaMessage}\n </Typography>\n ) : null}\n </div>\n </div>\n );\n }\n\n function renderAdvancedSchemaRow(\n label: string,\n name: string,\n control: ReactElement,\n ): ReactElement {\n return (\n <div style={ADVANCED_SCHEMA_ROW_STYLE}>\n <div style={ADVANCED_SCHEMA_VALUE_STYLE}>\n <BPMFormField label={label} name={name}>\n {control}\n </BPMFormField>\n </div>\n </div>\n );\n }\n}\n\nfunction readFieldTypeLabel(type: FieldType): string {\n return (\n FIELD_TYPE_OPTIONS.find((option) => option.type === type)?.label ?? type\n );\n}\n\nfunction hasConditionRules(field: FormFieldDefinition): boolean {\n return Boolean(field.visibleWhen || field.requiredWhen || field.readonlyWhen);\n}\n\nfunction readFieldAsConditionSelectOption(field: FormFieldDefinition): {\n readonly id: string;\n readonly name: string;\n} {\n return {\n id: field.fieldKey,\n name: field.label,\n };\n}\n\nfunction isTextFieldDefinition(\n field: FormFieldDefinition,\n): field is TextFieldDefinition {\n return field.type === 'text' || field.type === 'textarea';\n}\n\nfunction readStringDefaultValue(\n value: FormFieldDefinition['defaultValue'],\n): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction parseStringList(value: string): readonly string[] | undefined {\n const values = value\n .split(/[\\n,]/u)\n .map((item) => item.trim())\n .filter(Boolean);\n\n return values.length ? values : undefined;\n}\n\nfunction readStringListInput(value: readonly string[] | undefined): string {\n return value?.join('\\n') ?? '';\n}\n\nfunction stringifyJson(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n\nfunction updateFieldOption(\n options: readonly FormFieldOption[],\n targetIndex: number,\n patch: Partial<FormFieldOption>,\n): readonly FormFieldOption[] {\n return options.map((option, index) =>\n index === targetIndex ? { ...option, ...patch } : option,\n );\n}\n\nfunction createNextFieldOption(\n options: readonly FormFieldOption[],\n): FormFieldOption {\n const nextIndex = options.length + 1;\n\n return {\n label: `選項 ${nextIndex}`,\n value: readNextOptionValue(options, nextIndex),\n };\n}\n\nfunction readNextOptionValue(\n options: readonly FormFieldOption[],\n index: number,\n): string {\n const value = `option_${index}`;\n\n return options.some((option) => option.value === value)\n ? readNextOptionValue(options, index + 1)\n : value;\n}\n\nfunction moveItemByIndex<TItem>(\n items: readonly TItem[],\n sourceIndex: number,\n destinationIndex: number,\n): TItem[] {\n const sourceItem = items[sourceIndex];\n\n if (!sourceItem || sourceIndex === destinationIndex) {\n return [...items];\n }\n\n const remainingItems = items.filter((_, index) => index !== sourceIndex);\n\n return [\n ...remainingItems.slice(0, destinationIndex),\n sourceItem,\n ...remainingItems.slice(destinationIndex),\n ];\n}\n\n"],"mappings":";;;;;;;;;;;;;AAQA,IAAM,KAAuC;CAC3C,YAAY;CACZ,QAAQ;CACR,cAAc;CACd,OAAO;CACP,SAAS;CACT,WAAW;CACX,SAAS;CACT,OAAO;AACT,GAEM,IAA+C;CACnD,GAAK;CACL,EAAW;CACX,EAAW,MAAM;EACf,KAAK;GACH,QAAQ;GACR,cAAc;GACd,UAAU;GACV,OAAO;EACT;EACA,gBAAgB,EACd,SAAS,4CACX;EACA,eAAe;GACb,YACE;GACF,WAAW;EACb;EACA,cAAc,EACZ,OAAO,OACT;EACA,eAAe,EACb,aAAa,4CACf;EACA,gBAAgB,EACd,YACE,wFACJ;CACF,CAAC;AACH,GAEM,IAAa,QACX,OAAO,0BACb;CACE,eACE,kBAAC,OAAD;EAAK,OAAO;YAAuB;CAAgB,CAAA;CAErD,KAAK;AACP,CACF;AAWA,SAAgB,GAAe,EAC7B,cAAW,IACX,WACA,SACA,aACA,gBACA,YACoC;CACpC,OACE,kBAAC,GAAD;EACE,cAAY;EACZ,YAAY;GACV,gBAAgB;GAChB,iBAAiB;GACjB,eAAe;GACf,eAAe;GACf,YAAY;GACZ,qBAAqB;GACrB,2BAA2B;GAC3B,aAAa;GACb,oBAAoB;EACtB;EACA,UAAU,CAAC;EACX,YAAY,CAAC,GAAG,CAAsB;EAC9B;EACR,eAAe;EACL;EACG;EACb,UAAU;EACV,OAAM;EACC;EACP,OAAM;CACP,CAAA;AAEL;;;ACeA,IAAM,KAAiD;CACrD;EACE,aAAa;EACb,MAAM;EACN,OAAO;EACP,MAAM;CACR;CACA;EACE,aAAa;EACb,MAAM;EACN,OAAO;EACP,MAAM;CACR;CACA;EACE,aAAa;EACb,MAAM;EACN,OAAO;EACP,MAAM;CACR;CACA;EACE,aAAa;EACb,MAAM;EACN,OAAO;EACP,MAAM;CACR;CACA;EACE,aAAa;EACb,MAAM;EACN,OAAO;EACP,MAAM;CACR;CACA;EACE,aAAa;EACb,MAAM;EACN,OAAO;EACP,MAAM;CACR;CACA;EACE,aAAa;EACb,MAAM;EACN,OAAO;EACP,MAAM;CACR;CACA;EACE,aAAa;EACb,MAAM;EACN,OAAO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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use client";const e=require("./bpm-form-field-Bc6k4ZEO.cjs");let t=require("react"),n=require("@mezzanine-ui/react"),r=require("react/jsx-runtime"),i=require("@rytass/bpm-core-client/form");var a={alignItems:`start`,display:`grid`,gap:12,gridTemplateColumns:`repeat(12, minmax(0, 1fr))`},o={gridColumn:`1 / -1`},s={alignItems:`start`,display:`grid`,gap:8,minWidth:0},c={minWidth:`100%`,width:`100%`};function l(e){e&&(e.style.width=`100%`)}function u({emptyText:e=`尚未建立欄位。`,errors:c={},maxWidth:l,onChange:u,onUploadAttachment:f,readonly:m=!1,schema:h,singleColumn:g=!1,uiSchema:_,value:v}){let[y,b]=(0,t.useState)(()=>(0,i.buildFormRendererValues)(h.fields,v??{})),x=(0,t.useMemo)(()=>(0,i.buildFormRendererValues)(h.fields,v??y),[y,h.fields,v]),S=(0,t.useRef)(x),C=(0,t.useMemo)(()=>(0,i.readVisibleFormRendererFields)(h,_,x),[h,_,x]);(0,t.useEffect)(()=>{S.current=x},[x]),(0,t.useEffect)(()=>{b(e=>(0,i.buildFormRendererValues)(h.fields,v??e))},[h.fields,v]);function w(e,t){let n={...S.current,[e]:t};S.current=n,v||b(n),u?.(n)}return C.length?(0,r.jsx)(`div`,{style:{...a,...g?{maxWidth:l,width:`100%`}:{}},children:C.map(e=>(0,r.jsx)(d,{field:e,error:c[e.fieldKey]??null,fields:h.fields,onChange:w,onUploadAttachment:f,readonly:m,style:{...s,gridColumn:`span ${g?12:p(e,_)}`},value:x[e.fieldKey],values:x},e.fieldKey))}):(0,r.jsx)(`div`,{style:a,children:(0,r.jsx)(n.Typography,{color:`text-neutral`,style:o,variant:`body`,children:h.fields.length>0?`目前條件下沒有可填寫欄位。`:e})})}function d({error:t,field:a,fields:o,onChange:s,onUploadAttachment:c,readonly:l,style:u,value:d,values:p}){let m=(0,i.isFormRendererFieldRequired)(a,o,p),h=l||(0,i.isFormRendererFieldReadonly)(a,o,p);return(0,r.jsxs)(`div`,{"data-form-field-key":a.fieldKey,style:u,children:[(0,r.jsx)(e.t,{label:a.label,name:a.fieldKey,required:m,children:f(a,d,h,s,c)}),t?(0,r.jsx)(n.Typography,{color:`text-error`,variant:`caption`,children:t}):null]})}function f(e,t,a,o,s){if(e.type===`textarea`)return(0,r.jsx)(n.Textarea,{onChange:t=>o(e.fieldKey,t.target.value),placeholder:e.placeholder??`請輸入多行文字`,readOnly:a,ref:l,rows:3,style:c,value:m(t)});if(e.type===`boolean`)return(0,r.jsx)(n.Toggle,{checked:t===!0,disabled:a,label:`啟用`,onChange:t=>o(e.fieldKey,t.target.checked)});if(e.type===`checkbox`){let s=e.options.map(i.readFieldOptionAsSelectOption);return(0,r.jsx)(n.Select,{mode:`multiple`,onChange:t=>o(e.fieldKey,t.length?t.map(e=>e.id):void 0),options:s,placeholder:e.placeholder??`請選擇一或多個選項`,readOnly:a,value:s.filter(e=>h(t).includes(e.id))})}if(e.type===`select`||e.type===`radio`){let s=e.options.map(i.readFieldOptionAsSelectOption);return(0,r.jsx)(n.Select,{onChange:t=>o(e.fieldKey,t?.id??void 0),options:s,placeholder:e.placeholder??`請選擇`,readOnly:a,value:(0,i.readSelectOption)(s,m(t))})}return e.type===`file_upload`?(0,r.jsx)(n.Upload,{accept:e.acceptedMimeTypes?.join(`,`),disabled:a,maxFiles:e.maxFiles,mode:`button-list`,...(e.maxFiles??1)>1?{multiple:!0}:{},onChange:t=>o(e.fieldKey,t.length?t.map(e=>e.id):void 0),onUpload:async t=>Promise.all(t.map(async t=>({file:t,id:(s?await s(e,t):{id:`${t.name}-${t.lastModified}`}).id,progress:100,status:`done`}))),size:`sub`}):e.type===`date`?(0,r.jsx)(n.DatePicker,{format:`YYYY-MM-DD`,fullWidth:!0,onChange:t=>o(e.fieldKey,(0,i.formatDatePickerValue)(t)),placeholder:e.placeholder??_(e.type),readOnly:a,value:(0,i.readDatePickerValue)(t)}):e.type===`datetime`?(0,r.jsx)(n.DateTimePicker,{formatDate:`YYYY-MM-DD`,formatTime:`HH:mm`,fullWidth:!0,hideSecond:!0,onChange:t=>o(e.fieldKey,(0,i.formatDateTimePickerValue)(t)),placeholderLeft:`選擇日期`,placeholderRight:`選擇時間`,readOnly:a,value:(0,i.readDatePickerValue)(t)}):e.type===`number`||e.type===`money`?(0,r.jsx)(n.Input,{fullWidth:!0,max:e.maximum,min:e.minimum,onChange:t=>o(e.fieldKey,(0,i.clampOptionalNumber)((0,i.parseOptionalNumberInput)(t.target.value),{max:e.maximum,min:e.minimum})),placeholder:e.placeholder??_(e.type),...a?{readonly:!0}:{},showSpinner:!0,value:g(t),variant:`measure`}):(0,r.jsx)(n.Input,{fullWidth:!0,onChange:t=>o(e.fieldKey,t.target.value),placeholder:e.placeholder??_(e.type),...a?{readonly:!0}:{},value:m(t),variant:`base`})}function p(e,t){return{FULL:12,HALF:6,THIRD:4}[t.layout.find(t=>t.fieldKey===e.fieldKey)?.width??`FULL`]}function m(e){return typeof e==`string`?e:``}function h(e){return Array.isArray(e)?e:[]}function g(e){return typeof e==`number`?String(e):``}function _(e){return{boolean:``,checkbox:`請選擇一或多個選項`,date:`請選擇日期`,datetime:`請選擇日期與時間`,file_upload:`請上傳附件`,money:`請輸入金額`,number:`請輸入數字`,radio:`請選擇一個選項`,select:`請選擇一個選項`,text:`請輸入文字`,textarea:`請輸入多行文字`}[e]}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return u}});
|
|
2
|
-
//# sourceMappingURL=FormRendererView-BwVsH2eX.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FormRendererView-BwVsH2eX.cjs","names":[],"sources":["../../src/views/forms/renderer/FormRendererView.tsx"],"sourcesContent":["'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n DatePicker,\n DateTimePicker,\n Input,\n Select,\n Textarea,\n Toggle,\n Typography,\n Upload,\n} from '@mezzanine-ui/react';\nimport type { UploadFile } from '@mezzanine-ui/react/Upload';\nimport {\n FormDefinitionSchema,\n FormFieldDefinition,\n FormFieldValue,\n FormUiSchema,\n} from '@rytass/bpm-core-shared/form';\nimport {\n buildFormRendererValues,\n clampOptionalNumber,\n formatDatePickerValue,\n formatDateTimePickerValue,\n FormRendererValues,\n isFormRendererFieldReadonly,\n isFormRendererFieldRequired,\n parseOptionalNumberInput,\n readDatePickerValue,\n readFieldOptionAsSelectOption,\n readSelectOption,\n readVisibleFormRendererFields,\n} from '@rytass/bpm-core-client/form';\nimport { BPMFormField } from '../../../components/bpm-form-field';\n\nexport interface FormRendererProps {\n readonly emptyText?: string;\n readonly errors?: Readonly<Record<string, string>>;\n readonly maxWidth?: CSSProperties['maxWidth'];\n readonly onChange?: (values: FormRendererValues) => void;\n readonly onUploadAttachment?: (\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>;\n readonly readonly?: boolean;\n readonly schema: FormDefinitionSchema;\n readonly singleColumn?: boolean;\n readonly uiSchema: FormUiSchema;\n readonly value?: FormRendererValues;\n}\n\nconst FORM_RENDERER_GRID_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'grid',\n gap: 12,\n gridTemplateColumns: 'repeat(12, minmax(0, 1fr))',\n};\n\nconst FORM_RENDERER_EMPTY_STYLE: CSSProperties = {\n gridColumn: '1 / -1',\n};\n\nconst FORM_RENDERER_FIELD_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'grid',\n gap: 8,\n minWidth: 0,\n};\n\nconst TEXTAREA_STYLE: CSSProperties = {\n minWidth: '100%',\n width: '100%',\n};\n\nfunction applyFullWidthTextareaHost(element: HTMLDivElement | null): void {\n if (!element) {\n return;\n }\n\n element.style.width = '100%';\n}\n\nexport function FormRenderer({\n emptyText = '尚未建立欄位。',\n errors = {},\n maxWidth,\n onChange,\n onUploadAttachment,\n readonly = false,\n schema,\n singleColumn = false,\n uiSchema,\n value,\n}: FormRendererProps): ReactElement {\n const [internalValues, setInternalValues] = useState<FormRendererValues>(() =>\n buildFormRendererValues(schema.fields, value ?? {}),\n );\n const values = useMemo(\n (): FormRendererValues =>\n buildFormRendererValues(schema.fields, value ?? internalValues),\n [internalValues, schema.fields, value],\n );\n const valuesRef = useRef<FormRendererValues>(values);\n const visibleFields = useMemo(\n (): readonly FormFieldDefinition[] =>\n readVisibleFormRendererFields(schema, uiSchema, values),\n [schema, uiSchema, values],\n );\n\n useEffect((): void => {\n valuesRef.current = values;\n }, [values]);\n\n useEffect((): void => {\n setInternalValues((currentValues) =>\n buildFormRendererValues(schema.fields, value ?? currentValues),\n );\n }, [schema.fields, value]);\n\n function updateValue(\n fieldKey: string,\n nextValue: FormFieldValue | undefined,\n ): void {\n const nextValues = {\n ...valuesRef.current,\n [fieldKey]: nextValue,\n };\n valuesRef.current = nextValues;\n\n if (!value) {\n setInternalValues(nextValues);\n }\n\n onChange?.(nextValues);\n }\n\n if (!visibleFields.length) {\n return (\n <div style={FORM_RENDERER_GRID_STYLE}>\n <Typography\n color=\"text-neutral\"\n style={FORM_RENDERER_EMPTY_STYLE}\n variant=\"body\"\n >\n {schema.fields.length > 0 ? '目前條件下沒有可填寫欄位。' : emptyText}\n </Typography>\n </div>\n );\n }\n\n return (\n <div\n style={{\n ...FORM_RENDERER_GRID_STYLE,\n ...(singleColumn ? { maxWidth, width: '100%' } : {}),\n }}\n >\n {visibleFields.map((field) => (\n <FormRendererField\n field={field}\n error={errors[field.fieldKey] ?? null}\n fields={schema.fields}\n key={field.fieldKey}\n onChange={updateValue}\n onUploadAttachment={onUploadAttachment}\n readonly={readonly}\n style={{\n ...FORM_RENDERER_FIELD_STYLE,\n gridColumn: `span ${\n singleColumn ? 12 : readFieldColumnSpan(field, uiSchema)\n }`,\n }}\n value={values[field.fieldKey]}\n values={values}\n />\n ))}\n </div>\n );\n}\n\nfunction FormRendererField({\n error,\n field,\n fields,\n onChange,\n onUploadAttachment,\n readonly,\n style,\n value,\n values,\n}: {\n readonly error: string | null;\n readonly field: FormFieldDefinition;\n readonly fields: readonly FormFieldDefinition[];\n readonly onChange: (\n fieldKey: string,\n value: FormFieldValue | undefined,\n ) => void;\n readonly onUploadAttachment?:\n | ((\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>)\n | undefined;\n readonly readonly: boolean;\n readonly style: CSSProperties;\n readonly value: FormFieldValue | undefined;\n readonly values: FormRendererValues;\n}): ReactElement {\n const required = isFormRendererFieldRequired(field, fields, values);\n const fieldReadonly =\n readonly || isFormRendererFieldReadonly(field, fields, values);\n\n return (\n <div data-form-field-key={field.fieldKey} style={style}>\n <BPMFormField\n label={field.label}\n name={field.fieldKey}\n required={required}\n >\n {renderControl(\n field,\n value,\n fieldReadonly,\n onChange,\n onUploadAttachment,\n )}\n </BPMFormField>\n {error ? (\n <Typography color=\"text-error\" variant=\"caption\">\n {error}\n </Typography>\n ) : null}\n </div>\n );\n}\n\nfunction renderControl(\n field: FormFieldDefinition,\n value: FormFieldValue | undefined,\n readonly: boolean,\n onChange: (fieldKey: string, value: FormFieldValue | undefined) => void,\n onUploadAttachment:\n | ((\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>)\n | undefined,\n): ReactElement {\n if (field.type === 'textarea') {\n return (\n <Textarea\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void =>\n onChange(field.fieldKey, event.target.value)\n }\n placeholder={field.placeholder ?? '請輸入多行文字'}\n readOnly={readonly}\n ref={applyFullWidthTextareaHost}\n rows={3}\n style={TEXTAREA_STYLE}\n value={readStringValue(value)}\n />\n );\n }\n\n if (field.type === 'boolean') {\n return (\n <Toggle\n checked={value === true}\n disabled={readonly}\n label=\"啟用\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(field.fieldKey, event.target.checked)\n }\n />\n );\n }\n\n if (field.type === 'checkbox') {\n const options = field.options.map(readFieldOptionAsSelectOption);\n\n return (\n <Select\n mode=\"multiple\"\n onChange={(options): void =>\n onChange(\n field.fieldKey,\n options.length ? options.map((option) => option.id) : undefined,\n )\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇一或多個選項'}\n readOnly={readonly}\n value={options.filter((option) =>\n readStringArrayValue(value).includes(option.id),\n )}\n />\n );\n }\n\n if (field.type === 'select' || field.type === 'radio') {\n const options = field.options.map(readFieldOptionAsSelectOption);\n\n return (\n <Select\n onChange={(option): void =>\n onChange(field.fieldKey, option?.id ?? undefined)\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇'}\n readOnly={readonly}\n value={readSelectOption(options, readStringValue(value))}\n />\n );\n }\n\n if (field.type === 'file_upload') {\n return (\n <Upload\n accept={field.acceptedMimeTypes?.join(',')}\n disabled={readonly}\n maxFiles={field.maxFiles}\n mode=\"button-list\"\n {...((field.maxFiles ?? 1) > 1 ? { multiple: true } : {})}\n onChange={(files): void =>\n onChange(\n field.fieldKey,\n files.length ? files.map((file) => file.id) : undefined,\n )\n }\n onUpload={async (files): Promise<UploadFile[]> =>\n Promise.all(\n files.map(async (file): Promise<UploadFile> => {\n const uploadedFile = onUploadAttachment\n ? await onUploadAttachment(field, file)\n : { id: `${file.name}-${file.lastModified}` };\n\n return {\n file,\n id: uploadedFile.id,\n progress: 100,\n status: 'done',\n };\n }),\n )\n }\n size=\"sub\"\n />\n );\n }\n\n if (field.type === 'date') {\n return (\n <DatePicker\n format=\"YYYY-MM-DD\"\n fullWidth\n onChange={(nextValue): void =>\n onChange(field.fieldKey, formatDatePickerValue(nextValue))\n }\n placeholder={field.placeholder ?? readInputPlaceholder(field.type)}\n readOnly={readonly}\n value={readDatePickerValue(value)}\n />\n );\n }\n\n if (field.type === 'datetime') {\n return (\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n fullWidth\n hideSecond\n onChange={(nextValue): void =>\n onChange(field.fieldKey, formatDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"選擇日期\"\n placeholderRight=\"選擇時間\"\n readOnly={readonly}\n value={readDatePickerValue(value)}\n />\n );\n }\n\n if (field.type === 'number' || field.type === 'money') {\n return (\n <Input\n fullWidth\n max={field.maximum}\n min={field.minimum}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(\n field.fieldKey,\n clampOptionalNumber(parseOptionalNumberInput(event.target.value), {\n max: field.maximum,\n min: field.minimum,\n }),\n )\n }\n placeholder={field.placeholder ?? readInputPlaceholder(field.type)}\n {...(readonly ? { readonly: true as const } : {})}\n showSpinner\n value={readNumberInputValue(value)}\n variant=\"measure\"\n />\n );\n }\n\n return (\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(field.fieldKey, event.target.value)\n }\n placeholder={field.placeholder ?? readInputPlaceholder(field.type)}\n {...(readonly ? { readonly: true as const } : {})}\n value={readStringValue(value)}\n variant=\"base\"\n />\n );\n}\n\nfunction readFieldColumnSpan(\n field: FormFieldDefinition,\n uiSchema: FormUiSchema,\n): number {\n const width =\n uiSchema.layout.find((item) => item.fieldKey === field.fieldKey)?.width ??\n 'FULL';\n const spans: Readonly<Record<typeof width, number>> = {\n FULL: 12,\n HALF: 6,\n THIRD: 4,\n };\n\n return spans[width];\n}\n\nfunction readStringValue(value: FormFieldValue | undefined): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction readStringArrayValue(\n value: FormFieldValue | undefined,\n): readonly string[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction readNumberInputValue(value: FormFieldValue | undefined): string {\n return typeof value === 'number' ? String(value) : '';\n}\n\nfunction readInputPlaceholder(type: FormFieldDefinition['type']): string {\n const placeholders: Readonly<Record<FormFieldDefinition['type'], string>> = {\n boolean: '',\n checkbox: '請選擇一或多個選項',\n date: '請選擇日期',\n datetime: '請選擇日期與時間',\n file_upload: '請上傳附件',\n money: '請輸入金額',\n number: '請輸入數字',\n radio: '請選擇一個選項',\n select: '請選擇一個選項',\n text: '請輸入文字',\n textarea: '請輸入多行文字',\n };\n\n return placeholders[type];\n}\n\nexport { FormRenderer as FormRendererView };\n"],"mappings":"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"}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { t as e } from "./bpm-form-field-Cao0rMol.js";
|
|
3
|
-
import { useEffect as t, useMemo as n, useRef as r, useState as i } from "react";
|
|
4
|
-
import { DatePicker as a, DateTimePicker as o, Input as s, Select as c, Textarea as l, Toggle as u, Typography as d, Upload as f } from "@mezzanine-ui/react";
|
|
5
|
-
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
6
|
-
import { buildFormRendererValues as h, clampOptionalNumber as g, formatDatePickerValue as _, formatDateTimePickerValue as v, isFormRendererFieldReadonly as y, isFormRendererFieldRequired as b, parseOptionalNumberInput as x, readDatePickerValue as S, readFieldOptionAsSelectOption as C, readSelectOption as w, readVisibleFormRendererFields as T } from "@rytass/bpm-core-client/form";
|
|
7
|
-
//#region src/views/forms/renderer/FormRendererView.tsx
|
|
8
|
-
var E = {
|
|
9
|
-
alignItems: "start",
|
|
10
|
-
display: "grid",
|
|
11
|
-
gap: 12,
|
|
12
|
-
gridTemplateColumns: "repeat(12, minmax(0, 1fr))"
|
|
13
|
-
}, D = { gridColumn: "1 / -1" }, O = {
|
|
14
|
-
alignItems: "start",
|
|
15
|
-
display: "grid",
|
|
16
|
-
gap: 8,
|
|
17
|
-
minWidth: 0
|
|
18
|
-
}, k = {
|
|
19
|
-
minWidth: "100%",
|
|
20
|
-
width: "100%"
|
|
21
|
-
};
|
|
22
|
-
function A(e) {
|
|
23
|
-
e && (e.style.width = "100%");
|
|
24
|
-
}
|
|
25
|
-
function j({ emptyText: e = "尚未建立欄位。", errors: a = {}, maxWidth: o, onChange: s, onUploadAttachment: c, readonly: l = !1, schema: u, singleColumn: f = !1, uiSchema: m, value: g }) {
|
|
26
|
-
let [_, v] = i(() => h(u.fields, g ?? {})), y = n(() => h(u.fields, g ?? _), [
|
|
27
|
-
_,
|
|
28
|
-
u.fields,
|
|
29
|
-
g
|
|
30
|
-
]), b = r(y), x = n(() => T(u, m, y), [
|
|
31
|
-
u,
|
|
32
|
-
m,
|
|
33
|
-
y
|
|
34
|
-
]);
|
|
35
|
-
t(() => {
|
|
36
|
-
b.current = y;
|
|
37
|
-
}, [y]), t(() => {
|
|
38
|
-
v((e) => h(u.fields, g ?? e));
|
|
39
|
-
}, [u.fields, g]);
|
|
40
|
-
function S(e, t) {
|
|
41
|
-
let n = {
|
|
42
|
-
...b.current,
|
|
43
|
-
[e]: t
|
|
44
|
-
};
|
|
45
|
-
b.current = n, g || v(n), s?.(n);
|
|
46
|
-
}
|
|
47
|
-
return x.length ? /* @__PURE__ */ p("div", {
|
|
48
|
-
style: {
|
|
49
|
-
...E,
|
|
50
|
-
...f ? {
|
|
51
|
-
maxWidth: o,
|
|
52
|
-
width: "100%"
|
|
53
|
-
} : {}
|
|
54
|
-
},
|
|
55
|
-
children: x.map((e) => /* @__PURE__ */ p(M, {
|
|
56
|
-
field: e,
|
|
57
|
-
error: a[e.fieldKey] ?? null,
|
|
58
|
-
fields: u.fields,
|
|
59
|
-
onChange: S,
|
|
60
|
-
onUploadAttachment: c,
|
|
61
|
-
readonly: l,
|
|
62
|
-
style: {
|
|
63
|
-
...O,
|
|
64
|
-
gridColumn: `span ${f ? 12 : P(e, m)}`
|
|
65
|
-
},
|
|
66
|
-
value: y[e.fieldKey],
|
|
67
|
-
values: y
|
|
68
|
-
}, e.fieldKey))
|
|
69
|
-
}) : /* @__PURE__ */ p("div", {
|
|
70
|
-
style: E,
|
|
71
|
-
children: /* @__PURE__ */ p(d, {
|
|
72
|
-
color: "text-neutral",
|
|
73
|
-
style: D,
|
|
74
|
-
variant: "body",
|
|
75
|
-
children: u.fields.length > 0 ? "目前條件下沒有可填寫欄位。" : e
|
|
76
|
-
})
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
function M({ error: t, field: n, fields: r, onChange: i, onUploadAttachment: a, readonly: o, style: s, value: c, values: l }) {
|
|
80
|
-
let u = b(n, r, l), f = o || y(n, r, l);
|
|
81
|
-
return /* @__PURE__ */ m("div", {
|
|
82
|
-
"data-form-field-key": n.fieldKey,
|
|
83
|
-
style: s,
|
|
84
|
-
children: [/* @__PURE__ */ p(e, {
|
|
85
|
-
label: n.label,
|
|
86
|
-
name: n.fieldKey,
|
|
87
|
-
required: u,
|
|
88
|
-
children: N(n, c, f, i, a)
|
|
89
|
-
}), t ? /* @__PURE__ */ p(d, {
|
|
90
|
-
color: "text-error",
|
|
91
|
-
variant: "caption",
|
|
92
|
-
children: t
|
|
93
|
-
}) : null]
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
function N(e, t, n, r, i) {
|
|
97
|
-
if (e.type === "textarea") return /* @__PURE__ */ p(l, {
|
|
98
|
-
onChange: (t) => r(e.fieldKey, t.target.value),
|
|
99
|
-
placeholder: e.placeholder ?? "請輸入多行文字",
|
|
100
|
-
readOnly: n,
|
|
101
|
-
ref: A,
|
|
102
|
-
rows: 3,
|
|
103
|
-
style: k,
|
|
104
|
-
value: F(t)
|
|
105
|
-
});
|
|
106
|
-
if (e.type === "boolean") return /* @__PURE__ */ p(u, {
|
|
107
|
-
checked: t === !0,
|
|
108
|
-
disabled: n,
|
|
109
|
-
label: "啟用",
|
|
110
|
-
onChange: (t) => r(e.fieldKey, t.target.checked)
|
|
111
|
-
});
|
|
112
|
-
if (e.type === "checkbox") {
|
|
113
|
-
let i = e.options.map(C);
|
|
114
|
-
return /* @__PURE__ */ p(c, {
|
|
115
|
-
mode: "multiple",
|
|
116
|
-
onChange: (t) => r(e.fieldKey, t.length ? t.map((e) => e.id) : void 0),
|
|
117
|
-
options: i,
|
|
118
|
-
placeholder: e.placeholder ?? "請選擇一或多個選項",
|
|
119
|
-
readOnly: n,
|
|
120
|
-
value: i.filter((e) => I(t).includes(e.id))
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
if (e.type === "select" || e.type === "radio") {
|
|
124
|
-
let i = e.options.map(C);
|
|
125
|
-
return /* @__PURE__ */ p(c, {
|
|
126
|
-
onChange: (t) => r(e.fieldKey, t?.id ?? void 0),
|
|
127
|
-
options: i,
|
|
128
|
-
placeholder: e.placeholder ?? "請選擇",
|
|
129
|
-
readOnly: n,
|
|
130
|
-
value: w(i, F(t))
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
return e.type === "file_upload" ? /* @__PURE__ */ p(f, {
|
|
134
|
-
accept: e.acceptedMimeTypes?.join(","),
|
|
135
|
-
disabled: n,
|
|
136
|
-
maxFiles: e.maxFiles,
|
|
137
|
-
mode: "button-list",
|
|
138
|
-
...(e.maxFiles ?? 1) > 1 ? { multiple: !0 } : {},
|
|
139
|
-
onChange: (t) => r(e.fieldKey, t.length ? t.map((e) => e.id) : void 0),
|
|
140
|
-
onUpload: async (t) => Promise.all(t.map(async (t) => ({
|
|
141
|
-
file: t,
|
|
142
|
-
id: (i ? await i(e, t) : { id: `${t.name}-${t.lastModified}` }).id,
|
|
143
|
-
progress: 100,
|
|
144
|
-
status: "done"
|
|
145
|
-
}))),
|
|
146
|
-
size: "sub"
|
|
147
|
-
}) : e.type === "date" ? /* @__PURE__ */ p(a, {
|
|
148
|
-
format: "YYYY-MM-DD",
|
|
149
|
-
fullWidth: !0,
|
|
150
|
-
onChange: (t) => r(e.fieldKey, _(t)),
|
|
151
|
-
placeholder: e.placeholder ?? R(e.type),
|
|
152
|
-
readOnly: n,
|
|
153
|
-
value: S(t)
|
|
154
|
-
}) : e.type === "datetime" ? /* @__PURE__ */ p(o, {
|
|
155
|
-
formatDate: "YYYY-MM-DD",
|
|
156
|
-
formatTime: "HH:mm",
|
|
157
|
-
fullWidth: !0,
|
|
158
|
-
hideSecond: !0,
|
|
159
|
-
onChange: (t) => r(e.fieldKey, v(t)),
|
|
160
|
-
placeholderLeft: "選擇日期",
|
|
161
|
-
placeholderRight: "選擇時間",
|
|
162
|
-
readOnly: n,
|
|
163
|
-
value: S(t)
|
|
164
|
-
}) : e.type === "number" || e.type === "money" ? /* @__PURE__ */ p(s, {
|
|
165
|
-
fullWidth: !0,
|
|
166
|
-
max: e.maximum,
|
|
167
|
-
min: e.minimum,
|
|
168
|
-
onChange: (t) => r(e.fieldKey, g(x(t.target.value), {
|
|
169
|
-
max: e.maximum,
|
|
170
|
-
min: e.minimum
|
|
171
|
-
})),
|
|
172
|
-
placeholder: e.placeholder ?? R(e.type),
|
|
173
|
-
...n ? { readonly: !0 } : {},
|
|
174
|
-
showSpinner: !0,
|
|
175
|
-
value: L(t),
|
|
176
|
-
variant: "measure"
|
|
177
|
-
}) : /* @__PURE__ */ p(s, {
|
|
178
|
-
fullWidth: !0,
|
|
179
|
-
onChange: (t) => r(e.fieldKey, t.target.value),
|
|
180
|
-
placeholder: e.placeholder ?? R(e.type),
|
|
181
|
-
...n ? { readonly: !0 } : {},
|
|
182
|
-
value: F(t),
|
|
183
|
-
variant: "base"
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
function P(e, t) {
|
|
187
|
-
return {
|
|
188
|
-
FULL: 12,
|
|
189
|
-
HALF: 6,
|
|
190
|
-
THIRD: 4
|
|
191
|
-
}[t.layout.find((t) => t.fieldKey === e.fieldKey)?.width ?? "FULL"];
|
|
192
|
-
}
|
|
193
|
-
function F(e) {
|
|
194
|
-
return typeof e == "string" ? e : "";
|
|
195
|
-
}
|
|
196
|
-
function I(e) {
|
|
197
|
-
return Array.isArray(e) ? e : [];
|
|
198
|
-
}
|
|
199
|
-
function L(e) {
|
|
200
|
-
return typeof e == "number" ? String(e) : "";
|
|
201
|
-
}
|
|
202
|
-
function R(e) {
|
|
203
|
-
return {
|
|
204
|
-
boolean: "",
|
|
205
|
-
checkbox: "請選擇一或多個選項",
|
|
206
|
-
date: "請選擇日期",
|
|
207
|
-
datetime: "請選擇日期與時間",
|
|
208
|
-
file_upload: "請上傳附件",
|
|
209
|
-
money: "請輸入金額",
|
|
210
|
-
number: "請輸入數字",
|
|
211
|
-
radio: "請選擇一個選項",
|
|
212
|
-
select: "請選擇一個選項",
|
|
213
|
-
text: "請輸入文字",
|
|
214
|
-
textarea: "請輸入多行文字"
|
|
215
|
-
}[e];
|
|
216
|
-
}
|
|
217
|
-
//#endregion
|
|
218
|
-
export { j as t };
|
|
219
|
-
|
|
220
|
-
//# sourceMappingURL=FormRendererView-DrHsuSVo.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FormRendererView-DrHsuSVo.js","names":[],"sources":["../../src/views/forms/renderer/FormRendererView.tsx"],"sourcesContent":["'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n DatePicker,\n DateTimePicker,\n Input,\n Select,\n Textarea,\n Toggle,\n Typography,\n Upload,\n} from '@mezzanine-ui/react';\nimport type { UploadFile } from '@mezzanine-ui/react/Upload';\nimport {\n FormDefinitionSchema,\n FormFieldDefinition,\n FormFieldValue,\n FormUiSchema,\n} from '@rytass/bpm-core-shared/form';\nimport {\n buildFormRendererValues,\n clampOptionalNumber,\n formatDatePickerValue,\n formatDateTimePickerValue,\n FormRendererValues,\n isFormRendererFieldReadonly,\n isFormRendererFieldRequired,\n parseOptionalNumberInput,\n readDatePickerValue,\n readFieldOptionAsSelectOption,\n readSelectOption,\n readVisibleFormRendererFields,\n} from '@rytass/bpm-core-client/form';\nimport { BPMFormField } from '../../../components/bpm-form-field';\n\nexport interface FormRendererProps {\n readonly emptyText?: string;\n readonly errors?: Readonly<Record<string, string>>;\n readonly maxWidth?: CSSProperties['maxWidth'];\n readonly onChange?: (values: FormRendererValues) => void;\n readonly onUploadAttachment?: (\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>;\n readonly readonly?: boolean;\n readonly schema: FormDefinitionSchema;\n readonly singleColumn?: boolean;\n readonly uiSchema: FormUiSchema;\n readonly value?: FormRendererValues;\n}\n\nconst FORM_RENDERER_GRID_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'grid',\n gap: 12,\n gridTemplateColumns: 'repeat(12, minmax(0, 1fr))',\n};\n\nconst FORM_RENDERER_EMPTY_STYLE: CSSProperties = {\n gridColumn: '1 / -1',\n};\n\nconst FORM_RENDERER_FIELD_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'grid',\n gap: 8,\n minWidth: 0,\n};\n\nconst TEXTAREA_STYLE: CSSProperties = {\n minWidth: '100%',\n width: '100%',\n};\n\nfunction applyFullWidthTextareaHost(element: HTMLDivElement | null): void {\n if (!element) {\n return;\n }\n\n element.style.width = '100%';\n}\n\nexport function FormRenderer({\n emptyText = '尚未建立欄位。',\n errors = {},\n maxWidth,\n onChange,\n onUploadAttachment,\n readonly = false,\n schema,\n singleColumn = false,\n uiSchema,\n value,\n}: FormRendererProps): ReactElement {\n const [internalValues, setInternalValues] = useState<FormRendererValues>(() =>\n buildFormRendererValues(schema.fields, value ?? {}),\n );\n const values = useMemo(\n (): FormRendererValues =>\n buildFormRendererValues(schema.fields, value ?? internalValues),\n [internalValues, schema.fields, value],\n );\n const valuesRef = useRef<FormRendererValues>(values);\n const visibleFields = useMemo(\n (): readonly FormFieldDefinition[] =>\n readVisibleFormRendererFields(schema, uiSchema, values),\n [schema, uiSchema, values],\n );\n\n useEffect((): void => {\n valuesRef.current = values;\n }, [values]);\n\n useEffect((): void => {\n setInternalValues((currentValues) =>\n buildFormRendererValues(schema.fields, value ?? currentValues),\n );\n }, [schema.fields, value]);\n\n function updateValue(\n fieldKey: string,\n nextValue: FormFieldValue | undefined,\n ): void {\n const nextValues = {\n ...valuesRef.current,\n [fieldKey]: nextValue,\n };\n valuesRef.current = nextValues;\n\n if (!value) {\n setInternalValues(nextValues);\n }\n\n onChange?.(nextValues);\n }\n\n if (!visibleFields.length) {\n return (\n <div style={FORM_RENDERER_GRID_STYLE}>\n <Typography\n color=\"text-neutral\"\n style={FORM_RENDERER_EMPTY_STYLE}\n variant=\"body\"\n >\n {schema.fields.length > 0 ? '目前條件下沒有可填寫欄位。' : emptyText}\n </Typography>\n </div>\n );\n }\n\n return (\n <div\n style={{\n ...FORM_RENDERER_GRID_STYLE,\n ...(singleColumn ? { maxWidth, width: '100%' } : {}),\n }}\n >\n {visibleFields.map((field) => (\n <FormRendererField\n field={field}\n error={errors[field.fieldKey] ?? null}\n fields={schema.fields}\n key={field.fieldKey}\n onChange={updateValue}\n onUploadAttachment={onUploadAttachment}\n readonly={readonly}\n style={{\n ...FORM_RENDERER_FIELD_STYLE,\n gridColumn: `span ${\n singleColumn ? 12 : readFieldColumnSpan(field, uiSchema)\n }`,\n }}\n value={values[field.fieldKey]}\n values={values}\n />\n ))}\n </div>\n );\n}\n\nfunction FormRendererField({\n error,\n field,\n fields,\n onChange,\n onUploadAttachment,\n readonly,\n style,\n value,\n values,\n}: {\n readonly error: string | null;\n readonly field: FormFieldDefinition;\n readonly fields: readonly FormFieldDefinition[];\n readonly onChange: (\n fieldKey: string,\n value: FormFieldValue | undefined,\n ) => void;\n readonly onUploadAttachment?:\n | ((\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>)\n | undefined;\n readonly readonly: boolean;\n readonly style: CSSProperties;\n readonly value: FormFieldValue | undefined;\n readonly values: FormRendererValues;\n}): ReactElement {\n const required = isFormRendererFieldRequired(field, fields, values);\n const fieldReadonly =\n readonly || isFormRendererFieldReadonly(field, fields, values);\n\n return (\n <div data-form-field-key={field.fieldKey} style={style}>\n <BPMFormField\n label={field.label}\n name={field.fieldKey}\n required={required}\n >\n {renderControl(\n field,\n value,\n fieldReadonly,\n onChange,\n onUploadAttachment,\n )}\n </BPMFormField>\n {error ? (\n <Typography color=\"text-error\" variant=\"caption\">\n {error}\n </Typography>\n ) : null}\n </div>\n );\n}\n\nfunction renderControl(\n field: FormFieldDefinition,\n value: FormFieldValue | undefined,\n readonly: boolean,\n onChange: (fieldKey: string, value: FormFieldValue | undefined) => void,\n onUploadAttachment:\n | ((\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>)\n | undefined,\n): ReactElement {\n if (field.type === 'textarea') {\n return (\n <Textarea\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void =>\n onChange(field.fieldKey, event.target.value)\n }\n placeholder={field.placeholder ?? '請輸入多行文字'}\n readOnly={readonly}\n ref={applyFullWidthTextareaHost}\n rows={3}\n style={TEXTAREA_STYLE}\n value={readStringValue(value)}\n />\n );\n }\n\n if (field.type === 'boolean') {\n return (\n <Toggle\n checked={value === true}\n disabled={readonly}\n label=\"啟用\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(field.fieldKey, event.target.checked)\n }\n />\n );\n }\n\n if (field.type === 'checkbox') {\n const options = field.options.map(readFieldOptionAsSelectOption);\n\n return (\n <Select\n mode=\"multiple\"\n onChange={(options): void =>\n onChange(\n field.fieldKey,\n options.length ? options.map((option) => option.id) : undefined,\n )\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇一或多個選項'}\n readOnly={readonly}\n value={options.filter((option) =>\n readStringArrayValue(value).includes(option.id),\n )}\n />\n );\n }\n\n if (field.type === 'select' || field.type === 'radio') {\n const options = field.options.map(readFieldOptionAsSelectOption);\n\n return (\n <Select\n onChange={(option): void =>\n onChange(field.fieldKey, option?.id ?? undefined)\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇'}\n readOnly={readonly}\n value={readSelectOption(options, readStringValue(value))}\n />\n );\n }\n\n if (field.type === 'file_upload') {\n return (\n <Upload\n accept={field.acceptedMimeTypes?.join(',')}\n disabled={readonly}\n maxFiles={field.maxFiles}\n mode=\"button-list\"\n {...((field.maxFiles ?? 1) > 1 ? { multiple: true } : {})}\n onChange={(files): void =>\n onChange(\n field.fieldKey,\n files.length ? files.map((file) => file.id) : undefined,\n )\n }\n onUpload={async (files): Promise<UploadFile[]> =>\n Promise.all(\n files.map(async (file): Promise<UploadFile> => {\n const uploadedFile = onUploadAttachment\n ? await onUploadAttachment(field, file)\n : { id: `${file.name}-${file.lastModified}` };\n\n return {\n file,\n id: uploadedFile.id,\n progress: 100,\n status: 'done',\n };\n }),\n )\n }\n size=\"sub\"\n />\n );\n }\n\n if (field.type === 'date') {\n return (\n <DatePicker\n format=\"YYYY-MM-DD\"\n fullWidth\n onChange={(nextValue): void =>\n onChange(field.fieldKey, formatDatePickerValue(nextValue))\n }\n placeholder={field.placeholder ?? readInputPlaceholder(field.type)}\n readOnly={readonly}\n value={readDatePickerValue(value)}\n />\n );\n }\n\n if (field.type === 'datetime') {\n return (\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n fullWidth\n hideSecond\n onChange={(nextValue): void =>\n onChange(field.fieldKey, formatDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"選擇日期\"\n placeholderRight=\"選擇時間\"\n readOnly={readonly}\n value={readDatePickerValue(value)}\n />\n );\n }\n\n if (field.type === 'number' || field.type === 'money') {\n return (\n <Input\n fullWidth\n max={field.maximum}\n min={field.minimum}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(\n field.fieldKey,\n clampOptionalNumber(parseOptionalNumberInput(event.target.value), {\n max: field.maximum,\n min: field.minimum,\n }),\n )\n }\n placeholder={field.placeholder ?? readInputPlaceholder(field.type)}\n {...(readonly ? { readonly: true as const } : {})}\n showSpinner\n value={readNumberInputValue(value)}\n variant=\"measure\"\n />\n );\n }\n\n return (\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(field.fieldKey, event.target.value)\n }\n placeholder={field.placeholder ?? readInputPlaceholder(field.type)}\n {...(readonly ? { readonly: true as const } : {})}\n value={readStringValue(value)}\n variant=\"base\"\n />\n );\n}\n\nfunction readFieldColumnSpan(\n field: FormFieldDefinition,\n uiSchema: FormUiSchema,\n): number {\n const width =\n uiSchema.layout.find((item) => item.fieldKey === field.fieldKey)?.width ??\n 'FULL';\n const spans: Readonly<Record<typeof width, number>> = {\n FULL: 12,\n HALF: 6,\n THIRD: 4,\n };\n\n return spans[width];\n}\n\nfunction readStringValue(value: FormFieldValue | undefined): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction readStringArrayValue(\n value: FormFieldValue | undefined,\n): readonly string[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction readNumberInputValue(value: FormFieldValue | undefined): string {\n return typeof value === 'number' ? String(value) : '';\n}\n\nfunction readInputPlaceholder(type: FormFieldDefinition['type']): string {\n const placeholders: Readonly<Record<FormFieldDefinition['type'], string>> = {\n boolean: '',\n checkbox: '請選擇一或多個選項',\n date: '請選擇日期',\n datetime: '請選擇日期與時間',\n file_upload: '請上傳附件',\n money: '請輸入金額',\n number: '請輸入數字',\n radio: '請選擇一個選項',\n select: '請選擇一個選項',\n text: '請輸入文字',\n textarea: '請輸入多行文字',\n };\n\n return placeholders[type];\n}\n\nexport { FormRenderer as FormRendererView };\n"],"mappings":";;;;;;;AA4DA,IAAM,IAA0C;CAC9C,YAAY;CACZ,SAAS;CACT,KAAK;CACL,qBAAqB;AACvB,GAEM,IAA2C,EAC/C,YAAY,SACd,GAEM,IAA2C;CAC/C,YAAY;CACZ,SAAS;CACT,KAAK;CACL,UAAU;AACZ,GAEM,IAAgC;CACpC,UAAU;CACV,OAAO;AACT;AAEA,SAAS,EAA2B,GAAsC;CACnE,MAIL,EAAQ,MAAM,QAAQ;AACxB;AAEA,SAAgB,EAAa,EAC3B,eAAY,WACZ,YAAS,CAAC,GACV,aACA,aACA,uBACA,cAAW,IACX,WACA,kBAAe,IACf,aACA,YACkC;CAClC,IAAM,CAAC,GAAgB,KAAqB,QAC1C,EAAwB,EAAO,QAAQ,KAAS,CAAC,CAAC,CACpD,GACM,IAAS,QAEX,EAAwB,EAAO,QAAQ,KAAS,CAAc,GAChE;EAAC;EAAgB,EAAO;EAAQ;CAAK,CACvC,GACM,IAAY,EAA2B,CAAM,GAC7C,IAAgB,QAElB,EAA8B,GAAQ,GAAU,CAAM,GACxD;EAAC;EAAQ;EAAU;CAAM,CAC3B;CAMA,AAJA,QAAsB;EACpB,EAAU,UAAU;CACtB,GAAG,CAAC,CAAM,CAAC,GAEX,QAAsB;EACpB,GAAmB,MACjB,EAAwB,EAAO,QAAQ,KAAS,CAAa,CAC/D;CACF,GAAG,CAAC,EAAO,QAAQ,CAAK,CAAC;CAEzB,SAAS,EACP,GACA,GACM;EACN,IAAM,IAAa;GACjB,GAAG,EAAU;IACZ,IAAW;EACd;EAOA,AANA,EAAU,UAAU,GAEf,KACH,EAAkB,CAAU,GAG9B,IAAW,CAAU;CACvB;CAgBA,OAdK,EAAc,SAejB,kBAAC,OAAD;EACE,OAAO;GACL,GAAG;GACH,GAAI,IAAe;IAAE;IAAU,OAAO;GAAO,IAAI,CAAC;EACpD;YAEC,EAAc,KAAK,MAClB,kBAAC,GAAD;GACS;GACP,OAAO,EAAO,EAAM,aAAa;GACjC,QAAQ,EAAO;GAEf,UAAU;GACU;GACV;GACV,OAAO;IACL,GAAG;IACH,YAAY,QACV,IAAe,KAAK,EAAoB,GAAO,CAAQ;GAE3D;GACA,OAAO,EAAO,EAAM;GACZ;EACT,GAZM,EAAM,QAYZ,CACF;CACE,CAAA,IAtCH,kBAAC,OAAD;EAAK,OAAO;YACV,kBAAC,GAAD;GACE,OAAM;GACN,OAAO;GACP,SAAQ;aAEP,EAAO,OAAO,SAAS,IAAI,kBAAkB;EACpC,CAAA;CACT,CAAA;AAgCX;AAEA,SAAS,EAAkB,EACzB,UACA,UACA,WACA,aACA,uBACA,aACA,UACA,UACA,aAmBe;CACf,IAAM,IAAW,EAA4B,GAAO,GAAQ,CAAM,GAC5D,IACJ,KAAY,EAA4B,GAAO,GAAQ,CAAM;CAE/D,OACE,kBAAC,OAAD;EAAK,uBAAqB,EAAM;EAAiB;YAAjD,CACE,kBAAC,GAAD;GACE,OAAO,EAAM;GACb,MAAM,EAAM;GACF;aAET,EACC,GACA,GACA,GACA,GACA,CACF;EACY,CAAA,GACb,IACC,kBAAC,GAAD;GAAY,OAAM;GAAa,SAAQ;aACpC;EACS,CAAA,IACV,IACD;;AAET;AAEA,SAAS,EACP,GACA,GACA,GACA,GACA,GAMc;CACd,IAAI,EAAM,SAAS,YACjB,OACE,kBAAC,GAAD;EACE,WAAW,MACT,EAAS,EAAM,UAAU,EAAM,OAAO,KAAK;EAE7C,aAAa,EAAM,eAAe;EAClC,UAAU;EACV,KAAK;EACL,MAAM;EACN,OAAO;EACP,OAAO,EAAgB,CAAK;CAC7B,CAAA;CAIL,IAAI,EAAM,SAAS,WACjB,OACE,kBAAC,GAAD;EACE,SAAS,MAAU;EACnB,UAAU;EACV,OAAM;EACN,WAAW,MACT,EAAS,EAAM,UAAU,EAAM,OAAO,OAAO;CAEhD,CAAA;CAIL,IAAI,EAAM,SAAS,YAAY;EAC7B,IAAM,IAAU,EAAM,QAAQ,IAAI,CAA6B;EAE/D,OACE,kBAAC,GAAD;GACE,MAAK;GACL,WAAW,MACT,EACE,EAAM,UACN,EAAQ,SAAS,EAAQ,KAAK,MAAW,EAAO,EAAE,IAAI,KAAA,CACxD;GAEO;GACT,aAAa,EAAM,eAAe;GAClC,UAAU;GACV,OAAO,EAAQ,QAAQ,MACrB,EAAqB,CAAK,EAAE,SAAS,EAAO,EAAE,CAChD;EACD,CAAA;CAEL;CAEA,IAAI,EAAM,SAAS,YAAY,EAAM,SAAS,SAAS;EACrD,IAAM,IAAU,EAAM,QAAQ,IAAI,CAA6B;EAE/D,OACE,kBAAC,GAAD;GACE,WAAW,MACT,EAAS,EAAM,UAAU,GAAQ,MAAM,KAAA,CAAS;GAEzC;GACT,aAAa,EAAM,eAAe;GAClC,UAAU;GACV,OAAO,EAAiB,GAAS,EAAgB,CAAK,CAAC;EACxD,CAAA;CAEL;CA8FA,OA5FI,EAAM,SAAS,gBAEf,kBAAC,GAAD;EACE,QAAQ,EAAM,mBAAmB,KAAK,GAAG;EACzC,UAAU;EACV,UAAU,EAAM;EAChB,MAAK;EACL,IAAM,EAAM,YAAY,KAAK,IAAI,EAAE,UAAU,GAAK,IAAI,CAAC;EACvD,WAAW,MACT,EACE,EAAM,UACN,EAAM,SAAS,EAAM,KAAK,MAAS,EAAK,EAAE,IAAI,KAAA,CAChD;EAEF,UAAU,OAAO,MACf,QAAQ,IACN,EAAM,IAAI,OAAO,OAKR;GACL;GACA,KANmB,IACjB,MAAM,EAAmB,GAAO,CAAI,IACpC,EAAE,IAAI,GAAG,EAAK,KAAK,GAAG,EAAK,eAAe,GAI3B;GACjB,UAAU;GACV,QAAQ;EACV,EACD,CACH;EAEF,MAAK;CACN,CAAA,IAID,EAAM,SAAS,SAEf,kBAAC,GAAD;EACE,QAAO;EACP,WAAA;EACA,WAAW,MACT,EAAS,EAAM,UAAU,EAAsB,CAAS,CAAC;EAE3D,aAAa,EAAM,eAAe,EAAqB,EAAM,IAAI;EACjE,UAAU;EACV,OAAO,EAAoB,CAAK;CACjC,CAAA,IAID,EAAM,SAAS,aAEf,kBAAC,GAAD;EACE,YAAW;EACX,YAAW;EACX,WAAA;EACA,YAAA;EACA,WAAW,MACT,EAAS,EAAM,UAAU,EAA0B,CAAS,CAAC;EAE/D,iBAAgB;EAChB,kBAAiB;EACjB,UAAU;EACV,OAAO,EAAoB,CAAK;CACjC,CAAA,IAID,EAAM,SAAS,YAAY,EAAM,SAAS,UAE1C,kBAAC,GAAD;EACE,WAAA;EACA,KAAK,EAAM;EACX,KAAK,EAAM;EACX,WAAW,MACT,EACE,EAAM,UACN,EAAoB,EAAyB,EAAM,OAAO,KAAK,GAAG;GAChE,KAAK,EAAM;GACX,KAAK,EAAM;EACb,CAAC,CACH;EAEF,aAAa,EAAM,eAAe,EAAqB,EAAM,IAAI;EACjE,GAAK,IAAW,EAAE,UAAU,GAAc,IAAI,CAAC;EAC/C,aAAA;EACA,OAAO,EAAqB,CAAK;EACjC,SAAQ;CACT,CAAA,IAKH,kBAAC,GAAD;EACE,WAAA;EACA,WAAW,MACT,EAAS,EAAM,UAAU,EAAM,OAAO,KAAK;EAE7C,aAAa,EAAM,eAAe,EAAqB,EAAM,IAAI;EACjE,GAAK,IAAW,EAAE,UAAU,GAAc,IAAI,CAAC;EAC/C,OAAO,EAAgB,CAAK;EAC5B,SAAQ;CACT,CAAA;AAEL;AAEA,SAAS,EACP,GACA,GACQ;CAUR,OAAO;EALL,MAAM;EACN,MAAM;EACN,OAAO;CAGF,EARL,EAAS,OAAO,MAAM,MAAS,EAAK,aAAa,EAAM,QAAQ,GAAG,SAClE;AAQJ;AAEA,SAAS,EAAgB,GAA2C;CAClE,OAAO,OAAO,KAAU,WAAW,IAAQ;AAC7C;AAEA,SAAS,EACP,GACmB;CACnB,OAAO,MAAM,QAAQ,CAAK,IAAI,IAAQ,CAAC;AACzC;AAEA,SAAS,EAAqB,GAA2C;CACvE,OAAO,OAAO,KAAU,WAAW,OAAO,CAAK,IAAI;AACrD;AAEA,SAAS,EAAqB,GAA2C;CAevE,OAAO;EAbL,SAAS;EACT,UAAU;EACV,MAAM;EACN,UAAU;EACV,aAAa;EACb,OAAO;EACP,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,MAAM;EACN,UAAU;CAGL,EAAa;AACtB"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use client";require('../approval-instance-list-page.css');const e=require("./chunk-CMqjfN_6.cjs"),t=require("./router-adapter--gYs13E8.cjs"),n=require("./format-date-time-XxBzF0F5.cjs"),r=require("./routes-config-fDVHmvXi.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("@rytass/bpm-core-client"),s=require("react/jsx-runtime"),c=require("@rytass/bpm-core-client/workflow"),l=require("@mezzanine-ui/react/ContentHeader");l=e.t(l,1);let u=require("@mezzanine-ui/core/form");var d={instanceFilterArea:`bpm_instanceFilterArea_qpvJq`},f=[10,20,50],p=[{id:`ALL`,name:`全部狀態`,state:null},{id:`RUNNING`,name:`進行中`,state:`RUNNING`},{id:`APPROVED`,name:`已通過`,state:`APPROVED`},{id:`REJECTED`,name:`已拒絕`,state:`REJECTED`},{id:`RETURNED`,name:`已退回`,state:`RETURNED`},{id:`CANCELLED`,name:`已取消`,state:`CANCELLED`},{id:`EXPIRED`,name:`已逾期`,state:`EXPIRED`},{id:`DRAFT`,name:`草稿`,state:`DRAFT`}];function m({defaultState:e,description:m,emptyMessage:y,searchPlaceholder:b,title:w,view:T}){let E=t.r(),D=r.r(),[O,k]=(0,i.useState)(null),[A,j]=(0,i.useState)(new Map),[M,N]=(0,i.useState)(1),[P,F]=(0,i.useState)(10),[I,L]=(0,i.useState)(0),[R,z]=(0,i.useState)(!0),[B,V]=(0,i.useState)([]),[H,U]=(0,i.useState)(``),[W,G]=(0,i.useState)(_(e)),K=(0,i.useCallback)(async()=>{z(!0),k(null);try{let e=await(0,c.listApprovalInstancesPage)({page:M,pageSize:P,searchText:H,state:W.state,templateId:null,view:T});V(e.instances.map(h)),L(e.totalCount)}catch(e){k(C(e))}finally{z(!1)}},[M,P,H,W,T]);(0,i.useEffect)(()=>{K()},[K]),(0,i.useEffect)(()=>{let e=Array.from(new Set(B.map(e=>e.initiatorMemberId).filter(Boolean)));if(e.length===0){j(new Map);return}let t=!1;return(async()=>{try{let n=await(0,o.resolveMembers)(e);if(t)return;j(new Map(n.map(e=>[e.memberId,e])))}catch{if(t)return;j(new Map)}})(),()=>{t=!0}},[B]);let q=(0,i.useMemo)(()=>[{dataIndex:`caseTitle`,key:`caseTitle`,title:`案件`,width:300},{key:`state`,render:e=>(0,s.jsx)(a.Typography,{color:x(e.state),component:`span`,variant:`body`,children:e.stateLabel}),title:`狀態`,width:120},{key:`initiatorMemberId`,render:e=>(0,s.jsx)(a.Typography,{component:`span`,variant:`body`,children:S(e.initiatorMemberId,A)}),title:`發起人`,width:180},{key:`startedAt`,render:e=>(0,s.jsx)(a.Typography,{component:`span`,variant:`body`,children:n.t(e.startedAt)}),title:`發起時間`,width:220},{key:`completedAt`,render:e=>(0,s.jsx)(a.Typography,{component:`span`,variant:`body`,children:n.t(e.completedAt)}),title:`完成時間`,width:220}],[A]),J=(0,i.useMemo)(()=>({render:e=>[{name:`查看`,onClick:()=>E.push(D.caseDetail(e.id))}],variant:`base-secondary`,width:88}),[E]);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.PageHeader,{children:(0,s.jsx)(l.default,{description:m,title:w})}),(0,s.jsx)(a.SectionGroup,{children:(0,s.jsxs)(a.Section,{filterArea:(0,s.jsx)(a.FilterArea,{className:d.instanceFilterArea,size:`sub`,children:(0,s.jsxs)(a.FilterLine,{children:[(0,s.jsx)(a.Filter,{span:3,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:u.FormFieldLayout.VERTICAL,name:`instanceSearchText`,children:(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{U(e.target.value),N(1)},placeholder:b,size:`sub`,value:H,variant:`base`})})}),(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:u.FormFieldLayout.VERTICAL,name:`instanceState`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>{G(g(e)),N(1)},options:[...p],placeholder:`狀態`,renderValue:e=>`狀態:${v(e)}`,size:`sub`,value:W})})})]})}),children:[O?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:O}):null,!O&&!R&&B.length===0?(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:y}):null,(0,s.jsx)(a.Table,{actions:J,columns:q,dataSource:[...B],fullWidth:!0,loading:R,pagination:{current:M,onChange:e=>{N(e)},onChangePageSize:e=>{N(1),F(e)},pageSize:P,pageSizeLabel:`每頁筆數`,pageSizeOptions:f,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:I}})]})})]})}function h(e){return{...e,caseTitle:(0,c.readApprovalInstanceCaseTitle)(e),key:e.id,stateLabel:b(e.state)}}function g(e){return y(e)?_(e.state):p[0]}function _(e){return p.find(t=>t.state===e)??p[0]}function v(e){return y(e)?e.name:p[0].name}function y(e){return typeof e==`object`&&!!e&&`id`in e&&`name`in e&&`state`in e}function b(e){return e===`RUNNING`?`進行中`:e===`APPROVED`?`已通過`:e===`REJECTED`?`已拒絕`:e===`RETURNED`?`已退回`:e===`CANCELLED`?`已取消`:e===`EXPIRED`?`已逾期`:`草稿`}function x(e){return e===`APPROVED`?`text-success`:e===`REJECTED`||e===`CANCELLED`||e===`EXPIRED`?`text-error`:`text-neutral`}function S(e,t){let n=(e??``).trim();return n?t.get(n)?.name??n:`未知發起人`}function C(e){return e instanceof Error?e.message:`讀取簽核案件失敗。`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return m}});
|
|
2
|
-
//# sourceMappingURL=approval-instance-list-page-BMUKxzcz.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"approval-instance-list-page-BMUKxzcz.cjs","names":[],"sources":["../../src/components/approval-instance-list-page.module.scss","../../src/components/approval-instance-list-page.tsx"],"sourcesContent":[".instanceFilterArea {\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n}\n","'use client';\n\nimport type { ChangeEvent, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { resolveMembers, type MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listApprovalInstancesPage,\n readApprovalInstanceCaseTitle,\n type ApprovalInstanceRecord,\n type ApprovalInstanceState,\n type ApprovalInstanceView,\n} from '@rytass/bpm-core-client/workflow';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\nimport { formatDateTime } from '../lib/format-date-time';\nimport styles from './approval-instance-list-page.module.scss';\n\nexport interface ApprovalInstanceListPageProps {\n readonly defaultState: ApprovalInstanceState | null;\n readonly description: string;\n readonly emptyMessage: string;\n readonly searchPlaceholder: string;\n readonly title: string;\n readonly view: ApprovalInstanceView;\n}\n\ntype StateFilterOption = Readonly<{\n id: 'ALL' | ApprovalInstanceState;\n name: string;\n state: ApprovalInstanceState | null;\n}>;\n\ntype ApprovalInstanceRow = Readonly<\n Record<string, unknown> &\n ApprovalInstanceRecord & {\n caseTitle: string;\n key: string;\n stateLabel: string;\n }\n>;\n\nconst INSTANCE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst STATE_FILTER_OPTIONS: readonly StateFilterOption[] = [\n { id: 'ALL', name: '全部狀態', state: null },\n { id: 'RUNNING', name: '進行中', state: 'RUNNING' },\n { id: 'APPROVED', name: '已通過', state: 'APPROVED' },\n { id: 'REJECTED', name: '已拒絕', state: 'REJECTED' },\n { id: 'RETURNED', name: '已退回', state: 'RETURNED' },\n { id: 'CANCELLED', name: '已取消', state: 'CANCELLED' },\n { id: 'EXPIRED', name: '已逾期', state: 'EXPIRED' },\n { id: 'DRAFT', name: '草稿', state: 'DRAFT' },\n];\n\n/**\n * Shared list page for any approval-instance \"view\" (inbox / sent / cc /\n * delegated). Caller picks the view + default state filter; the page renders\n * the standard BPM filter bar + paginated table and navigates to\n * `/instances/:id` on row action.\n */\nexport function ApprovalInstanceListPage({\n defaultState,\n description,\n emptyMessage,\n searchPlaceholder,\n title,\n view,\n}: ApprovalInstanceListPageProps): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [error, setError] = useState<string | null>(null);\n const [initiatorProfilesById, setInitiatorProfilesById] = useState<\n ReadonlyMap<string, MemberProfileRecord>\n >(new Map());\n const [instancePage, setInstancePage] = useState(1);\n const [instancePageSize, setInstancePageSize] = useState(10);\n const [instanceTotalCount, setInstanceTotalCount] = useState(0);\n const [loading, setLoading] = useState(true);\n const [rows, setRows] = useState<readonly ApprovalInstanceRow[]>([]);\n const [searchText, setSearchText] = useState('');\n const [stateFilter, setStateFilter] = useState<StateFilterOption>(\n readStateFilterOption(defaultState),\n );\n\n const refreshInstances = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const result = await listApprovalInstancesPage({\n page: instancePage,\n pageSize: instancePageSize,\n searchText,\n state: stateFilter.state,\n templateId: null,\n view,\n });\n\n setRows(result.instances.map(readApprovalInstanceRow));\n setInstanceTotalCount(result.totalCount);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [instancePage, instancePageSize, searchText, stateFilter, view]);\n\n useEffect((): void => {\n void refreshInstances();\n }, [refreshInstances]);\n\n useEffect((): (() => void) | void => {\n const initiatorMemberIds = Array.from(\n new Set(rows.map((row) => row.initiatorMemberId).filter(Boolean)),\n );\n\n if (initiatorMemberIds.length === 0) {\n setInitiatorProfilesById(new Map());\n\n return;\n }\n\n let cancelled = false;\n\n void (async (): Promise<void> => {\n try {\n const profiles = await resolveMembers(initiatorMemberIds);\n\n if (cancelled) {\n return;\n }\n\n setInitiatorProfilesById(\n new Map(profiles.map((profile) => [profile.memberId, profile])),\n );\n } catch {\n if (cancelled) {\n return;\n }\n\n setInitiatorProfilesById(new Map());\n }\n })();\n\n return (): void => {\n cancelled = true;\n };\n }, [rows]);\n\n const columns = useMemo(\n (): TableColumn<ApprovalInstanceRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 300 },\n {\n key: 'state',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography\n color={readInstanceStateColor(record.state)}\n component=\"span\"\n variant=\"body\"\n >\n {record.stateLabel}\n </Typography>\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'initiatorMemberId',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {readInitiatorLabel(\n record.initiatorMemberId,\n initiatorProfilesById,\n )}\n </Typography>\n ),\n title: '發起人',\n width: 180,\n },\n {\n key: 'startedAt',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.startedAt)}\n </Typography>\n ),\n title: '發起時間',\n width: 220,\n },\n {\n key: 'completedAt',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.completedAt)}\n </Typography>\n ),\n title: '完成時間',\n width: 220,\n },\n ],\n [initiatorProfilesById],\n );\n const tableActions = useMemo(\n (): TableActions<ApprovalInstanceRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<ApprovalInstanceRow>['render']> => [\n {\n name: '查看',\n onClick: (): void => router.push(routes.caseDetail(record.id)),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n return (\n <>\n <PageHeader>\n <ContentHeader description={description} title={title} />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.instanceFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"instanceSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setInstancePage(1);\n }}\n placeholder={searchPlaceholder}\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"instanceState\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setStateFilter(readSelectedStateFilterOption(option));\n setInstancePage(1);\n }}\n options={[...STATE_FILTER_OPTIONS]}\n placeholder=\"狀態\"\n renderValue={(value): string =>\n `狀態:${readStateFilterLabel(value)}`\n }\n size=\"sub\"\n value={stateFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {!error && !loading && rows.length === 0 ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n {emptyMessage}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={[...rows]}\n fullWidth\n loading={loading}\n pagination={{\n current: instancePage,\n onChange: (page): void => {\n setInstancePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setInstancePage(1);\n setInstancePageSize(pageSize);\n },\n pageSize: instancePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: INSTANCE_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: instanceTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readApprovalInstanceRow(\n instance: ApprovalInstanceRecord,\n): ApprovalInstanceRow {\n return {\n ...instance,\n caseTitle: readApprovalInstanceCaseTitle(instance),\n key: instance.id,\n stateLabel: readInstanceStateLabel(instance.state),\n };\n}\n\nfunction readSelectedStateFilterOption(option: unknown): StateFilterOption {\n if (!isStateFilterOption(option)) {\n return STATE_FILTER_OPTIONS[0];\n }\n return readStateFilterOption(option.state);\n}\n\nfunction readStateFilterOption(\n state: ApprovalInstanceState | null,\n): StateFilterOption {\n return (\n STATE_FILTER_OPTIONS.find((option) => option.state === state) ??\n STATE_FILTER_OPTIONS[0]\n );\n}\n\nfunction readStateFilterLabel(value: unknown): string {\n return isStateFilterOption(value) ? value.name : STATE_FILTER_OPTIONS[0].name;\n}\n\nfunction isStateFilterOption(value: unknown): value is StateFilterOption {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'id' in value &&\n 'name' in value &&\n 'state' in value\n );\n}\n\nfunction readInstanceStateLabel(state: ApprovalInstanceState): string {\n if (state === 'RUNNING') return '進行中';\n if (state === 'APPROVED') return '已通過';\n if (state === 'REJECTED') return '已拒絕';\n if (state === 'RETURNED') return '已退回';\n if (state === 'CANCELLED') return '已取消';\n if (state === 'EXPIRED') return '已逾期';\n return '草稿';\n}\n\nfunction readInstanceStateColor(\n state: ApprovalInstanceState,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (state === 'APPROVED') return 'text-success';\n if (state === 'REJECTED' || state === 'CANCELLED' || state === 'EXPIRED') {\n return 'text-error';\n }\n return 'text-neutral';\n}\n\nfunction readInitiatorLabel(\n initiatorMemberId: string | null | undefined,\n initiatorProfilesById: ReadonlyMap<string, MemberProfileRecord>,\n): string {\n const trimmedMemberId = (initiatorMemberId ?? '').trim();\n if (!trimmedMemberId) return '未知發起人';\n return initiatorProfilesById.get(trimmedMemberId)?.name ?? trimmedMemberId;\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取簽核案件失敗。';\n}\n"],"mappings":"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"}
|