@rytass/bpm-core-react 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/chunks/{FormBuilderView-BPLwAJGv.cjs → FormBuilderView-D6baVqBY.cjs} +2 -2
  3. package/dist/chunks/{FormBuilderView-BPLwAJGv.cjs.map → FormBuilderView-D6baVqBY.cjs.map} +1 -1
  4. package/dist/chunks/{FormBuilderView-Do9-MIAe.js → FormBuilderView-QtREqV4j.js} +2 -2
  5. package/dist/chunks/{FormBuilderView-Do9-MIAe.js.map → FormBuilderView-QtREqV4j.js.map} +1 -1
  6. package/dist/chunks/FormRendererView-Cw9LiidV.cjs +2 -0
  7. package/dist/chunks/FormRendererView-Cw9LiidV.cjs.map +1 -0
  8. package/dist/chunks/{FormRendererView-C5POZbWz.js → FormRendererView-D8QHLvd0.js} +224 -139
  9. package/dist/chunks/FormRendererView-D8QHLvd0.js.map +1 -0
  10. package/dist/chunks/{compose-CULMDsLS.cjs → compose-CODnd9-2.cjs} +2 -2
  11. package/dist/chunks/{compose-CULMDsLS.cjs.map → compose-CODnd9-2.cjs.map} +1 -1
  12. package/dist/chunks/{compose-DJBlA5PD.js → compose-D-OS-Ngs.js} +4 -4
  13. package/dist/chunks/{compose-DJBlA5PD.js.map → compose-D-OS-Ngs.js.map} +1 -1
  14. package/dist/chunks/{designer-CmqAU92b.cjs → designer-Cdn10NNl.cjs} +2 -2
  15. package/dist/chunks/{designer-CmqAU92b.cjs.map → designer-Cdn10NNl.cjs.map} +1 -1
  16. package/dist/chunks/{designer-BszXJ5RO.js → designer-DDSxwtjV.js} +2 -2
  17. package/dist/chunks/{designer-BszXJ5RO.js.map → designer-DDSxwtjV.js.map} +1 -1
  18. package/dist/chunks/detail-CtVu5NTi.cjs +2 -0
  19. package/dist/chunks/detail-CtVu5NTi.cjs.map +1 -0
  20. package/dist/chunks/{detail-DAak2OXS.js → detail-DAPz2qyn.js} +31 -30
  21. package/dist/chunks/detail-DAPz2qyn.js.map +1 -0
  22. package/dist/pages/instances/detail/index.cjs +1 -1
  23. package/dist/pages/instances/detail/index.js +1 -1
  24. package/dist/pages/templates/compose/index.cjs +1 -1
  25. package/dist/pages/templates/compose/index.js +1 -1
  26. package/dist/pages/templates/designer/index.cjs +1 -1
  27. package/dist/pages/templates/designer/index.js +1 -1
  28. package/dist/views/forms/builder/index.cjs +1 -1
  29. package/dist/views/forms/builder/index.js +1 -1
  30. package/dist/views/forms/renderer/form-data-source-field.d.ts +15 -0
  31. package/dist/views/forms/renderer/index.cjs +1 -1
  32. package/dist/views/forms/renderer/index.js +2 -2
  33. package/dist/views/instances/detail/index.cjs +1 -1
  34. package/dist/views/instances/detail/index.js +1 -1
  35. package/dist/views/instances/new/index.cjs +1 -1
  36. package/dist/views/instances/new/index.cjs.map +1 -1
  37. package/dist/views/instances/new/index.js +8 -6
  38. package/dist/views/instances/new/index.js.map +1 -1
  39. package/dist/views/templates/compose/index.cjs +1 -1
  40. package/dist/views/templates/compose/index.js +1 -1
  41. package/dist/views/templates/designer/index.cjs +1 -1
  42. package/dist/views/templates/designer/index.js +1 -1
  43. package/package.json +29 -20
  44. package/dist/chunks/FormRendererView-C5POZbWz.js.map +0 -1
  45. package/dist/chunks/FormRendererView-DNtNodNl.cjs +0 -2
  46. package/dist/chunks/FormRendererView-DNtNodNl.cjs.map +0 -1
  47. package/dist/chunks/detail-CDexqBoU.cjs +0 -2
  48. package/dist/chunks/detail-CDexqBoU.cjs.map +0 -1
  49. package/dist/chunks/detail-DAak2OXS.js.map +0 -1
@@ -8,6 +8,11 @@ export type FormRendererDataSourceContext = {
8
8
  readonly templateId?: string | null;
9
9
  };
10
10
  export interface FormDataSourceFieldState {
11
+ /**
12
+ * False when nothing can be re-requested — a read-only or context-less field
13
+ * has no query to retry, so the view must not offer a dead retry action.
14
+ */
15
+ readonly canRetry: boolean;
11
16
  readonly error: string | null;
12
17
  readonly hasValue: boolean;
13
18
  readonly hasNextPage: boolean;
@@ -32,3 +37,13 @@ export interface UseFormDataSourceFieldInput {
32
37
  export declare function useFormDataSourceField(input: UseFormDataSourceFieldInput): FormDataSourceFieldState;
33
38
  export declare function readFormDataSourceFieldStatusMessage(state: FormDataSourceFieldState): string | null;
34
39
  export declare function isFormDataSourceFieldSubmissionBlocked(state: Pick<FormDataSourceFieldState, 'hasValue' | 'status'>): boolean;
40
+ /**
41
+ * The copy to show when a submission is refused because of dynamic options.
42
+ * `LOADING` and `STALE` clear on their own once the pending query answers, so
43
+ * saying "finish validating" reads as a dead end for what is really a "wait a
44
+ * moment"; the caller would otherwise show the same permanent-sounding line for
45
+ * both cases.
46
+ *
47
+ * Returns `null` when nothing blocks the submission.
48
+ */
49
+ export declare function readFormDataSourceSubmissionBlockMessage(states: readonly Pick<FormDataSourceFieldState, 'hasValue' | 'status'>[]): string | null;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormRendererView-DNtNodNl.cjs");exports.FormRenderer=e.t,exports.FormRendererView=e.t,exports.isFormDataSourceFieldSubmissionBlocked=e.n,exports.readFormDataSourceFieldStatusMessage=e.r,exports.useFormDataSourceField=e.i;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormRendererView-Cw9LiidV.cjs");exports.FormRenderer=e.t,exports.FormRendererView=e.t,exports.isFormDataSourceFieldSubmissionBlocked=e.n,exports.readFormDataSourceFieldStatusMessage=e.r,exports.readFormDataSourceSubmissionBlockMessage=e.i,exports.useFormDataSourceField=e.a;
@@ -1,2 +1,2 @@
1
- import { i as e, n as t, r as n, t as r } from "../../../chunks/FormRendererView-C5POZbWz.js";
2
- export { r as FormRenderer, r as FormRendererView, t as isFormDataSourceFieldSubmissionBlocked, n as readFormDataSourceFieldStatusMessage, e as useFormDataSourceField };
1
+ import { a as e, i as t, n, r, t as i } from "../../../chunks/FormRendererView-D8QHLvd0.js";
2
+ export { i as FormRenderer, i as FormRendererView, n as isFormDataSourceFieldSubmissionBlocked, r as readFormDataSourceFieldStatusMessage, t as readFormDataSourceSubmissionBlockMessage, e as useFormDataSourceField };
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-CDexqBoU.cjs");exports.InstanceAttachmentsSection=e.a,exports.InstanceDetailView=e.t,exports.InstanceFormSection=e.o,exports.InstanceHistorySection=e.n,exports.InstanceSignaturesSection=e.r,exports.InstanceTasksSection=e.i;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-CtVu5NTi.cjs");exports.InstanceAttachmentsSection=e.a,exports.InstanceDetailView=e.t,exports.InstanceFormSection=e.o,exports.InstanceHistorySection=e.n,exports.InstanceSignaturesSection=e.r,exports.InstanceTasksSection=e.i;
@@ -1,2 +1,2 @@
1
- import { a as e, i as t, n, o as r, r as i, t as a } from "../../../chunks/detail-DAak2OXS.js";
1
+ import { a as e, i as t, n, o as r, r as i, t as a } from "../../../chunks/detail-DAPz2qyn.js";
2
2
  export { e as InstanceAttachmentsSection, a as InstanceDetailView, r as InstanceFormSection, n as InstanceHistorySection, i as InstanceSignaturesSection, t as InstanceTasksSection };
@@ -1,2 +1,2 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/chunk-CMqjfN_6.cjs"),t=require("../../../chunks/router-adapter--gYs13E8.cjs"),n=require("../../../chunks/auth-provider-4BeCw7cI.cjs"),r=require("../../../chunks/format-date-time-XxBzF0F5.cjs"),i=require("../../../chunks/routes-config-fDVHmvXi.cjs"),a=require("../../../chunks/FormRendererView-DNtNodNl.cjs");let o=require("react"),s=require("@mezzanine-ui/react"),c=require("react/jsx-runtime"),l=require("@rytass/bpm-core-client/workflow"),u=require("@mezzanine-ui/react/ContentHeader");u=e.t(u,1);let d=require("@mezzanine-ui/icons"),f=require("@rytass/bpm-core-client/form");var p={display:`grid`,gap:16};function m(e={}){return(0,c.jsx)(o.Suspense,{fallback:(0,c.jsx)(g,{}),children:(0,c.jsx)(h,{templateId:e.templateId??void 0})})}function h({templateId:e}){let m=t.r(),h=i.r(),{member:g}=n.n(),v=g?.memberId??null,y=e??null,[b,x]=(0,o.useState)(null),[S,C]=(0,o.useState)({}),[w,T]=(0,o.useState)([]),[E,D]=(0,o.useState)(null),[O,k]=(0,o.useState)({}),[A,j]=(0,o.useState)(!0),[M,N]=(0,o.useState)(!1),[P,F]=(0,o.useState)({}),I=(0,o.useCallback)((e,t)=>{F(n=>{let r=n[e];return r?.hasValue===t.hasValue&&r.status===t.status?n:{...n,[e]:{hasValue:t.hasValue,status:t.status}}})},[]);(0,o.useEffect)(()=>{if(!y){B();return}V(y)},[y]);let L=(0,o.useMemo)(()=>w.map(e=>({...e,key:e.id,updatedAt:r.t(e.updatedAt),versionLabel:`v${e.version}`})),[w]),R=(0,o.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`模板名稱`,width:240},{dataIndex:`versionLabel`,key:`versionLabel`,title:`發布版本`,width:120},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:220}],[]),z=(0,o.useMemo)(()=>({render:e=>[{name:`發起`,onClick:()=>m.push(h.caseNew(e.id)),variant:`base-primary`}],variant:`base-secondary`,width:88}),[m]);async function B(){j(!0),D(null),x(null),F({});try{T(await(0,l.listLaunchableTemplates)())}catch(e){D(_(e))}finally{j(!1)}}async function V(e){j(!0),D(null),T([]),F({});try{x(await(0,l.readLaunchContext)(e))}catch(e){D(_(e))}finally{j(!1)}}async function H(){if(!b||!v)return;if(N(!0),D(null),k({}),Object.values(P).some(a.n)){D(`請先完成動態選項驗證。`),N(!1);return}let e=(0,f.validateFormRendererValues)({schema:b.formVersion.schema,uiSchema:b.formVersion.uiSchema,values:S});if(!e.valid){k(e.errors),D(`請先補齊必填欄位。`),e.firstInvalidFieldKey&&(0,f.focusFormRendererField)(e.firstInvalidFieldKey),N(!1);return}try{let e=await(0,l.submitApprovalInstance)({formData:S,initiatorMemberId:v,templateId:b.template.id,title:(0,l.readFormDataCaseTitle)({fallbackTitle:b.template.name,formData:S,schema:b.formVersion.schema,uiSchema:b.formVersion.uiSchema})});m.push(h.caseDetail(e))}catch(e){D(_(e))}finally{N(!1)}}async function U(e,t){if(!v)throw Error(`尚未登入,無法上傳附件`);return{id:(await(0,l.uploadAttachment)({file:t,formFieldPath:`form.${e.fieldKey}`})).id}}return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(s.PageHeader,{children:(0,c.jsx)(u.default,{description:b?`${b.template.name} · 表單 v${b.formVersion.version}`:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`,children:b?(0,c.jsx)(s.Button,{disabled:A||M,icon:d.CheckedIcon,iconType:`leading`,onClick:H,variant:`base-primary`,children:`送出`}):null})}),(0,c.jsx)(s.SectionGroup,{children:(0,c.jsx)(s.Section,{children:(0,c.jsxs)(`div`,{style:p,children:[E?(0,c.jsx)(s.Typography,{color:`text-error`,variant:`body`,children:E}):null,A?(0,c.jsx)(s.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`}):null,b?(0,c.jsx)(a.t,{dataSourceContext:{kind:`runtime`,templateId:b.template.id},errors:O,maxWidth:480,onChange:e=>{C(e),k({})},onDataSourceStateChange:I,onUploadAttachment:U,schema:b.formVersion.schema,singleColumn:!0,uiSchema:b.formVersion.uiSchema,value:S}):null,!y&&!A?L.length>0?(0,c.jsx)(s.Table,{actions:z,columns:R,dataSource:L,fullWidth:!0}):(0,c.jsx)(s.Typography,{color:`text-neutral`,variant:`body`,children:`目前沒有可發起的已發布模板。`}):null]})})})]})}function g(){return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(s.PageHeader,{children:(0,c.jsx)(u.default,{description:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`})}),(0,c.jsx)(s.SectionGroup,{children:(0,c.jsx)(s.Section,{children:(0,c.jsx)(s.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`})})})]})}function _(e){return(0,f.readFormDataSourceErrorMessage)(e)||(e instanceof Error?e.message:`發生未知錯誤`)}exports.InstanceNewView=m;
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/chunk-CMqjfN_6.cjs"),t=require("../../../chunks/router-adapter--gYs13E8.cjs"),n=require("../../../chunks/auth-provider-4BeCw7cI.cjs"),r=require("../../../chunks/format-date-time-XxBzF0F5.cjs"),i=require("../../../chunks/routes-config-fDVHmvXi.cjs"),a=require("../../../chunks/FormRendererView-Cw9LiidV.cjs");let o=require("react"),s=require("@mezzanine-ui/react"),c=require("react/jsx-runtime"),l=require("@rytass/bpm-core-client/workflow"),u=require("@mezzanine-ui/react/ContentHeader");u=e.t(u,1);let d=require("@mezzanine-ui/icons"),f=require("@rytass/bpm-core-client/form");var p={display:`grid`,gap:16};function m(e={}){return(0,c.jsx)(o.Suspense,{fallback:(0,c.jsx)(g,{}),children:(0,c.jsx)(h,{templateId:e.templateId??void 0})})}function h({templateId:e}){let m=t.r(),h=i.r(),{member:g}=n.n(),v=g?.memberId??null,y=e??null,[b,x]=(0,o.useState)(null),[S,C]=(0,o.useState)({}),[w,T]=(0,o.useState)([]),[E,D]=(0,o.useState)(null),[O,k]=(0,o.useState)({}),[A,j]=(0,o.useState)(!0),[M,N]=(0,o.useState)(!1),[P,F]=(0,o.useState)({}),I=(0,o.useCallback)((e,t)=>{F(n=>{let r=n[e];return r?.hasValue===t.hasValue&&r.status===t.status?n:{...n,[e]:{hasValue:t.hasValue,status:t.status}}})},[]);(0,o.useEffect)(()=>{if(!y){B();return}V(y)},[y]);let L=(0,o.useMemo)(()=>w.map(e=>({...e,key:e.id,updatedAt:r.t(e.updatedAt),versionLabel:`v${e.version}`})),[w]),R=(0,o.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`模板名稱`,width:240},{dataIndex:`versionLabel`,key:`versionLabel`,title:`發布版本`,width:120},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:220}],[]),z=(0,o.useMemo)(()=>({render:e=>[{name:`發起`,onClick:()=>m.push(h.caseNew(e.id)),variant:`base-primary`}],variant:`base-secondary`,width:88}),[m]);async function B(){j(!0),D(null),x(null),F({});try{T(await(0,l.listLaunchableTemplates)())}catch(e){D(_(e))}finally{j(!1)}}async function V(e){j(!0),D(null),T([]),F({});try{x(await(0,l.readLaunchContext)(e))}catch(e){D(_(e))}finally{j(!1)}}async function H(){if(!b||!v)return;N(!0),D(null),k({});let e=a.i(Object.values(P));if(e){D(e),N(!1);return}let t=(0,f.validateFormRendererValues)({schema:b.formVersion.schema,uiSchema:b.formVersion.uiSchema,values:S});if(!t.valid){k(t.errors),D(`請先補齊必填欄位。`),t.firstInvalidFieldKey&&(0,f.focusFormRendererField)(t.firstInvalidFieldKey),N(!1);return}try{let e=await(0,l.submitApprovalInstance)({formData:S,initiatorMemberId:v,templateId:b.template.id,title:(0,l.readFormDataCaseTitle)({fallbackTitle:b.template.name,formData:S,schema:b.formVersion.schema,uiSchema:b.formVersion.uiSchema})});m.push(h.caseDetail(e))}catch(e){D(_(e))}finally{N(!1)}}async function U(e,t){if(!v)throw Error(`尚未登入,無法上傳附件`);return{id:(await(0,l.uploadAttachment)({file:t,formFieldPath:`form.${e.fieldKey}`})).id}}return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(s.PageHeader,{children:(0,c.jsx)(u.default,{description:b?`${b.template.name} · 表單 v${b.formVersion.version}`:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`,children:b?(0,c.jsx)(s.Button,{disabled:A||M,icon:d.CheckedIcon,iconType:`leading`,onClick:H,variant:`base-primary`,children:`送出`}):null})}),(0,c.jsx)(s.SectionGroup,{children:(0,c.jsx)(s.Section,{children:(0,c.jsxs)(`div`,{style:p,children:[E?(0,c.jsx)(s.Typography,{color:`text-error`,variant:`body`,children:E}):null,A?(0,c.jsx)(s.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`}):null,b?(0,c.jsx)(a.t,{dataSourceContext:{kind:`runtime`,templateId:b.template.id},errors:O,maxWidth:480,onChange:e=>{C(e),k({})},onDataSourceStateChange:I,onUploadAttachment:U,schema:b.formVersion.schema,singleColumn:!0,uiSchema:b.formVersion.uiSchema,value:S}):null,!y&&!A?L.length>0?(0,c.jsx)(s.Table,{actions:z,columns:R,dataSource:L,fullWidth:!0}):(0,c.jsx)(s.Typography,{color:`text-neutral`,variant:`body`,children:`目前沒有可發起的已發布模板。`}):null]})})})]})}function g(){return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(s.PageHeader,{children:(0,c.jsx)(u.default,{description:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`})}),(0,c.jsx)(s.SectionGroup,{children:(0,c.jsx)(s.Section,{children:(0,c.jsx)(s.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`})})})]})}function _(e){return(0,f.readFormDataSourceErrorMessage)(e)||(e instanceof Error?e.message:`發生未知錯誤`)}exports.InstanceNewView=m;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../../src/views/instances/new/InstanceNewView.tsx"],"sourcesContent":["'use client';\n\nimport {\n CSSProperties,\n ReactElement,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { CheckedIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n focusFormRendererField,\n FormRendererValues,\n readFormDataSourceErrorMessage,\n validateFormRendererValues,\n} from '@rytass/bpm-core-client/form';\nimport {\n LaunchContext,\n LaunchableTemplateRecord,\n listLaunchableTemplates,\n readFormDataCaseTitle,\n readLaunchContext,\n submitApprovalInstance,\n uploadAttachment,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport { useAuth } from '../../../lib/auth-provider';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport { FormRenderer } from '../../forms/renderer/FormRendererView';\nimport {\n isFormDataSourceFieldSubmissionBlocked,\n type FormDataSourceFieldState,\n} from '../../forms/renderer/form-data-source-field';\n\nconst FORM_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\ntype LaunchableTemplateRow = Readonly<\n Record<string, unknown> &\n LaunchableTemplateRecord & {\n key: string;\n versionLabel: string;\n }\n>;\n\nexport interface InstanceNewViewProps {\n /**\n * Optional template id pre-selected by the host. The Server Component\n * page should read `?templateId=` from its `searchParams` and pass the\n * value through this prop.\n */\n readonly templateId?: string | null;\n}\n\n/**\n * Framework-agnostic view for the BPM \"發起簽核\" launch page. Mechanical port\n * of `apps/client/src/app/instances/new/page.tsx` — picks a launchable\n * template and submits the launch form.\n */\nexport function InstanceNewView(\n props: InstanceNewViewProps = {},\n): ReactElement {\n return (\n <Suspense fallback={<NewApprovalInstanceLoading />}>\n <NewApprovalInstanceContent templateId={props.templateId ?? undefined} />\n </Suspense>\n );\n}\n\nfunction NewApprovalInstanceContent({\n templateId: templateIdProp,\n}: {\n readonly templateId?: string;\n}): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const templateId = templateIdProp ?? null;\n const [context, setContext] = useState<LaunchContext | null>(null);\n const [formValues, setFormValues] = useState<FormRendererValues>({});\n const [templates, setTemplates] = useState<\n readonly LaunchableTemplateRecord[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [formErrors, setFormErrors] = useState<\n Readonly<Record<string, string>>\n >({});\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n const [dataSourceStates, setDataSourceStates] = useState<\n Readonly<\n Record<string, Pick<FormDataSourceFieldState, 'hasValue' | 'status'>>\n >\n >({});\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n status: state.status,\n },\n };\n });\n },\n [],\n );\n\n useEffect((): void => {\n if (!templateId) {\n void refreshTemplates();\n\n return;\n }\n\n void refreshContext(templateId);\n }, [templateId]);\n\n const rows = useMemo(\n (): LaunchableTemplateRow[] =>\n templates.map((template) => ({\n ...template,\n key: template.id,\n updatedAt: formatDateTime(template.updatedAt),\n versionLabel: `v${template.version}`,\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<LaunchableTemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 240 },\n {\n dataIndex: 'versionLabel',\n key: 'versionLabel',\n title: '發布版本',\n width: 120,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<LaunchableTemplateRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<LaunchableTemplateRow>['render']> => [\n {\n name: '發起',\n onClick: (): void =>\n router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n async function refreshTemplates(): Promise<void> {\n setLoading(true);\n setError(null);\n setContext(null);\n setDataSourceStates({});\n\n try {\n setTemplates(await listLaunchableTemplates());\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function refreshContext(nextTemplateId: string): Promise<void> {\n setLoading(true);\n setError(null);\n setTemplates([]);\n setDataSourceStates({});\n\n try {\n setContext(await readLaunchContext(nextTemplateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleSubmit(): Promise<void> {\n if (!context || !currentMemberId) {\n return;\n }\n\n setSubmitting(true);\n setError(null);\n setFormErrors({});\n\n if (\n Object.values(dataSourceStates).some(\n isFormDataSourceFieldSubmissionBlocked,\n )\n ) {\n setError('請先完成動態選項驗證。');\n setSubmitting(false);\n\n return;\n }\n\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: formValues,\n });\n\n if (!validation.valid) {\n setFormErrors(validation.errors);\n setError('請先補齊必填欄位。');\n\n if (validation.firstInvalidFieldKey) {\n focusFormRendererField(validation.firstInvalidFieldKey);\n }\n\n setSubmitting(false);\n\n return;\n }\n\n try {\n const instanceId = await submitApprovalInstance({\n formData: formValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: formValues,\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n }),\n });\n\n router.push(routes.caseDetail(instanceId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSubmitting(false);\n }\n }\n\n async function handleUploadAttachment(\n field: FormFieldDefinition,\n file: File,\n ): Promise<{ readonly id: string }> {\n if (!currentMemberId) {\n throw new Error('尚未登入,無法上傳附件');\n }\n\n const attachment = await uploadAttachment({\n file,\n formFieldPath: `form.${field.fieldKey}`,\n });\n\n return { id: attachment.id };\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description={\n context\n ? `${context.template.name} · 表單 v${context.formVersion.version}`\n : '選擇可發起的已發布模板後填寫表單內容。'\n }\n title=\"發起簽核\"\n >\n {context ? (\n <Button\n disabled={loading || submitting}\n icon={CheckedIcon}\n iconType=\"leading\"\n onClick={handleSubmit}\n variant=\"base-primary\"\n >\n 送出\n </Button>\n ) : null}\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={FORM_SECTION_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n {loading ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n ) : null}\n\n {context ? (\n <FormRenderer\n dataSourceContext={{\n kind: 'runtime',\n templateId: context.template.id,\n }}\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onDataSourceStateChange={handleDataSourceStateChange}\n onUploadAttachment={handleUploadAttachment}\n schema={context.formVersion.schema}\n singleColumn\n uiSchema={context.formVersion.uiSchema}\n value={formValues}\n />\n ) : null}\n\n {!templateId && !loading ? (\n rows.length > 0 ? (\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 目前沒有可發起的已發布模板。\n </Typography>\n )\n ) : null}\n </div>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"選擇可發起的已發布模板後填寫表單內容。\"\n title=\"發起簽核\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../../src/views/instances/new/InstanceNewView.tsx"],"sourcesContent":["'use client';\n\nimport {\n CSSProperties,\n ReactElement,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { CheckedIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n focusFormRendererField,\n FormRendererValues,\n readFormDataSourceErrorMessage,\n validateFormRendererValues,\n} from '@rytass/bpm-core-client/form';\nimport {\n LaunchContext,\n LaunchableTemplateRecord,\n listLaunchableTemplates,\n readFormDataCaseTitle,\n readLaunchContext,\n submitApprovalInstance,\n uploadAttachment,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport { useAuth } from '../../../lib/auth-provider';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport { FormRenderer } from '../../forms/renderer/FormRendererView';\nimport {\n readFormDataSourceSubmissionBlockMessage,\n type FormDataSourceFieldState,\n} from '../../forms/renderer/form-data-source-field';\n\nconst FORM_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\ntype LaunchableTemplateRow = Readonly<\n Record<string, unknown> &\n LaunchableTemplateRecord & {\n key: string;\n versionLabel: string;\n }\n>;\n\nexport interface InstanceNewViewProps {\n /**\n * Optional template id pre-selected by the host. The Server Component\n * page should read `?templateId=` from its `searchParams` and pass the\n * value through this prop.\n */\n readonly templateId?: string | null;\n}\n\n/**\n * Framework-agnostic view for the BPM \"發起簽核\" launch page. Mechanical port\n * of `apps/client/src/app/instances/new/page.tsx` — picks a launchable\n * template and submits the launch form.\n */\nexport function InstanceNewView(\n props: InstanceNewViewProps = {},\n): ReactElement {\n return (\n <Suspense fallback={<NewApprovalInstanceLoading />}>\n <NewApprovalInstanceContent templateId={props.templateId ?? undefined} />\n </Suspense>\n );\n}\n\nfunction NewApprovalInstanceContent({\n templateId: templateIdProp,\n}: {\n readonly templateId?: string;\n}): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const templateId = templateIdProp ?? null;\n const [context, setContext] = useState<LaunchContext | null>(null);\n const [formValues, setFormValues] = useState<FormRendererValues>({});\n const [templates, setTemplates] = useState<\n readonly LaunchableTemplateRecord[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [formErrors, setFormErrors] = useState<\n Readonly<Record<string, string>>\n >({});\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n const [dataSourceStates, setDataSourceStates] = useState<\n Readonly<\n Record<string, Pick<FormDataSourceFieldState, 'hasValue' | 'status'>>\n >\n >({});\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n status: state.status,\n },\n };\n });\n },\n [],\n );\n\n useEffect((): void => {\n if (!templateId) {\n void refreshTemplates();\n\n return;\n }\n\n void refreshContext(templateId);\n }, [templateId]);\n\n const rows = useMemo(\n (): LaunchableTemplateRow[] =>\n templates.map((template) => ({\n ...template,\n key: template.id,\n updatedAt: formatDateTime(template.updatedAt),\n versionLabel: `v${template.version}`,\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<LaunchableTemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 240 },\n {\n dataIndex: 'versionLabel',\n key: 'versionLabel',\n title: '發布版本',\n width: 120,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<LaunchableTemplateRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<LaunchableTemplateRow>['render']> => [\n {\n name: '發起',\n onClick: (): void =>\n router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n async function refreshTemplates(): Promise<void> {\n setLoading(true);\n setError(null);\n setContext(null);\n setDataSourceStates({});\n\n try {\n setTemplates(await listLaunchableTemplates());\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function refreshContext(nextTemplateId: string): Promise<void> {\n setLoading(true);\n setError(null);\n setTemplates([]);\n setDataSourceStates({});\n\n try {\n setContext(await readLaunchContext(nextTemplateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleSubmit(): Promise<void> {\n if (!context || !currentMemberId) {\n return;\n }\n\n setSubmitting(true);\n setError(null);\n setFormErrors({});\n\n const dataSourceBlockMessage = readFormDataSourceSubmissionBlockMessage(\n Object.values(dataSourceStates),\n );\n\n if (dataSourceBlockMessage) {\n setError(dataSourceBlockMessage);\n setSubmitting(false);\n\n return;\n }\n\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: formValues,\n });\n\n if (!validation.valid) {\n setFormErrors(validation.errors);\n setError('請先補齊必填欄位。');\n\n if (validation.firstInvalidFieldKey) {\n focusFormRendererField(validation.firstInvalidFieldKey);\n }\n\n setSubmitting(false);\n\n return;\n }\n\n try {\n const instanceId = await submitApprovalInstance({\n formData: formValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: formValues,\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n }),\n });\n\n router.push(routes.caseDetail(instanceId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSubmitting(false);\n }\n }\n\n async function handleUploadAttachment(\n field: FormFieldDefinition,\n file: File,\n ): Promise<{ readonly id: string }> {\n if (!currentMemberId) {\n throw new Error('尚未登入,無法上傳附件');\n }\n\n const attachment = await uploadAttachment({\n file,\n formFieldPath: `form.${field.fieldKey}`,\n });\n\n return { id: attachment.id };\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description={\n context\n ? `${context.template.name} · 表單 v${context.formVersion.version}`\n : '選擇可發起的已發布模板後填寫表單內容。'\n }\n title=\"發起簽核\"\n >\n {context ? (\n <Button\n disabled={loading || submitting}\n icon={CheckedIcon}\n iconType=\"leading\"\n onClick={handleSubmit}\n variant=\"base-primary\"\n >\n 送出\n </Button>\n ) : null}\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={FORM_SECTION_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n {loading ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n ) : null}\n\n {context ? (\n <FormRenderer\n dataSourceContext={{\n kind: 'runtime',\n templateId: context.template.id,\n }}\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onDataSourceStateChange={handleDataSourceStateChange}\n onUploadAttachment={handleUploadAttachment}\n schema={context.formVersion.schema}\n singleColumn\n uiSchema={context.formVersion.uiSchema}\n value={formValues}\n />\n ) : null}\n\n {!templateId && !loading ? (\n rows.length > 0 ? (\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 目前沒有可發起的已發布模板。\n </Typography>\n )\n ) : null}\n </div>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"選擇可發起的已發布模板後填寫表單內容。\"\n title=\"發起簽核\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { r as e } from "../../../chunks/router-adapter-DftlFTOd.js";
3
3
  import { n as t } from "../../../chunks/auth-provider-B5oPmvk2.js";
4
4
  import { t as n } from "../../../chunks/format-date-time-CB-LxzqT.js";
5
5
  import { r } from "../../../chunks/routes-config-RBYQtUd0.js";
6
- import { n as i, t as a } from "../../../chunks/FormRendererView-C5POZbWz.js";
6
+ import { i, t as a } from "../../../chunks/FormRendererView-D8QHLvd0.js";
7
7
  import { Suspense as o, useCallback as s, useEffect as c, useMemo as l, useState as u } from "react";
8
8
  import { Button as d, PageHeader as f, Section as p, SectionGroup as m, Table as h, Typography as g } from "@mezzanine-ui/react";
9
9
  import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
@@ -97,17 +97,19 @@ function M({ templateId: o }) {
97
97
  }
98
98
  async function ie() {
99
99
  if (!I || !N) return;
100
- if (Y(!0), U(null), G({}), Object.values(X).some(i)) {
101
- U("請先完成動態選項驗證。"), Y(!1);
100
+ Y(!0), U(null), G({});
101
+ let e = i(Object.values(X));
102
+ if (e) {
103
+ U(e), Y(!1);
102
104
  return;
103
105
  }
104
- let e = k({
106
+ let t = k({
105
107
  schema: I.formVersion.schema,
106
108
  uiSchema: I.formVersion.uiSchema,
107
109
  values: R
108
110
  });
109
- if (!e.valid) {
110
- G(e.errors), U("請先補齊必填欄位。"), e.firstInvalidFieldKey && D(e.firstInvalidFieldKey), Y(!1);
111
+ if (!t.valid) {
112
+ G(t.errors), U("請先補齊必填欄位。"), t.firstInvalidFieldKey && D(t.firstInvalidFieldKey), Y(!1);
111
113
  return;
112
114
  }
113
115
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/views/instances/new/InstanceNewView.tsx"],"sourcesContent":["'use client';\n\nimport {\n CSSProperties,\n ReactElement,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { CheckedIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n focusFormRendererField,\n FormRendererValues,\n readFormDataSourceErrorMessage,\n validateFormRendererValues,\n} from '@rytass/bpm-core-client/form';\nimport {\n LaunchContext,\n LaunchableTemplateRecord,\n listLaunchableTemplates,\n readFormDataCaseTitle,\n readLaunchContext,\n submitApprovalInstance,\n uploadAttachment,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport { useAuth } from '../../../lib/auth-provider';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport { FormRenderer } from '../../forms/renderer/FormRendererView';\nimport {\n isFormDataSourceFieldSubmissionBlocked,\n type FormDataSourceFieldState,\n} from '../../forms/renderer/form-data-source-field';\n\nconst FORM_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\ntype LaunchableTemplateRow = Readonly<\n Record<string, unknown> &\n LaunchableTemplateRecord & {\n key: string;\n versionLabel: string;\n }\n>;\n\nexport interface InstanceNewViewProps {\n /**\n * Optional template id pre-selected by the host. The Server Component\n * page should read `?templateId=` from its `searchParams` and pass the\n * value through this prop.\n */\n readonly templateId?: string | null;\n}\n\n/**\n * Framework-agnostic view for the BPM \"發起簽核\" launch page. Mechanical port\n * of `apps/client/src/app/instances/new/page.tsx` — picks a launchable\n * template and submits the launch form.\n */\nexport function InstanceNewView(\n props: InstanceNewViewProps = {},\n): ReactElement {\n return (\n <Suspense fallback={<NewApprovalInstanceLoading />}>\n <NewApprovalInstanceContent templateId={props.templateId ?? undefined} />\n </Suspense>\n );\n}\n\nfunction NewApprovalInstanceContent({\n templateId: templateIdProp,\n}: {\n readonly templateId?: string;\n}): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const templateId = templateIdProp ?? null;\n const [context, setContext] = useState<LaunchContext | null>(null);\n const [formValues, setFormValues] = useState<FormRendererValues>({});\n const [templates, setTemplates] = useState<\n readonly LaunchableTemplateRecord[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [formErrors, setFormErrors] = useState<\n Readonly<Record<string, string>>\n >({});\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n const [dataSourceStates, setDataSourceStates] = useState<\n Readonly<\n Record<string, Pick<FormDataSourceFieldState, 'hasValue' | 'status'>>\n >\n >({});\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n status: state.status,\n },\n };\n });\n },\n [],\n );\n\n useEffect((): void => {\n if (!templateId) {\n void refreshTemplates();\n\n return;\n }\n\n void refreshContext(templateId);\n }, [templateId]);\n\n const rows = useMemo(\n (): LaunchableTemplateRow[] =>\n templates.map((template) => ({\n ...template,\n key: template.id,\n updatedAt: formatDateTime(template.updatedAt),\n versionLabel: `v${template.version}`,\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<LaunchableTemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 240 },\n {\n dataIndex: 'versionLabel',\n key: 'versionLabel',\n title: '發布版本',\n width: 120,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<LaunchableTemplateRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<LaunchableTemplateRow>['render']> => [\n {\n name: '發起',\n onClick: (): void =>\n router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n async function refreshTemplates(): Promise<void> {\n setLoading(true);\n setError(null);\n setContext(null);\n setDataSourceStates({});\n\n try {\n setTemplates(await listLaunchableTemplates());\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function refreshContext(nextTemplateId: string): Promise<void> {\n setLoading(true);\n setError(null);\n setTemplates([]);\n setDataSourceStates({});\n\n try {\n setContext(await readLaunchContext(nextTemplateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleSubmit(): Promise<void> {\n if (!context || !currentMemberId) {\n return;\n }\n\n setSubmitting(true);\n setError(null);\n setFormErrors({});\n\n if (\n Object.values(dataSourceStates).some(\n isFormDataSourceFieldSubmissionBlocked,\n )\n ) {\n setError('請先完成動態選項驗證。');\n setSubmitting(false);\n\n return;\n }\n\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: formValues,\n });\n\n if (!validation.valid) {\n setFormErrors(validation.errors);\n setError('請先補齊必填欄位。');\n\n if (validation.firstInvalidFieldKey) {\n focusFormRendererField(validation.firstInvalidFieldKey);\n }\n\n setSubmitting(false);\n\n return;\n }\n\n try {\n const instanceId = await submitApprovalInstance({\n formData: formValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: formValues,\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n }),\n });\n\n router.push(routes.caseDetail(instanceId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSubmitting(false);\n }\n }\n\n async function handleUploadAttachment(\n field: FormFieldDefinition,\n file: File,\n ): Promise<{ readonly id: string }> {\n if (!currentMemberId) {\n throw new Error('尚未登入,無法上傳附件');\n }\n\n const attachment = await uploadAttachment({\n file,\n formFieldPath: `form.${field.fieldKey}`,\n });\n\n return { id: attachment.id };\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description={\n context\n ? `${context.template.name} · 表單 v${context.formVersion.version}`\n : '選擇可發起的已發布模板後填寫表單內容。'\n }\n title=\"發起簽核\"\n >\n {context ? (\n <Button\n disabled={loading || submitting}\n icon={CheckedIcon}\n iconType=\"leading\"\n onClick={handleSubmit}\n variant=\"base-primary\"\n >\n 送出\n </Button>\n ) : null}\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={FORM_SECTION_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n {loading ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n ) : null}\n\n {context ? (\n <FormRenderer\n dataSourceContext={{\n kind: 'runtime',\n templateId: context.template.id,\n }}\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onDataSourceStateChange={handleDataSourceStateChange}\n onUploadAttachment={handleUploadAttachment}\n schema={context.formVersion.schema}\n singleColumn\n uiSchema={context.formVersion.uiSchema}\n value={formValues}\n />\n ) : null}\n\n {!templateId && !loading ? (\n rows.length > 0 ? (\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 目前沒有可發起的已發布模板。\n </Typography>\n )\n ) : null}\n </div>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"選擇可發起的已發布模板後填寫表單內容。\"\n title=\"發起簽核\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/views/instances/new/InstanceNewView.tsx"],"sourcesContent":["'use client';\n\nimport {\n CSSProperties,\n ReactElement,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { CheckedIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n focusFormRendererField,\n FormRendererValues,\n readFormDataSourceErrorMessage,\n validateFormRendererValues,\n} from '@rytass/bpm-core-client/form';\nimport {\n LaunchContext,\n LaunchableTemplateRecord,\n listLaunchableTemplates,\n readFormDataCaseTitle,\n readLaunchContext,\n submitApprovalInstance,\n uploadAttachment,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport { useAuth } from '../../../lib/auth-provider';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport { FormRenderer } from '../../forms/renderer/FormRendererView';\nimport {\n readFormDataSourceSubmissionBlockMessage,\n type FormDataSourceFieldState,\n} from '../../forms/renderer/form-data-source-field';\n\nconst FORM_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\ntype LaunchableTemplateRow = Readonly<\n Record<string, unknown> &\n LaunchableTemplateRecord & {\n key: string;\n versionLabel: string;\n }\n>;\n\nexport interface InstanceNewViewProps {\n /**\n * Optional template id pre-selected by the host. The Server Component\n * page should read `?templateId=` from its `searchParams` and pass the\n * value through this prop.\n */\n readonly templateId?: string | null;\n}\n\n/**\n * Framework-agnostic view for the BPM \"發起簽核\" launch page. Mechanical port\n * of `apps/client/src/app/instances/new/page.tsx` — picks a launchable\n * template and submits the launch form.\n */\nexport function InstanceNewView(\n props: InstanceNewViewProps = {},\n): ReactElement {\n return (\n <Suspense fallback={<NewApprovalInstanceLoading />}>\n <NewApprovalInstanceContent templateId={props.templateId ?? undefined} />\n </Suspense>\n );\n}\n\nfunction NewApprovalInstanceContent({\n templateId: templateIdProp,\n}: {\n readonly templateId?: string;\n}): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const templateId = templateIdProp ?? null;\n const [context, setContext] = useState<LaunchContext | null>(null);\n const [formValues, setFormValues] = useState<FormRendererValues>({});\n const [templates, setTemplates] = useState<\n readonly LaunchableTemplateRecord[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [formErrors, setFormErrors] = useState<\n Readonly<Record<string, string>>\n >({});\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n const [dataSourceStates, setDataSourceStates] = useState<\n Readonly<\n Record<string, Pick<FormDataSourceFieldState, 'hasValue' | 'status'>>\n >\n >({});\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n status: state.status,\n },\n };\n });\n },\n [],\n );\n\n useEffect((): void => {\n if (!templateId) {\n void refreshTemplates();\n\n return;\n }\n\n void refreshContext(templateId);\n }, [templateId]);\n\n const rows = useMemo(\n (): LaunchableTemplateRow[] =>\n templates.map((template) => ({\n ...template,\n key: template.id,\n updatedAt: formatDateTime(template.updatedAt),\n versionLabel: `v${template.version}`,\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<LaunchableTemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 240 },\n {\n dataIndex: 'versionLabel',\n key: 'versionLabel',\n title: '發布版本',\n width: 120,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<LaunchableTemplateRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<LaunchableTemplateRow>['render']> => [\n {\n name: '發起',\n onClick: (): void =>\n router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n async function refreshTemplates(): Promise<void> {\n setLoading(true);\n setError(null);\n setContext(null);\n setDataSourceStates({});\n\n try {\n setTemplates(await listLaunchableTemplates());\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function refreshContext(nextTemplateId: string): Promise<void> {\n setLoading(true);\n setError(null);\n setTemplates([]);\n setDataSourceStates({});\n\n try {\n setContext(await readLaunchContext(nextTemplateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleSubmit(): Promise<void> {\n if (!context || !currentMemberId) {\n return;\n }\n\n setSubmitting(true);\n setError(null);\n setFormErrors({});\n\n const dataSourceBlockMessage = readFormDataSourceSubmissionBlockMessage(\n Object.values(dataSourceStates),\n );\n\n if (dataSourceBlockMessage) {\n setError(dataSourceBlockMessage);\n setSubmitting(false);\n\n return;\n }\n\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: formValues,\n });\n\n if (!validation.valid) {\n setFormErrors(validation.errors);\n setError('請先補齊必填欄位。');\n\n if (validation.firstInvalidFieldKey) {\n focusFormRendererField(validation.firstInvalidFieldKey);\n }\n\n setSubmitting(false);\n\n return;\n }\n\n try {\n const instanceId = await submitApprovalInstance({\n formData: formValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: formValues,\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n }),\n });\n\n router.push(routes.caseDetail(instanceId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSubmitting(false);\n }\n }\n\n async function handleUploadAttachment(\n field: FormFieldDefinition,\n file: File,\n ): Promise<{ readonly id: string }> {\n if (!currentMemberId) {\n throw new Error('尚未登入,無法上傳附件');\n }\n\n const attachment = await uploadAttachment({\n file,\n formFieldPath: `form.${field.fieldKey}`,\n });\n\n return { id: attachment.id };\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description={\n context\n ? `${context.template.name} · 表單 v${context.formVersion.version}`\n : '選擇可發起的已發布模板後填寫表單內容。'\n }\n title=\"發起簽核\"\n >\n {context ? (\n <Button\n disabled={loading || submitting}\n icon={CheckedIcon}\n iconType=\"leading\"\n onClick={handleSubmit}\n variant=\"base-primary\"\n >\n 送出\n </Button>\n ) : null}\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={FORM_SECTION_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n {loading ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n ) : null}\n\n {context ? (\n <FormRenderer\n dataSourceContext={{\n kind: 'runtime',\n templateId: context.template.id,\n }}\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onDataSourceStateChange={handleDataSourceStateChange}\n onUploadAttachment={handleUploadAttachment}\n schema={context.formVersion.schema}\n singleColumn\n uiSchema={context.formVersion.uiSchema}\n value={formValues}\n />\n ) : null}\n\n {!templateId && !loading ? (\n rows.length > 0 ? (\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 目前沒有可發起的已發布模板。\n </Typography>\n )\n ) : null}\n </div>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"選擇可發起的已發布模板後填寫表單內容。\"\n title=\"發起簽核\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/compose-CULMDsLS.cjs");exports.EMPTY_COMPOSE_FORM_SCHEMA=e.n,exports.EMPTY_COMPOSE_FORM_UI_SCHEMA=e.r,exports.TemplateComposeWizardView=e.t,exports.useTemplateComposeWizard=e.i;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/compose-CODnd9-2.cjs");exports.EMPTY_COMPOSE_FORM_SCHEMA=e.n,exports.EMPTY_COMPOSE_FORM_UI_SCHEMA=e.r,exports.TemplateComposeWizardView=e.t,exports.useTemplateComposeWizard=e.i;
@@ -1,2 +1,2 @@
1
- import { i as e, n as t, r as n, t as r } from "../../../chunks/compose-DJBlA5PD.js";
1
+ import { i as e, n as t, r as n, t as r } from "../../../chunks/compose-D-OS-Ngs.js";
2
2
  export { t as EMPTY_COMPOSE_FORM_SCHEMA, n as EMPTY_COMPOSE_FORM_UI_SCHEMA, r as TemplateComposeWizardView, e as useTemplateComposeWizard };
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/designer-CmqAU92b.cjs");exports.TemplateDesignerView=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/designer-Cdn10NNl.cjs");exports.TemplateDesignerView=e.t;
@@ -1,2 +1,2 @@
1
- import { t as e } from "../../../chunks/designer-BszXJ5RO.js";
1
+ import { t as e } from "../../../chunks/designer-DDSxwtjV.js";
2
2
  export { e as TemplateDesignerView };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rytass/bpm-core-react",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "BPM approval workflow React components and views for the Rytass BPM stack. Ships AuthProvider, NotificationDrawer + bell widget, host-facing hooks (useBPMMember / useBPMLogout / useBPMRoutes), and full page-body views for inbox / instances / templates / forms / admin / settings on top of Mezzanine UI and the BPM client functions. The host owns the navigation shell — BPM does not bundle a layout.",
5
5
  "keywords": [
6
6
  "bpm",
@@ -278,24 +278,33 @@
278
278
  }
279
279
  },
280
280
  "peerDependencies": {
281
- "@codemirror/lang-json": "^6.0.2",
282
- "@codemirror/view": "^6.41.1",
283
- "@hello-pangea/dnd": "^18.0.1",
284
- "@mezzanine-ui/core": "^1.0.4",
285
- "@mezzanine-ui/icons": "^1.0.2",
286
- "@mezzanine-ui/react": "^1.1.0",
287
- "@rytass/bpm-core-client": "^0.9.0",
288
- "@rytass/bpm-core-shared": "^0.9.0",
289
- "@uiw/react-codemirror": "^4.25.9",
290
- "@xyflow/react": "^12.10.2",
291
- "dagre": "^0.8.5",
292
- "next": "~16.2.6",
281
+ "@ai-sdk/openai": ">=3.0.0",
282
+ "@ai-sdk/react": ">=3.0.0",
283
+ "@codemirror/lang-json": ">=6.0.0",
284
+ "@codemirror/view": ">=6.0.0",
285
+ "@hello-pangea/dnd": ">=18.0.0",
286
+ "@mezzanine-ui/core": ">=1.0.0",
287
+ "@mezzanine-ui/icons": ">=1.0.0",
288
+ "@mezzanine-ui/react": ">=1.0.0",
289
+ "@rytass/bpm-core-client": "^0.10.0",
290
+ "@rytass/bpm-core-shared": "^0.10.0",
291
+ "@uiw/react-codemirror": ">=4.0.0",
292
+ "@xyflow/react": ">=12.0.0",
293
+ "ai": ">=6.0.0",
294
+ "dagre": ">=0.8.5",
295
+ "next": ">=15.0.0",
293
296
  "pdfjs-dist": "^5.4.296",
294
- "react": "^18.0.0 || ^19.0.0",
295
- "react-dom": "^18.0.0 || ^19.0.0",
296
- "react-pdf": "^10.4.1"
297
+ "react": ">=18.0.0",
298
+ "react-dom": ">=18.0.0",
299
+ "react-pdf": ">=10.0.0"
297
300
  },
298
301
  "peerDependenciesMeta": {
302
+ "@ai-sdk/openai": {
303
+ "optional": true
304
+ },
305
+ "@ai-sdk/react": {
306
+ "optional": true
307
+ },
299
308
  "@codemirror/lang-json": {
300
309
  "optional": true
301
310
  },
@@ -314,6 +323,9 @@
314
323
  "@xyflow/react": {
315
324
  "optional": true
316
325
  },
326
+ "ai": {
327
+ "optional": true
328
+ },
317
329
  "dagre": {
318
330
  "optional": true
319
331
  },
@@ -328,9 +340,6 @@
328
340
  }
329
341
  },
330
342
  "dependencies": {
331
- "@ai-sdk/openai": "^3.0.67",
332
- "@ai-sdk/react": "^3.0.195",
333
- "ai": "^6.0.193",
334
343
  "moment": "^2.30.1"
335
344
  }
336
- }
345
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"FormRendererView-C5POZbWz.js","names":[],"sources":["../../src/views/forms/renderer/form-data-source-field.ts","../../src/views/forms/renderer/FormRendererView.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n FormDataSourceValueSnapshots,\n FormDefinitionSchema,\n FormFieldDefinition,\n FormFieldOption,\n FormFieldValue,\n FormUiSchema,\n isFormDataSourceFieldDefinition,\n} from '@rytass/bpm-core-shared/form';\nimport {\n FormDataSourceFieldStatus,\n FormRendererValues,\n mergeFormDataSourceOptions,\n readFormDataSourceErrorMessage,\n readMissingFormDataSourceOptionValues,\n previewFormFieldOptions,\n readFormDataSourceValueSignature,\n readMissingFormDataSourceDependencies,\n readSelectedFormDataSourceOptions,\n readFormFieldOptions,\n} from '@rytass/bpm-core-client/form';\n\nexport type FormRendererDataSourceContext =\n | { readonly kind: 'preview' }\n | {\n readonly instanceId?: string | null;\n readonly kind: 'runtime';\n readonly templateId?: string | null;\n };\n\nexport interface FormDataSourceFieldState {\n readonly error: string | null;\n readonly hasValue: boolean;\n readonly hasNextPage: boolean;\n readonly invalidValues: readonly string[];\n readonly onReachBottom: () => void;\n readonly onSearch: (searchText: string) => void;\n readonly options: readonly FormFieldOption[];\n readonly retry: () => void;\n readonly status: FormDataSourceFieldStatus;\n}\n\nexport interface UseFormDataSourceFieldInput {\n readonly context?: FormRendererDataSourceContext;\n readonly field: FormFieldDefinition;\n readonly formData: FormRendererValues;\n readonly initialFormData?: FormRendererValues;\n readonly initialValue?: FormFieldValue | undefined;\n readonly optionSnapshots?: FormDataSourceValueSnapshots;\n readonly readonly: boolean;\n readonly schema: FormDefinitionSchema;\n readonly uiSchema: FormUiSchema;\n}\n\nconst EMPTY_FIELD_STATE: FormDataSourceFieldState = {\n error: null,\n hasValue: false,\n hasNextPage: false,\n invalidValues: [],\n onReachBottom: (): void => undefined,\n onSearch: (): void => undefined,\n options: [],\n retry: (): void => undefined,\n status: 'IDLE',\n};\n\nexport function useFormDataSourceField(\n input: UseFormDataSourceFieldInput,\n): FormDataSourceFieldState {\n const dynamicField = isFormDataSourceFieldDefinition(input.field)\n ? input.field\n : null;\n const snapshot = dynamicField\n ? input.optionSnapshots?.[dynamicField.fieldKey]\n : undefined;\n const snapshotSignature = JSON.stringify(snapshot ?? null);\n const snapshotOptions = useMemo(\n (): readonly FormFieldOption[] => snapshot?.options ?? [],\n [snapshotSignature],\n );\n const formDataSignature = JSON.stringify(input.formData);\n const initialFormDataSignature = JSON.stringify(input.initialFormData ?? {});\n const schemaSignature = JSON.stringify(input.schema);\n const uiSchemaSignature = JSON.stringify(input.uiSchema);\n const contextKind = input.context?.kind;\n const contextInstanceId =\n input.context?.kind === 'runtime' ? input.context.instanceId : undefined;\n const contextTemplateId =\n input.context?.kind === 'runtime' ? input.context.templateId : undefined;\n const missingDependencies = dynamicField\n ? readMissingFormDataSourceDependencies(dynamicField, input.formData)\n : [];\n const missingDependenciesSignature = JSON.stringify(missingDependencies);\n const dataSourceRefreshSignature = dynamicField\n ? JSON.stringify({\n bindings: dynamicField.dataSource.bindings.map((binding) =>\n binding.from.kind === 'FIELD'\n ? {\n fieldKey: binding.from.fieldKey,\n value: input.formData[binding.from.fieldKey],\n }\n : { value: binding.from.value },\n ),\n value:\n typeof input.initialFormData !== 'undefined' ||\n typeof input.initialValue !== 'undefined'\n ? input.formData[dynamicField.fieldKey]\n : undefined,\n })\n : '';\n const effectiveContext = useMemo(\n (): FormRendererDataSourceContext | undefined => {\n if (contextKind === 'preview') {\n return { kind: 'preview' };\n }\n\n if (contextKind === 'runtime' && !input.readonly) {\n return {\n instanceId: contextInstanceId,\n kind: 'runtime',\n templateId: contextTemplateId,\n };\n }\n\n return undefined;\n },\n [\n contextInstanceId,\n contextKind,\n contextTemplateId,\n input.readonly,\n ],\n );\n const valueChanged = dynamicField\n ? (typeof input.initialFormData !== 'undefined' ||\n typeof input.initialValue !== 'undefined') &&\n readFormDataSourceValueSignature(input.initialValue) !==\n readFormDataSourceValueSignature(input.formData[dynamicField.fieldKey])\n : false;\n const bindingsChanged = dynamicField\n ? typeof input.initialFormData !== 'undefined' &&\n dynamicField.dataSource.bindings.some((binding) => {\n if (binding.from.kind !== 'FIELD') {\n return false;\n }\n\n return (\n readFormDataSourceValueSignature(\n input.initialFormData?.[binding.from.fieldKey],\n ) !==\n readFormDataSourceValueSignature(input.formData[binding.from.fieldKey])\n );\n })\n : false;\n const isStale = Boolean(snapshot && (valueChanged || bindingsChanged));\n const [remoteOptions, setRemoteOptions] = useState<readonly FormFieldOption[]>(\n [],\n );\n const [searchText, setSearchText] = useState('');\n const [nextCursor, setNextCursor] = useState<string | null>(null);\n const [status, setStatus] = useState<FormDataSourceFieldStatus>(\n dynamicField ? (snapshot ? (isStale ? 'STALE' : 'VALID') : 'IDLE') : 'IDLE',\n );\n const [error, setError] = useState<string | null>(null);\n const requestSequence = useRef(0);\n const lastRequest = useRef<{ readonly cursor: string | null; readonly searchText: string }>({\n cursor: null,\n searchText: '',\n });\n\n const queryFormData = useMemo(\n (): Readonly<Record<string, FormFieldValue>> =>\n Object.entries(input.formData).reduce<\n Readonly<Record<string, FormFieldValue>>\n >((values, [key, value]) => {\n if (typeof value === 'undefined') {\n return values;\n }\n\n return { ...values, [key]: value };\n }, {}),\n [formDataSignature],\n );\n const mergedOptions = useMemo(\n (): readonly FormFieldOption[] =>\n mergeFormDataSourceOptions(snapshotOptions, remoteOptions),\n [remoteOptions, snapshotOptions],\n );\n const invalidValues = useMemo(\n (): readonly string[] =>\n readMissingFormDataSourceOptionValues(\n dynamicField ? input.formData[dynamicField.fieldKey] : undefined,\n mergedOptions,\n ),\n [dynamicField, input.formData, mergedOptions],\n );\n const hasValue = readFormDataSourceValuePresent(\n dynamicField ? input.formData[dynamicField.fieldKey] : undefined,\n );\n\n const loadOptions = useCallback(\n (nextSearchTextToLoad: string, cursor: string | null): void => {\n if (!dynamicField || !effectiveContext) {\n return;\n }\n\n if (missingDependencies.length > 0) {\n setStatus('WAITING_FOR_DEPENDENCIES');\n setError(null);\n\n return;\n }\n\n const requestId = requestSequence.current + 1;\n requestSequence.current = requestId;\n lastRequest.current = {\n cursor,\n searchText: nextSearchTextToLoad,\n };\n setStatus(isStale ? 'STALE' : 'LOADING');\n setError(null);\n\n const request =\n effectiveContext.kind === 'preview'\n ? previewFormFieldOptions({\n cursor,\n fieldKey: dynamicField.fieldKey,\n formData: queryFormData,\n schema: input.schema,\n searchText: nextSearchTextToLoad,\n uiSchema: input.uiSchema,\n })\n : readFormFieldOptions({\n cursor,\n fieldKey: dynamicField.fieldKey,\n formData: queryFormData,\n instanceId: effectiveContext.instanceId ?? null,\n searchText: nextSearchTextToLoad,\n templateId: effectiveContext.templateId ?? null,\n });\n\n void request\n .then((result): void => {\n if (requestSequence.current !== requestId) {\n return;\n }\n\n setRemoteOptions((currentOptions) => {\n const currentValue = dynamicField\n ? input.formData[dynamicField.fieldKey]\n : undefined;\n const selectedOptions = readSelectedFormDataSourceOptions(\n currentValue,\n currentOptions,\n );\n\n return mergeFormDataSourceOptions(\n selectedOptions,\n cursor ? currentOptions : [],\n result.options,\n );\n });\n setNextCursor(result.nextCursor);\n setStatus('VALID');\n setError(null);\n })\n .catch((requestError: unknown): void => {\n if (requestSequence.current !== requestId) {\n return;\n }\n\n setStatus('UNAVAILABLE');\n // The backend answers with stable codes rather than prose, so show\n // the mapped copy instead of a raw `FORM_DATA_SOURCE_*` string.\n setError(\n readFormDataSourceErrorMessage(requestError) ??\n (requestError instanceof Error\n ? requestError.message\n : '選項來源暫時無法使用。'),\n );\n });\n },\n [\n dynamicField,\n effectiveContext,\n isStale,\n missingDependencies.length,\n queryFormData,\n schemaSignature,\n uiSchemaSignature,\n ],\n );\n const loadOptionsRef = useRef(loadOptions);\n loadOptionsRef.current = loadOptions;\n\n useEffect((): void => {\n requestSequence.current += 1;\n setRemoteOptions((currentOptions) => {\n const currentValue = dynamicField\n ? input.formData[dynamicField.fieldKey]\n : undefined;\n\n return readSelectedFormDataSourceOptions(currentValue, currentOptions);\n });\n setNextCursor((currentCursor) =>\n currentCursor === null ? currentCursor : null,\n );\n setSearchText((currentSearchText) =>\n currentSearchText ? '' : currentSearchText,\n );\n setError((currentError) => (currentError ? null : currentError));\n\n if (!dynamicField) {\n setStatus('IDLE');\n\n return;\n }\n\n if (missingDependencies.length > 0) {\n setStatus('WAITING_FOR_DEPENDENCIES');\n\n return;\n }\n\n if (!effectiveContext) {\n setStatus(\n snapshot\n ? isStale\n ? 'STALE'\n : 'VALID'\n : input.readonly\n ? 'UNAVAILABLE'\n : 'IDLE',\n );\n\n return;\n }\n\n if (dynamicField.type === 'autocomplete') {\n setStatus(snapshot ? (isStale ? 'STALE' : 'VALID') : 'IDLE');\n\n return;\n }\n\n loadOptionsRef.current('', null);\n }, [\n dynamicField,\n effectiveContext,\n dataSourceRefreshSignature,\n initialFormDataSignature,\n input.readonly,\n isStale,\n missingDependenciesSignature,\n snapshotSignature,\n ]);\n\n const onSearch = useCallback(\n (nextSearchTextToLoad: string): void => {\n setSearchText(nextSearchTextToLoad);\n setRemoteOptions((currentOptions) => {\n const currentValue = dynamicField\n ? input.formData[dynamicField.fieldKey]\n : undefined;\n\n return readSelectedFormDataSourceOptions(currentValue, currentOptions);\n });\n setNextCursor(null);\n loadOptions(nextSearchTextToLoad, null);\n },\n [loadOptions],\n );\n const onReachBottom = useCallback((): void => {\n if (nextCursor) {\n loadOptions(searchText, nextCursor);\n }\n }, [loadOptions, nextCursor, searchText]);\n const retry = useCallback((): void => {\n loadOptions(lastRequest.current.searchText, lastRequest.current.cursor);\n }, [loadOptions]);\n\n if (!dynamicField) {\n return EMPTY_FIELD_STATE;\n }\n\n return {\n error,\n hasValue,\n hasNextPage: Boolean(nextCursor),\n invalidValues,\n onReachBottom,\n onSearch,\n options: mergedOptions,\n retry,\n status: status === 'VALID' && invalidValues.length ? 'INVALID' : status,\n };\n}\n\nexport function readFormDataSourceFieldStatusMessage(\n state: FormDataSourceFieldState,\n): string | null {\n switch (state.status) {\n case 'WAITING_FOR_DEPENDENCIES':\n return '請先填寫相依欄位。';\n case 'STALE':\n return '選項需要重新載入或驗證。';\n case 'INVALID':\n return state.invalidValues.length\n ? `無法辨識選項:${state.invalidValues.join('、')}`\n : '目前選項已失效,請重新選擇。';\n case 'UNAVAILABLE':\n return state.error ?? '選項來源暫時無法使用。';\n case 'VALID':\n return state.options.length ? null : '目前沒有可用選項。';\n default:\n return null;\n }\n}\n\nexport function isFormDataSourceFieldSubmissionBlocked(\n state: Pick<FormDataSourceFieldState, 'hasValue' | 'status'>,\n): boolean {\n return state.hasValue && state.status !== 'VALID';\n}\n\nfunction readFormDataSourceValuePresent(\n value: FormFieldValue | undefined,\n): boolean {\n if (typeof value === 'undefined' || value === null) {\n return false;\n }\n\n if (typeof value === 'string') {\n return value.trim().length > 0;\n }\n\n if (Array.isArray(value)) {\n return value.length > 0;\n }\n\n return true;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n AutoComplete,\n Button,\n CheckboxGroup,\n DatePicker,\n DateTimePicker,\n Input,\n RadioGroup,\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 FormDataSourceOptionFieldDefinition,\n FormDataSourceValueSnapshots,\n FormDefinitionSchema,\n FormFieldDefinition,\n FormFieldValue,\n FormUiSchema,\n isFormDataSourceFieldDefinition,\n isFormStaticOptionFieldDefinition,\n readFormFieldSelectionMode,\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 readSelectedFormDataSourceOptions,\n readSelectOption,\n readVisibleFormRendererFields,\n} from '@rytass/bpm-core-client/form';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport {\n FormDataSourceFieldState,\n FormRendererDataSourceContext,\n readFormDataSourceFieldStatusMessage,\n useFormDataSourceField,\n} from './form-data-source-field';\n\nexport interface FormRendererProps {\n readonly dataSourceContext?: FormRendererDataSourceContext;\n readonly dataSourceInitialValues?: FormRendererValues;\n readonly emptyText?: string;\n readonly errors?: Readonly<Record<string, string>>;\n readonly maxWidth?: CSSProperties['maxWidth'];\n readonly onChange?: (values: FormRendererValues) => void;\n readonly onDataSourceStateChange?: (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ) => void;\n readonly onUploadAttachment?: (\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>;\n readonly optionSnapshots?: FormDataSourceValueSnapshots;\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 dataSourceContext,\n dataSourceInitialValues,\n emptyText = '尚未建立欄位。',\n errors = {},\n maxWidth,\n onChange,\n onDataSourceStateChange,\n onUploadAttachment,\n optionSnapshots,\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 dataSourceContext={dataSourceContext}\n dataSourceInitialValues={dataSourceInitialValues}\n field={field}\n error={errors[field.fieldKey] ?? null}\n fields={schema.fields}\n key={field.fieldKey}\n onChange={updateValue}\n onDataSourceStateChange={onDataSourceStateChange}\n onUploadAttachment={onUploadAttachment}\n optionSnapshots={optionSnapshots}\n readonly={readonly}\n schema={schema}\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 uiSchema={uiSchema}\n />\n ))}\n </div>\n );\n}\n\nfunction FormRendererField({\n dataSourceContext,\n dataSourceInitialValues,\n error,\n field,\n fields,\n onChange,\n onDataSourceStateChange,\n onUploadAttachment,\n optionSnapshots,\n readonly,\n schema,\n style,\n value,\n values,\n uiSchema,\n}: {\n readonly dataSourceContext?: FormRendererDataSourceContext;\n readonly dataSourceInitialValues?: FormRendererValues;\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 onDataSourceStateChange?: (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ) => void;\n readonly onUploadAttachment?:\n | ((\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>)\n | undefined;\n readonly optionSnapshots?: FormDataSourceValueSnapshots;\n readonly readonly: boolean;\n readonly schema: FormDefinitionSchema;\n readonly style: CSSProperties;\n readonly uiSchema: FormUiSchema;\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 const dataSourceState = useFormDataSourceField({\n context: dataSourceContext,\n field,\n formData: values,\n initialFormData: dataSourceInitialValues,\n initialValue: dataSourceInitialValues?.[field.fieldKey],\n optionSnapshots,\n readonly: fieldReadonly,\n schema,\n uiSchema,\n });\n const dataSourceStatusMessage = readFormDataSourceFieldStatusMessage(\n dataSourceState,\n );\n const dataSourceStateSignature = JSON.stringify({\n hasValue: dataSourceState.hasValue,\n invalidValues: dataSourceState.invalidValues,\n status: dataSourceState.status,\n });\n\n useEffect((): void => {\n if (!isFormDataSourceFieldDefinition(field)) {\n return;\n }\n\n onDataSourceStateChange?.(field.fieldKey, {\n hasValue: dataSourceState.hasValue,\n invalidValues: dataSourceState.invalidValues,\n status: dataSourceState.status,\n });\n }, [\n dataSourceStateSignature,\n field.fieldKey,\n onDataSourceStateChange,\n ]);\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 dataSourceContext,\n dataSourceState,\n )}\n </BPMFormField>\n {error ? (\n <Typography color=\"text-error\" variant=\"caption\">\n {error}\n </Typography>\n ) : null}\n {dataSourceStatusMessage ? (\n <div style={DATA_SOURCE_FEEDBACK_STYLE}>\n <Typography\n color={\n dataSourceState.status === 'INVALID' ||\n dataSourceState.status === 'UNAVAILABLE'\n ? 'text-error'\n : 'text-neutral'\n }\n variant=\"caption\"\n >\n {dataSourceStatusMessage}\n </Typography>\n {dataSourceState.status === 'UNAVAILABLE' ? (\n <Button\n onClick={dataSourceState.retry}\n size=\"sub\"\n type=\"button\"\n variant=\"base-ghost\"\n >\n 重試\n </Button>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n\nconst DATA_SOURCE_FEEDBACK_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n gap: 8,\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 dataSourceContext: FormRendererDataSourceContext | undefined,\n dataSourceState: FormDataSourceFieldState,\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 (isFormDataSourceFieldDefinition(field)) {\n return renderDynamicOptionControl(\n field,\n value,\n readonly,\n onChange,\n dataSourceContext,\n dataSourceState,\n );\n }\n\n if (isFormStaticOptionFieldDefinition(field) && 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\n ? options.map((option) => option.id)\n : 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 (isFormStaticOptionFieldDefinition(field)) {\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 renderDynamicOptionControl(\n field: FormDataSourceOptionFieldDefinition,\n value: FormFieldValue | undefined,\n readonly: boolean,\n onChange: (fieldKey: string, value: FormFieldValue | undefined) => void,\n dataSourceContext: FormRendererDataSourceContext | undefined,\n dataSourceState: FormDataSourceFieldState,\n): ReactElement {\n const options = dataSourceState.options.map(readFieldOptionAsSelectOption);\n const selectedOptions = readSelectedFormDataSourceOptions(\n value,\n dataSourceState.options,\n ).map(readFieldOptionAsSelectOption);\n const loading = dataSourceState.status === 'LOADING';\n const waitingForDependencies =\n dataSourceState.status === 'WAITING_FOR_DEPENDENCIES';\n const interactiveSearch = Boolean(dataSourceContext) && !readonly;\n const optionControlDisabled = readonly || waitingForDependencies;\n\n if (field.type === 'autocomplete') {\n if (readFormFieldSelectionMode(field) === 'multiple') {\n return (\n <AutoComplete\n asyncData={interactiveSearch}\n clearSearchText\n disabled={optionControlDisabled}\n disabledOptionsFilter={interactiveSearch}\n globalPortal\n loading={loading}\n mode=\"multiple\"\n onChange={(nextOptions): void =>\n onChange(\n field.fieldKey,\n nextOptions.length\n ? nextOptions.map((option) => option.id)\n : undefined,\n )\n }\n onReachBottom={\n dataSourceState.hasNextPage\n ? dataSourceState.onReachBottom\n : undefined\n }\n onSearch={interactiveSearch ? dataSourceState.onSearch : undefined}\n options={options}\n placeholder={field.placeholder ?? '請輸入或選擇'}\n readOnly={readonly}\n searchDebounceTime={300}\n value={selectedOptions}\n />\n );\n }\n\n return (\n <AutoComplete\n asyncData={interactiveSearch}\n clearSearchText\n disabled={optionControlDisabled}\n disabledOptionsFilter={interactiveSearch}\n globalPortal\n loading={loading}\n mode=\"single\"\n onChange={(nextOption): void =>\n onChange(field.fieldKey, nextOption?.id ?? undefined)\n }\n onReachBottom={\n dataSourceState.hasNextPage\n ? dataSourceState.onReachBottom\n : undefined\n }\n onSearch={interactiveSearch ? dataSourceState.onSearch : undefined}\n options={options}\n placeholder={field.placeholder ?? '請輸入或選擇'}\n readOnly={readonly}\n searchDebounceTime={300}\n value={selectedOptions[0] ?? null}\n />\n );\n }\n\n if (field.type === 'radio') {\n return (\n <RadioGroup\n disabled={optionControlDisabled}\n name={field.fieldKey}\n onChange={(event): void =>\n onChange(field.fieldKey, event.target.value || undefined)\n }\n options={options}\n value={readStringValue(value)}\n />\n );\n }\n\n if (field.type === 'checkbox') {\n return (\n <CheckboxGroup\n disabled={optionControlDisabled}\n name={field.fieldKey}\n onChange={(event): void =>\n onChange(\n field.fieldKey,\n event.target.values.length ? event.target.values : undefined,\n )\n }\n options={options.map((option) => ({\n label: option.name,\n value: option.id,\n }))}\n value={[...readStringArrayValue(value)]}\n />\n );\n }\n\n if (readFormFieldSelectionMode(field) === 'multiple') {\n return (\n <Select\n disabled={optionControlDisabled}\n loading={loading}\n mode=\"multiple\"\n onChange={(nextOptions): void =>\n onChange(\n field.fieldKey,\n nextOptions.length\n ? nextOptions.map((option) => option.id)\n : undefined,\n )\n }\n onReachBottom={\n dataSourceState.hasNextPage\n ? dataSourceState.onReachBottom\n : undefined\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇一或多個選項'}\n readOnly={readonly}\n value={selectedOptions}\n />\n );\n }\n\n return (\n <Select\n disabled={optionControlDisabled}\n loading={loading}\n onChange={(nextOption): void =>\n onChange(field.fieldKey, nextOption?.id ?? undefined)\n }\n onReachBottom={\n dataSourceState.hasNextPage\n ? dataSourceState.onReachBottom\n : undefined\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇'}\n readOnly={readonly}\n value={selectedOptions[0] ?? null}\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 autocomplete: '請輸入或選擇',\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,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"),a=require("@rytass/bpm-core-shared/form");var o={error:null,hasValue:!1,hasNextPage:!1,invalidValues:[],onReachBottom:()=>void 0,onSearch:()=>void 0,options:[],retry:()=>void 0,status:`IDLE`};function s(e){let n=(0,a.isFormDataSourceFieldDefinition)(e.field)?e.field:null,r=n?e.optionSnapshots?.[n.fieldKey]:void 0,s=JSON.stringify(r??null),c=(0,t.useMemo)(()=>r?.options??[],[s]),l=JSON.stringify(e.formData),d=JSON.stringify(e.initialFormData??{}),f=JSON.stringify(e.schema),p=JSON.stringify(e.uiSchema),m=e.context?.kind,h=e.context?.kind===`runtime`?e.context.instanceId:void 0,g=e.context?.kind===`runtime`?e.context.templateId:void 0,_=n?(0,i.readMissingFormDataSourceDependencies)(n,e.formData):[],v=JSON.stringify(_),y=n?JSON.stringify({bindings:n.dataSource.bindings.map(t=>t.from.kind===`FIELD`?{fieldKey:t.from.fieldKey,value:e.formData[t.from.fieldKey]}:{value:t.from.value}),value:e.initialFormData!==void 0||e.initialValue!==void 0?e.formData[n.fieldKey]:void 0}):``,b=(0,t.useMemo)(()=>{if(m===`preview`)return{kind:`preview`};if(m===`runtime`&&!e.readonly)return{instanceId:h,kind:`runtime`,templateId:g}},[h,m,g,e.readonly]),x=n?(e.initialFormData!==void 0||e.initialValue!==void 0)&&(0,i.readFormDataSourceValueSignature)(e.initialValue)!==(0,i.readFormDataSourceValueSignature)(e.formData[n.fieldKey]):!1,S=n?e.initialFormData!==void 0&&n.dataSource.bindings.some(t=>t.from.kind===`FIELD`?(0,i.readFormDataSourceValueSignature)(e.initialFormData?.[t.from.fieldKey])!==(0,i.readFormDataSourceValueSignature)(e.formData[t.from.fieldKey]):!1):!1,C=!!(r&&(x||S)),[w,T]=(0,t.useState)([]),[E,D]=(0,t.useState)(``),[O,k]=(0,t.useState)(null),[A,j]=(0,t.useState)(n&&r?C?`STALE`:`VALID`:`IDLE`),[M,N]=(0,t.useState)(null),P=(0,t.useRef)(0),F=(0,t.useRef)({cursor:null,searchText:``}),I=(0,t.useMemo)(()=>Object.entries(e.formData).reduce((e,[t,n])=>n===void 0?e:{...e,[t]:n},{}),[l]),L=(0,t.useMemo)(()=>(0,i.mergeFormDataSourceOptions)(c,w),[w,c]),R=(0,t.useMemo)(()=>(0,i.readMissingFormDataSourceOptionValues)(n?e.formData[n.fieldKey]:void 0,L),[n,e.formData,L]),z=u(n?e.formData[n.fieldKey]:void 0),B=(0,t.useCallback)((t,r)=>{if(!n||!b)return;if(_.length>0){j(`WAITING_FOR_DEPENDENCIES`),N(null);return}let a=P.current+1;P.current=a,F.current={cursor:r,searchText:t},j(C?`STALE`:`LOADING`),N(null),(b.kind===`preview`?(0,i.previewFormFieldOptions)({cursor:r,fieldKey:n.fieldKey,formData:I,schema:e.schema,searchText:t,uiSchema:e.uiSchema}):(0,i.readFormFieldOptions)({cursor:r,fieldKey:n.fieldKey,formData:I,instanceId:b.instanceId??null,searchText:t,templateId:b.templateId??null})).then(t=>{P.current===a&&(T(a=>(0,i.mergeFormDataSourceOptions)((0,i.readSelectedFormDataSourceOptions)(n?e.formData[n.fieldKey]:void 0,a),r?a:[],t.options)),k(t.nextCursor),j(`VALID`),N(null))}).catch(e=>{P.current===a&&(j(`UNAVAILABLE`),N((0,i.readFormDataSourceErrorMessage)(e)??(e instanceof Error?e.message:`選項來源暫時無法使用。`)))})},[n,b,C,_.length,I,f,p]),V=(0,t.useRef)(B);V.current=B,(0,t.useEffect)(()=>{if(P.current+=1,T(t=>(0,i.readSelectedFormDataSourceOptions)(n?e.formData[n.fieldKey]:void 0,t)),k(e=>e===null?e:null),D(e=>e&&``),N(e=>e&&null),!n){j(`IDLE`);return}if(_.length>0){j(`WAITING_FOR_DEPENDENCIES`);return}if(!b){j(r?C?`STALE`:`VALID`:e.readonly?`UNAVAILABLE`:`IDLE`);return}if(n.type===`autocomplete`){j(r?C?`STALE`:`VALID`:`IDLE`);return}V.current(``,null)},[n,b,y,d,e.readonly,C,v,s]);let H=(0,t.useCallback)(t=>{D(t),T(t=>(0,i.readSelectedFormDataSourceOptions)(n?e.formData[n.fieldKey]:void 0,t)),k(null),B(t,null)},[B]),U=(0,t.useCallback)(()=>{O&&B(E,O)},[B,O,E]),W=(0,t.useCallback)(()=>{B(F.current.searchText,F.current.cursor)},[B]);return n?{error:M,hasValue:z,hasNextPage:!!O,invalidValues:R,onReachBottom:U,onSearch:H,options:L,retry:W,status:A===`VALID`&&R.length?`INVALID`:A}:o}function c(e){switch(e.status){case`WAITING_FOR_DEPENDENCIES`:return`請先填寫相依欄位。`;case`STALE`:return`選項需要重新載入或驗證。`;case`INVALID`:return e.invalidValues.length?`無法辨識選項:${e.invalidValues.join(`、`)}`:`目前選項已失效,請重新選擇。`;case`UNAVAILABLE`:return e.error??`選項來源暫時無法使用。`;case`VALID`:return e.options.length?null:`目前沒有可用選項。`;default:return null}}function l(e){return e.hasValue&&e.status!==`VALID`}function u(e){return e==null?!1:typeof e==`string`?e.trim().length>0:Array.isArray(e)?e.length>0:!0}var d={alignItems:`start`,display:`grid`,gap:12,gridTemplateColumns:`repeat(12, minmax(0, 1fr))`},f={gridColumn:`1 / -1`},p={alignItems:`start`,display:`grid`,gap:8,minWidth:0},m={minWidth:`100%`,width:`100%`};function h(e){e&&(e.style.width=`100%`)}function g({dataSourceContext:e,dataSourceInitialValues:a,emptyText:o=`尚未建立欄位。`,errors:s={},maxWidth:c,onChange:l,onDataSourceStateChange:u,onUploadAttachment:m,optionSnapshots:h,readonly:g=!1,schema:v,singleColumn:y=!1,uiSchema:b,value:S}){let[C,w]=(0,t.useState)(()=>(0,i.buildFormRendererValues)(v.fields,S??{})),T=(0,t.useMemo)(()=>(0,i.buildFormRendererValues)(v.fields,S??C),[C,v.fields,S]),E=(0,t.useRef)(T),D=(0,t.useMemo)(()=>(0,i.readVisibleFormRendererFields)(v,b,T),[v,b,T]);(0,t.useEffect)(()=>{E.current=T},[T]),(0,t.useEffect)(()=>{w(e=>(0,i.buildFormRendererValues)(v.fields,S??e))},[v.fields,S]);function O(e,t){let n={...E.current,[e]:t};E.current=n,S||w(n),l?.(n)}return D.length?(0,r.jsx)(`div`,{style:{...d,...y?{maxWidth:c,width:`100%`}:{}},children:D.map(t=>(0,r.jsx)(_,{dataSourceContext:e,dataSourceInitialValues:a,field:t,error:s[t.fieldKey]??null,fields:v.fields,onChange:O,onDataSourceStateChange:u,onUploadAttachment:m,optionSnapshots:h,readonly:g,schema:v,style:{...p,gridColumn:`span ${y?12:x(t,b)}`},value:T[t.fieldKey],values:T,uiSchema:b},t.fieldKey))}):(0,r.jsx)(`div`,{style:d,children:(0,r.jsx)(n.Typography,{color:`text-neutral`,style:f,variant:`body`,children:v.fields.length>0?`目前條件下沒有可填寫欄位。`:o})})}function _({dataSourceContext:o,dataSourceInitialValues:l,error:u,field:d,fields:f,onChange:p,onDataSourceStateChange:m,onUploadAttachment:h,optionSnapshots:g,readonly:_,schema:b,style:x,value:S,values:C,uiSchema:w}){let T=(0,i.isFormRendererFieldRequired)(d,f,C),E=_||(0,i.isFormRendererFieldReadonly)(d,f,C),D=s({context:o,field:d,formData:C,initialFormData:l,initialValue:l?.[d.fieldKey],optionSnapshots:g,readonly:E,schema:b,uiSchema:w}),O=c(D);return(0,t.useEffect)(()=>{(0,a.isFormDataSourceFieldDefinition)(d)&&m?.(d.fieldKey,{hasValue:D.hasValue,invalidValues:D.invalidValues,status:D.status})},[JSON.stringify({hasValue:D.hasValue,invalidValues:D.invalidValues,status:D.status}),d.fieldKey,m]),(0,r.jsxs)(`div`,{"data-form-field-key":d.fieldKey,style:x,children:[(0,r.jsx)(e.t,{label:d.label,name:d.fieldKey,required:T,children:y(d,S,E,p,h,o,D)}),u?(0,r.jsx)(n.Typography,{color:`text-error`,variant:`caption`,children:u}):null,O?(0,r.jsxs)(`div`,{style:v,children:[(0,r.jsx)(n.Typography,{color:D.status===`INVALID`||D.status===`UNAVAILABLE`?`text-error`:`text-neutral`,variant:`caption`,children:O}),D.status===`UNAVAILABLE`?(0,r.jsx)(n.Button,{onClick:D.retry,size:`sub`,type:`button`,variant:`base-ghost`,children:`重試`}):null]}):null]})}var v={alignItems:`center`,display:`flex`,gap:8};function y(e,t,o,s,c,l,u){if(e.type===`textarea`)return(0,r.jsx)(n.Textarea,{onChange:t=>s(e.fieldKey,t.target.value),placeholder:e.placeholder??`請輸入多行文字`,readOnly:o,ref:h,rows:3,style:m,value:S(t)});if(e.type===`boolean`)return(0,r.jsx)(n.Toggle,{checked:t===!0,disabled:o,label:`啟用`,onChange:t=>s(e.fieldKey,t.target.checked)});if((0,a.isFormDataSourceFieldDefinition)(e))return b(e,t,o,s,l,u);if((0,a.isFormStaticOptionFieldDefinition)(e)&&e.type===`checkbox`){let a=e.options.map(i.readFieldOptionAsSelectOption);return(0,r.jsx)(n.Select,{mode:`multiple`,onChange:t=>s(e.fieldKey,t?.length?t.map(e=>e.id):void 0),options:a,placeholder:e.placeholder??`請選擇一或多個選項`,readOnly:o,value:a.filter(e=>C(t).includes(e.id))})}if((0,a.isFormStaticOptionFieldDefinition)(e)){let a=e.options.map(i.readFieldOptionAsSelectOption);return(0,r.jsx)(n.Select,{onChange:t=>s(e.fieldKey,t?.id??void 0),options:a,placeholder:e.placeholder??`請選擇`,readOnly:o,value:(0,i.readSelectOption)(a,S(t))})}return e.type===`file_upload`?(0,r.jsx)(n.Upload,{accept:e.acceptedMimeTypes?.join(`,`),disabled:o,maxFiles:e.maxFiles,mode:`button-list`,...(e.maxFiles??1)>1?{multiple:!0}:{},onChange:t=>s(e.fieldKey,t.length?t.map(e=>e.id):void 0),onUpload:async t=>Promise.all(t.map(async t=>({file:t,id:(c?await c(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=>s(e.fieldKey,(0,i.formatDatePickerValue)(t)),placeholder:e.placeholder??T(e.type),readOnly:o,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=>s(e.fieldKey,(0,i.formatDateTimePickerValue)(t)),placeholderLeft:`選擇日期`,placeholderRight:`選擇時間`,readOnly:o,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=>s(e.fieldKey,(0,i.clampOptionalNumber)((0,i.parseOptionalNumberInput)(t.target.value),{max:e.maximum,min:e.minimum})),placeholder:e.placeholder??T(e.type),...o?{readonly:!0}:{},showSpinner:!0,value:w(t),variant:`measure`}):(0,r.jsx)(n.Input,{fullWidth:!0,onChange:t=>s(e.fieldKey,t.target.value),placeholder:e.placeholder??T(e.type),...o?{readonly:!0}:{},value:S(t),variant:`base`})}function b(e,t,o,s,c,l){let u=l.options.map(i.readFieldOptionAsSelectOption),d=(0,i.readSelectedFormDataSourceOptions)(t,l.options).map(i.readFieldOptionAsSelectOption),f=l.status===`LOADING`,p=l.status===`WAITING_FOR_DEPENDENCIES`,m=!!c&&!o,h=o||p;return e.type===`autocomplete`?(0,a.readFormFieldSelectionMode)(e)===`multiple`?(0,r.jsx)(n.AutoComplete,{asyncData:m,clearSearchText:!0,disabled:h,disabledOptionsFilter:m,globalPortal:!0,loading:f,mode:`multiple`,onChange:t=>s(e.fieldKey,t.length?t.map(e=>e.id):void 0),onReachBottom:l.hasNextPage?l.onReachBottom:void 0,onSearch:m?l.onSearch:void 0,options:u,placeholder:e.placeholder??`請輸入或選擇`,readOnly:o,searchDebounceTime:300,value:d}):(0,r.jsx)(n.AutoComplete,{asyncData:m,clearSearchText:!0,disabled:h,disabledOptionsFilter:m,globalPortal:!0,loading:f,mode:`single`,onChange:t=>s(e.fieldKey,t?.id??void 0),onReachBottom:l.hasNextPage?l.onReachBottom:void 0,onSearch:m?l.onSearch:void 0,options:u,placeholder:e.placeholder??`請輸入或選擇`,readOnly:o,searchDebounceTime:300,value:d[0]??null}):e.type===`radio`?(0,r.jsx)(n.RadioGroup,{disabled:h,name:e.fieldKey,onChange:t=>s(e.fieldKey,t.target.value||void 0),options:u,value:S(t)}):e.type===`checkbox`?(0,r.jsx)(n.CheckboxGroup,{disabled:h,name:e.fieldKey,onChange:t=>s(e.fieldKey,t.target.values.length?t.target.values:void 0),options:u.map(e=>({label:e.name,value:e.id})),value:[...C(t)]}):(0,a.readFormFieldSelectionMode)(e)===`multiple`?(0,r.jsx)(n.Select,{disabled:h,loading:f,mode:`multiple`,onChange:t=>s(e.fieldKey,t.length?t.map(e=>e.id):void 0),onReachBottom:l.hasNextPage?l.onReachBottom:void 0,options:u,placeholder:e.placeholder??`請選擇一或多個選項`,readOnly:o,value:d}):(0,r.jsx)(n.Select,{disabled:h,loading:f,onChange:t=>s(e.fieldKey,t?.id??void 0),onReachBottom:l.hasNextPage?l.onReachBottom:void 0,options:u,placeholder:e.placeholder??`請選擇`,readOnly:o,value:d[0]??null})}function x(e,t){return{FULL:12,HALF:6,THIRD:4}[t.layout.find(t=>t.fieldKey===e.fieldKey)?.width??`FULL`]}function S(e){return typeof e==`string`?e:``}function C(e){return Array.isArray(e)?e:[]}function w(e){return typeof e==`number`?String(e):``}function T(e){return{boolean:``,autocomplete:`請輸入或選擇`,checkbox:`請選擇一或多個選項`,date:`請選擇日期`,datetime:`請選擇日期與時間`,file_upload:`請上傳附件`,money:`請輸入金額`,number:`請輸入數字`,radio:`請選擇一個選項`,select:`請選擇一個選項`,text:`請輸入文字`,textarea:`請輸入多行文字`}[e]}Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return g}});
2
- //# sourceMappingURL=FormRendererView-DNtNodNl.cjs.map