@rytass/bpm-core-react 0.13.3 → 0.13.5

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 (148) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +1 -0
  3. package/dist/chunks/{FormBuilderView-D4xIuPYB.js → FormBuilderView-BYLN6W-P.js} +2 -2
  4. package/dist/chunks/{FormBuilderView-D4xIuPYB.js.map → FormBuilderView-BYLN6W-P.js.map} +1 -1
  5. package/dist/chunks/{FormBuilderView-CLFlfDGe.cjs → FormBuilderView-VmdPVbg7.cjs} +2 -2
  6. package/dist/chunks/{FormBuilderView-CLFlfDGe.cjs.map → FormBuilderView-VmdPVbg7.cjs.map} +1 -1
  7. package/dist/chunks/FormRendererView-Bs8lTb4k.cjs +2 -0
  8. package/dist/chunks/{FormRendererView-BxGT16z0.cjs.map → FormRendererView-Bs8lTb4k.cjs.map} +1 -1
  9. package/dist/chunks/{FormRendererView-DUceSOXe.js → FormRendererView-UPowZZgw.js} +3 -3
  10. package/dist/chunks/{FormRendererView-DUceSOXe.js.map → FormRendererView-UPowZZgw.js.map} +1 -1
  11. package/dist/chunks/{approval-instance-list-page-BjX2kaoF.js → approval-instance-list-page-CPXMP3PL.js} +2 -2
  12. package/dist/chunks/{approval-instance-list-page-BjX2kaoF.js.map → approval-instance-list-page-CPXMP3PL.js.map} +1 -1
  13. package/dist/chunks/{approval-instance-list-page-CWiQvnfE.cjs → approval-instance-list-page-ax0pm8bt.cjs} +2 -2
  14. package/dist/chunks/{approval-instance-list-page-CWiQvnfE.cjs.map → approval-instance-list-page-ax0pm8bt.cjs.map} +1 -1
  15. package/dist/chunks/{compose-Bb-REfoB.js → compose-6P64PO1i.js} +5 -5
  16. package/dist/chunks/{compose-Bb-REfoB.js.map → compose-6P64PO1i.js.map} +1 -1
  17. package/dist/chunks/{compose-DzRYZcqe.cjs → compose-BnSRL4ml.cjs} +2 -2
  18. package/dist/chunks/{compose-DzRYZcqe.cjs.map → compose-BnSRL4ml.cjs.map} +1 -1
  19. package/dist/chunks/{dashboard-page-DJ9vOPga.js → dashboard-page-CeCLV1tp.js} +2 -2
  20. package/dist/chunks/{dashboard-page-DJ9vOPga.js.map → dashboard-page-CeCLV1tp.js.map} +1 -1
  21. package/dist/chunks/{dashboard-page-CH87L5nx.cjs → dashboard-page-DooFJsxM.cjs} +2 -2
  22. package/dist/chunks/{dashboard-page-CH87L5nx.cjs.map → dashboard-page-DooFJsxM.cjs.map} +1 -1
  23. package/dist/chunks/{delegations-vpLtus9g.cjs → delegations-8LsxcQM4.cjs} +2 -2
  24. package/dist/chunks/{delegations-vpLtus9g.cjs.map → delegations-8LsxcQM4.cjs.map} +1 -1
  25. package/dist/chunks/{delegations-0MbJ7CWj.js → delegations-B8gLSt0i.js} +4 -5
  26. package/dist/chunks/{delegations-0MbJ7CWj.js.map → delegations-B8gLSt0i.js.map} +1 -1
  27. package/dist/chunks/{delegations-DyMGIDpp.js → delegations-DRupxJ4_.js} +4 -5
  28. package/dist/chunks/{delegations-DyMGIDpp.js.map → delegations-DRupxJ4_.js.map} +1 -1
  29. package/dist/chunks/{delegations-Bc9psOZ3.cjs → delegations-DlYwMiAW.cjs} +2 -2
  30. package/dist/chunks/{delegations-Bc9psOZ3.cjs.map → delegations-DlYwMiAW.cjs.map} +1 -1
  31. package/dist/chunks/{designer-C6oIO9Kq.js → designer-C3s2kSna.js} +1342 -841
  32. package/dist/chunks/designer-C3s2kSna.js.map +1 -0
  33. package/dist/chunks/designer-_g58R6rQ.cjs +65 -0
  34. package/dist/chunks/designer-_g58R6rQ.cjs.map +1 -0
  35. package/dist/chunks/detail-Db-UOELp.cjs +2 -0
  36. package/dist/chunks/detail-Db-UOELp.cjs.map +1 -0
  37. package/dist/chunks/detail-pYEIk-jW.js +2325 -0
  38. package/dist/chunks/detail-pYEIk-jW.js.map +1 -0
  39. package/dist/chunks/{login-9bCXyjbX.cjs → login-AtVxZBsC.cjs} +2 -2
  40. package/dist/chunks/{login-9bCXyjbX.cjs.map → login-AtVxZBsC.cjs.map} +1 -1
  41. package/dist/chunks/{login-BKxpLibd.js → login-C6qlTC6F.js} +2 -2
  42. package/dist/chunks/{login-BKxpLibd.js.map → login-C6qlTC6F.js.map} +1 -1
  43. package/dist/chunks/{orgs-Cr_7zsAD.js → orgs-BpqVu5ka.js} +2 -2
  44. package/dist/chunks/{orgs-Cr_7zsAD.js.map → orgs-BpqVu5ka.js.map} +1 -1
  45. package/dist/chunks/orgs-D0-5BaHT.cjs +2 -0
  46. package/dist/chunks/{orgs-Bz8hBMoQ.cjs.map → orgs-D0-5BaHT.cjs.map} +1 -1
  47. package/dist/chunks/providers-DHtDZFNA.cjs +2 -0
  48. package/dist/chunks/{providers-BsEn3ikK.cjs.map → providers-DHtDZFNA.cjs.map} +1 -1
  49. package/dist/chunks/{providers-DjLh4oLY.js → providers-J5eyByQj.js} +7 -7
  50. package/dist/chunks/{providers-DjLh4oLY.js.map → providers-J5eyByQj.js.map} +1 -1
  51. package/dist/chunks/{routes-config-fDVHmvXi.cjs → routes-config-C1j_vFKo.cjs} +2 -2
  52. package/dist/chunks/routes-config-C1j_vFKo.cjs.map +1 -0
  53. package/dist/chunks/{routes-config-RBYQtUd0.js → routes-config-yZbESPlw.js} +3 -2
  54. package/dist/chunks/routes-config-yZbESPlw.js.map +1 -0
  55. package/dist/chunks/use-bpm-member-D57LKe_u.js +20 -0
  56. package/dist/chunks/use-bpm-member-D57LKe_u.js.map +1 -0
  57. package/dist/chunks/use-bpm-member-DpNAQtNC.cjs +2 -0
  58. package/dist/chunks/use-bpm-member-DpNAQtNC.cjs.map +1 -0
  59. package/dist/index.cjs +1 -1
  60. package/dist/index.cjs.map +1 -1
  61. package/dist/index.js +19 -24
  62. package/dist/index.js.map +1 -1
  63. package/dist/lib/routes-config.d.ts +2 -0
  64. package/dist/lib/use-bpm-member.d.ts +6 -0
  65. package/dist/next/index.cjs +1 -1
  66. package/dist/next/index.js +2 -2
  67. package/dist/pages/admin/delegations/index.cjs +1 -1
  68. package/dist/pages/admin/delegations/index.js +1 -1
  69. package/dist/pages/admin/orgs/index.cjs +1 -1
  70. package/dist/pages/admin/orgs/index.js +1 -1
  71. package/dist/pages/admin/webhook-endpoints/index.cjs +2 -0
  72. package/dist/pages/admin/webhook-endpoints/index.cjs.map +1 -0
  73. package/dist/pages/admin/webhook-endpoints/index.d.ts +4 -0
  74. package/dist/pages/admin/webhook-endpoints/index.js +14 -0
  75. package/dist/pages/admin/webhook-endpoints/index.js.map +1 -0
  76. package/dist/pages/delegations/index.cjs +1 -1
  77. package/dist/pages/delegations/index.js +1 -1
  78. package/dist/pages/instances/detail/index.cjs +1 -1
  79. package/dist/pages/instances/detail/index.js +1 -1
  80. package/dist/pages/login/index.cjs +1 -1
  81. package/dist/pages/login/index.js +1 -1
  82. package/dist/pages/templates/compose/index.cjs +1 -1
  83. package/dist/pages/templates/compose/index.js +1 -1
  84. package/dist/pages/templates/designer/index.cjs +1 -1
  85. package/dist/pages/templates/designer/index.js +1 -1
  86. package/dist/style.css +1 -1
  87. package/dist/views/admin/delegations/index.cjs +1 -1
  88. package/dist/views/admin/delegations/index.js +1 -1
  89. package/dist/views/admin/index.cjs +1 -1
  90. package/dist/views/admin/index.d.ts +1 -0
  91. package/dist/views/admin/index.js +4 -3
  92. package/dist/views/admin/orgs/index.cjs +1 -1
  93. package/dist/views/admin/orgs/index.js +1 -1
  94. package/dist/views/admin/webhook-endpoints/AdminWebhookEndpointsView.d.ts +8 -0
  95. package/dist/views/admin/webhook-endpoints/index.cjs +2 -0
  96. package/dist/views/admin/webhook-endpoints/index.cjs.map +1 -0
  97. package/dist/views/admin/webhook-endpoints/index.d.ts +1 -0
  98. package/dist/views/admin/webhook-endpoints/index.js +729 -0
  99. package/dist/views/admin/webhook-endpoints/index.js.map +1 -0
  100. package/dist/views/cc/index.cjs +1 -1
  101. package/dist/views/cc/index.js +1 -1
  102. package/dist/views/dashboard/index.cjs +1 -1
  103. package/dist/views/dashboard/index.js +1 -1
  104. package/dist/views/delegations/index.cjs +1 -1
  105. package/dist/views/delegations/index.js +1 -1
  106. package/dist/views/forms/builder/index.cjs +1 -1
  107. package/dist/views/forms/builder/index.js +1 -1
  108. package/dist/views/forms/renderer/index.cjs +1 -1
  109. package/dist/views/forms/renderer/index.js +1 -1
  110. package/dist/views/inbox/index.cjs +1 -1
  111. package/dist/views/inbox/index.js +1 -1
  112. package/dist/views/instances/detail/InstanceDetailView.d.ts +6 -1
  113. package/dist/views/instances/detail/index.cjs +1 -1
  114. package/dist/views/instances/detail/index.d.ts +1 -0
  115. package/dist/views/instances/detail/index.js +2 -2
  116. package/dist/views/instances/detail/sections/InstanceWebhookDeliveriesSection.d.ts +20 -0
  117. package/dist/views/instances/detail/sections/shared.d.ts +37 -4
  118. package/dist/views/instances/new/index.cjs +1 -1
  119. package/dist/views/instances/new/index.js +2 -2
  120. package/dist/views/login/index.cjs +1 -1
  121. package/dist/views/login/index.js +1 -1
  122. package/dist/views/search/index.cjs +1 -1
  123. package/dist/views/search/index.js +1 -1
  124. package/dist/views/sent/index.cjs +1 -1
  125. package/dist/views/sent/index.js +1 -1
  126. package/dist/views/templates/compose/index.cjs +1 -1
  127. package/dist/views/templates/compose/index.js +1 -1
  128. package/dist/views/templates/designer/NotifyWebhookTargetsEditor.d.ts +20 -0
  129. package/dist/views/templates/designer/index.cjs +1 -1
  130. package/dist/views/templates/designer/index.js +1 -1
  131. package/dist/views/templates/designer/notify-webhook-designer.d.ts +74 -0
  132. package/dist/views/templates/index.cjs +1 -1
  133. package/dist/views/templates/index.js +1 -1
  134. package/dist/views/templates/versions/index.cjs +1 -1
  135. package/dist/views/templates/versions/index.js +1 -1
  136. package/package.json +13 -3
  137. package/dist/chunks/FormRendererView-BxGT16z0.cjs +0 -2
  138. package/dist/chunks/designer-C6oIO9Kq.js.map +0 -1
  139. package/dist/chunks/designer-gFUdImeZ.cjs +0 -65
  140. package/dist/chunks/designer-gFUdImeZ.cjs.map +0 -1
  141. package/dist/chunks/detail-BgKgMvYx.js +0 -2044
  142. package/dist/chunks/detail-BgKgMvYx.js.map +0 -1
  143. package/dist/chunks/detail-Dnz5aaI-.cjs +0 -2
  144. package/dist/chunks/detail-Dnz5aaI-.cjs.map +0 -1
  145. package/dist/chunks/orgs-Bz8hBMoQ.cjs +0 -2
  146. package/dist/chunks/providers-BsEn3ikK.cjs +0 -2
  147. package/dist/chunks/routes-config-RBYQtUd0.js.map +0 -1
  148. package/dist/chunks/routes-config-fDVHmvXi.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"login-9bCXyjbX.cjs","names":[],"sources":["../../src/views/login/login.module.scss","../../src/views/login/LoginView.tsx"],"sourcesContent":[".loginPage {\n align-items: center;\n background: var(--mzn-color-bg-body);\n display: flex;\n min-height: 100vh;\n justify-content: center;\n padding: 32px;\n}\n\n.loginPanel {\n border: 1px solid var(--mzn-color-border);\n border-radius: 8px;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 28px;\n max-width: 440px;\n padding: 32px;\n width: 100%;\n}\n\n.brand {\n align-items: center;\n display: flex;\n gap: 14px;\n}\n\n.brandLogo {\n border-radius: 8px;\n height: 40px;\n width: 40px;\n object-fit: contain;\n}\n\n.form {\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n\n.demoUsers {\n border-top: 1px solid var(--mzn-color-border);\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding-top: 20px;\n}\n\n.demoUserList {\n display: grid;\n gap: 8px;\n}\n\n.demoUserButton {\n background: transparent;\n border: 1px solid var(--mzn-color-border);\n border-radius: 6px;\n color: inherit;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n font: inherit;\n gap: 2px;\n padding: 10px 12px;\n text-align: left;\n}\n\n.demoUserButton:hover {\n border-color: var(--mzn-color-primary);\n}\n\n.demoUserButton span:last-child {\n color: var(--mzn-color-text-secondary);\n font-size: 12px;\n}\n","'use client';\n\nimport {\n useCallback,\n useEffect,\n useState,\n type ChangeEvent,\n type FormEvent,\n type ReactElement,\n} from 'react';\nimport { Button, Input, Typography } from '@mezzanine-ui/react';\nimport { LoginIcon } from '@mezzanine-ui/icons';\nimport {\n listApiTestMembers,\n type ApiPublicMember,\n} from '@rytass/bpm-core-client';\nimport { useAuth } from '../../lib/auth-provider';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport styles from './login.module.scss';\n\nexport interface LoginViewProps {\n /**\n * Logo image URL. Renders an inline `<img>` so the view stays framework\n * agnostic (no `next/image` dependency). Defaults to\n * `/rytass-logo.png` — host should serve a static asset at that path or\n * override via this prop.\n */\n readonly logoSrc?: string;\n /**\n * Pre-fill the identifier input. Defaults to the seeded demo account\n * email so the form is usable out of the box.\n */\n readonly defaultIdentifier?: string;\n /**\n * Pre-fill the password input. Defaults to the seeded demo password\n * (`'demo'`). Production hosts should pass an empty string.\n */\n readonly defaultPassword?: string;\n /**\n * Custom redirect target after a successful login. Defaults to reading\n * `?next=` from the host router's search params, falling back to `'/'`.\n */\n readonly defaultNextPath?: string;\n /**\n * Override the BPM admin brand title shown above the form. Defaults to\n * `'BPM Admin'`.\n */\n readonly brandTitle?: string;\n /**\n * Override the brand subtitle shown above the form. Defaults to\n * `'BPM API 登入'`.\n */\n readonly brandSubtitle?: string;\n}\n\nconst DEFAULT_LOGO = '/rytass-logo.png';\nconst DEFAULT_IDENTIFIER = 'lin.ceo@example.internal';\nconst DEFAULT_PASSWORD = 'demo';\n\n/**\n * Login UI for the BPM admin host. Renders the brand mark, identifier /\n * password fields, and a \"test members\" picker fed by\n * `listApiTestMembers()`. Self-contained: composes Mezzanine UI primitives,\n * reads the auth context, and uses the host router adapter to redirect on\n * success.\n *\n * Wrap with `<AuthProvider>` (and indirectly `<RouterAdapterProvider>`)\n * higher in the tree. The `pages/login` subpath ships a thin Next.js\n * wrapper that exports `default` (Server Component) and `metadata`.\n */\nexport function LoginView({\n logoSrc = DEFAULT_LOGO,\n defaultIdentifier = DEFAULT_IDENTIFIER,\n defaultPassword = DEFAULT_PASSWORD,\n defaultNextPath,\n brandTitle = 'BPM Admin',\n brandSubtitle = 'BPM API 登入',\n}: LoginViewProps = {}): ReactElement {\n const router = useRouterAdapter();\n const { loading, login, member } = useAuth();\n const [testMembers, setTestMembers] = useState<readonly ApiPublicMember[]>(\n [],\n );\n const [error, setError] = useState<string | null>(null);\n const [identifier, setIdentifier] = useState(defaultIdentifier);\n const [password, setPassword] = useState(defaultPassword);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (loading || !member) return;\n router.replace(resolveNextPath(defaultNextPath));\n }, [defaultNextPath, loading, member, router]);\n\n useEffect((): void => {\n void (async () => {\n try {\n setTestMembers(await listApiTestMembers());\n } catch {\n setTestMembers([]);\n }\n })();\n }, []);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>): Promise<void> => {\n event.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n await login({ identifier, password });\n router.replace(resolveNextPath(defaultNextPath));\n } catch (loginError: unknown) {\n setError(readErrorMessage(loginError));\n } finally {\n setSubmitting(false);\n }\n },\n [defaultNextPath, identifier, login, password, router],\n );\n\n function handleIdentifierChange(event: ChangeEvent<HTMLInputElement>): void {\n setIdentifier(event.target.value);\n }\n function handlePasswordChange(event: ChangeEvent<HTMLInputElement>): void {\n setPassword(event.target.value);\n }\n\n return (\n <main className={styles.loginPage}>\n <section className={styles.loginPanel}>\n <div className={styles.brand}>\n <img alt=\"\" className={styles.brandLogo} src={logoSrc} />\n <div>\n <Typography variant=\"h3\">{brandTitle}</Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n {brandSubtitle}\n </Typography>\n </div>\n </div>\n\n <form className={styles.form} onSubmit={handleSubmit}>\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 帳號\n </Typography>\n <Input\n fullWidth\n name=\"identifier\"\n onChange={handleIdentifierChange}\n placeholder=\"member id 或 email\"\n value={identifier}\n />\n </label>\n\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 密碼\n </Typography>\n <Input\n fullWidth\n inputType=\"password\"\n name=\"password\"\n onChange={handlePasswordChange}\n value={password}\n variant=\"password\"\n />\n </label>\n\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n <Button\n disabled={submitting}\n icon={LoginIcon}\n iconType=\"leading\"\n type=\"submit\"\n variant=\"base-primary\"\n >\n 登入\n </Button>\n </form>\n\n {testMembers.length ? (\n <div className={styles.demoUsers}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 測試帳號\n </Typography>\n <div className={styles.demoUserList}>\n {testMembers.map((testMember) => (\n <button\n className={styles.demoUserButton}\n key={testMember.memberId}\n onClick={(): void => setIdentifier(testMember.email)}\n type=\"button\"\n >\n <span>{testMember.name}</span>\n <span>{testMember.email}</span>\n </button>\n ))}\n </div>\n </div>\n ) : null}\n </section>\n </main>\n );\n}\n\nfunction resolveNextPath(fallback: string | undefined): string {\n if (fallback && fallback.startsWith('/') && !fallback.startsWith('//')) {\n return fallback;\n }\n const params = readBrowserSearchParams();\n const next = params.get('next');\n if (!next || !next.startsWith('/') || next.startsWith('//')) {\n return '/';\n }\n return next;\n}\n\nfunction readBrowserSearchParams(): URLSearchParams {\n if (typeof window === 'undefined') return new URLSearchParams();\n return new URLSearchParams(window.location.search);\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '登入失敗';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"login-AtVxZBsC.cjs","names":[],"sources":["../../src/views/login/login.module.scss","../../src/views/login/LoginView.tsx"],"sourcesContent":[".loginPage {\n align-items: center;\n background: var(--mzn-color-bg-body);\n display: flex;\n min-height: 100vh;\n justify-content: center;\n padding: 32px;\n}\n\n.loginPanel {\n border: 1px solid var(--mzn-color-border);\n border-radius: 8px;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 28px;\n max-width: 440px;\n padding: 32px;\n width: 100%;\n}\n\n.brand {\n align-items: center;\n display: flex;\n gap: 14px;\n}\n\n.brandLogo {\n border-radius: 8px;\n height: 40px;\n width: 40px;\n object-fit: contain;\n}\n\n.form {\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n\n.demoUsers {\n border-top: 1px solid var(--mzn-color-border);\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding-top: 20px;\n}\n\n.demoUserList {\n display: grid;\n gap: 8px;\n}\n\n.demoUserButton {\n background: transparent;\n border: 1px solid var(--mzn-color-border);\n border-radius: 6px;\n color: inherit;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n font: inherit;\n gap: 2px;\n padding: 10px 12px;\n text-align: left;\n}\n\n.demoUserButton:hover {\n border-color: var(--mzn-color-primary);\n}\n\n.demoUserButton span:last-child {\n color: var(--mzn-color-text-secondary);\n font-size: 12px;\n}\n","'use client';\n\nimport {\n useCallback,\n useEffect,\n useState,\n type ChangeEvent,\n type FormEvent,\n type ReactElement,\n} from 'react';\nimport { Button, Input, Typography } from '@mezzanine-ui/react';\nimport { LoginIcon } from '@mezzanine-ui/icons';\nimport {\n listApiTestMembers,\n type ApiPublicMember,\n} from '@rytass/bpm-core-client';\nimport { useAuth } from '../../lib/auth-provider';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport styles from './login.module.scss';\n\nexport interface LoginViewProps {\n /**\n * Logo image URL. Renders an inline `<img>` so the view stays framework\n * agnostic (no `next/image` dependency). Defaults to\n * `/rytass-logo.png` — host should serve a static asset at that path or\n * override via this prop.\n */\n readonly logoSrc?: string;\n /**\n * Pre-fill the identifier input. Defaults to the seeded demo account\n * email so the form is usable out of the box.\n */\n readonly defaultIdentifier?: string;\n /**\n * Pre-fill the password input. Defaults to the seeded demo password\n * (`'demo'`). Production hosts should pass an empty string.\n */\n readonly defaultPassword?: string;\n /**\n * Custom redirect target after a successful login. Defaults to reading\n * `?next=` from the host router's search params, falling back to `'/'`.\n */\n readonly defaultNextPath?: string;\n /**\n * Override the BPM admin brand title shown above the form. Defaults to\n * `'BPM Admin'`.\n */\n readonly brandTitle?: string;\n /**\n * Override the brand subtitle shown above the form. Defaults to\n * `'BPM API 登入'`.\n */\n readonly brandSubtitle?: string;\n}\n\nconst DEFAULT_LOGO = '/rytass-logo.png';\nconst DEFAULT_IDENTIFIER = 'lin.ceo@example.internal';\nconst DEFAULT_PASSWORD = 'demo';\n\n/**\n * Login UI for the BPM admin host. Renders the brand mark, identifier /\n * password fields, and a \"test members\" picker fed by\n * `listApiTestMembers()`. Self-contained: composes Mezzanine UI primitives,\n * reads the auth context, and uses the host router adapter to redirect on\n * success.\n *\n * Wrap with `<AuthProvider>` (and indirectly `<RouterAdapterProvider>`)\n * higher in the tree. The `pages/login` subpath ships a thin Next.js\n * wrapper that exports `default` (Server Component) and `metadata`.\n */\nexport function LoginView({\n logoSrc = DEFAULT_LOGO,\n defaultIdentifier = DEFAULT_IDENTIFIER,\n defaultPassword = DEFAULT_PASSWORD,\n defaultNextPath,\n brandTitle = 'BPM Admin',\n brandSubtitle = 'BPM API 登入',\n}: LoginViewProps = {}): ReactElement {\n const router = useRouterAdapter();\n const { loading, login, member } = useAuth();\n const [testMembers, setTestMembers] = useState<readonly ApiPublicMember[]>(\n [],\n );\n const [error, setError] = useState<string | null>(null);\n const [identifier, setIdentifier] = useState(defaultIdentifier);\n const [password, setPassword] = useState(defaultPassword);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (loading || !member) return;\n router.replace(resolveNextPath(defaultNextPath));\n }, [defaultNextPath, loading, member, router]);\n\n useEffect((): void => {\n void (async () => {\n try {\n setTestMembers(await listApiTestMembers());\n } catch {\n setTestMembers([]);\n }\n })();\n }, []);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>): Promise<void> => {\n event.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n await login({ identifier, password });\n router.replace(resolveNextPath(defaultNextPath));\n } catch (loginError: unknown) {\n setError(readErrorMessage(loginError));\n } finally {\n setSubmitting(false);\n }\n },\n [defaultNextPath, identifier, login, password, router],\n );\n\n function handleIdentifierChange(event: ChangeEvent<HTMLInputElement>): void {\n setIdentifier(event.target.value);\n }\n function handlePasswordChange(event: ChangeEvent<HTMLInputElement>): void {\n setPassword(event.target.value);\n }\n\n return (\n <main className={styles.loginPage}>\n <section className={styles.loginPanel}>\n <div className={styles.brand}>\n <img alt=\"\" className={styles.brandLogo} src={logoSrc} />\n <div>\n <Typography variant=\"h3\">{brandTitle}</Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n {brandSubtitle}\n </Typography>\n </div>\n </div>\n\n <form className={styles.form} onSubmit={handleSubmit}>\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 帳號\n </Typography>\n <Input\n fullWidth\n name=\"identifier\"\n onChange={handleIdentifierChange}\n placeholder=\"member id 或 email\"\n value={identifier}\n />\n </label>\n\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 密碼\n </Typography>\n <Input\n fullWidth\n inputType=\"password\"\n name=\"password\"\n onChange={handlePasswordChange}\n value={password}\n variant=\"password\"\n />\n </label>\n\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n <Button\n disabled={submitting}\n icon={LoginIcon}\n iconType=\"leading\"\n type=\"submit\"\n variant=\"base-primary\"\n >\n 登入\n </Button>\n </form>\n\n {testMembers.length ? (\n <div className={styles.demoUsers}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 測試帳號\n </Typography>\n <div className={styles.demoUserList}>\n {testMembers.map((testMember) => (\n <button\n className={styles.demoUserButton}\n key={testMember.memberId}\n onClick={(): void => setIdentifier(testMember.email)}\n type=\"button\"\n >\n <span>{testMember.name}</span>\n <span>{testMember.email}</span>\n </button>\n ))}\n </div>\n </div>\n ) : null}\n </section>\n </main>\n );\n}\n\nfunction resolveNextPath(fallback: string | undefined): string {\n if (fallback && fallback.startsWith('/') && !fallback.startsWith('//')) {\n return fallback;\n }\n const params = readBrowserSearchParams();\n const next = params.get('next');\n if (!next || !next.startsWith('/') || next.startsWith('//')) {\n return '/';\n }\n return next;\n}\n\nfunction readBrowserSearchParams(): URLSearchParams {\n if (typeof window === 'undefined') return new URLSearchParams();\n return new URLSearchParams(window.location.search);\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '登入失敗';\n}\n"],"mappings":"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"}
@@ -19,7 +19,7 @@ import '../login.css';var f = {
19
19
  function g({ logoSrc: g = p, defaultIdentifier: v = m, defaultPassword: b = h, defaultNextPath: x, brandTitle: S = "BPM Admin", brandSubtitle: C = "BPM API 登入" } = {}) {
20
20
  let w = e(), { loading: T, login: E, member: D } = t(), [O, k] = i([]), [A, j] = i(null), [M, N] = i(v), [P, F] = i(b), [I, L] = i(!1);
21
21
  r(() => {
22
- T || !D || w.replace(_(x));
22
+ !T && D && w.replace(_(x));
23
23
  }, [
24
24
  x,
25
25
  T,
@@ -155,4 +155,4 @@ function y(e) {
155
155
  //#endregion
156
156
  export { g as t };
157
157
 
158
- //# sourceMappingURL=login-BKxpLibd.js.map
158
+ //# sourceMappingURL=login-C6qlTC6F.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"login-BKxpLibd.js","names":[],"sources":["../../src/views/login/login.module.scss","../../src/views/login/LoginView.tsx"],"sourcesContent":[".loginPage {\n align-items: center;\n background: var(--mzn-color-bg-body);\n display: flex;\n min-height: 100vh;\n justify-content: center;\n padding: 32px;\n}\n\n.loginPanel {\n border: 1px solid var(--mzn-color-border);\n border-radius: 8px;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 28px;\n max-width: 440px;\n padding: 32px;\n width: 100%;\n}\n\n.brand {\n align-items: center;\n display: flex;\n gap: 14px;\n}\n\n.brandLogo {\n border-radius: 8px;\n height: 40px;\n width: 40px;\n object-fit: contain;\n}\n\n.form {\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n\n.demoUsers {\n border-top: 1px solid var(--mzn-color-border);\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding-top: 20px;\n}\n\n.demoUserList {\n display: grid;\n gap: 8px;\n}\n\n.demoUserButton {\n background: transparent;\n border: 1px solid var(--mzn-color-border);\n border-radius: 6px;\n color: inherit;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n font: inherit;\n gap: 2px;\n padding: 10px 12px;\n text-align: left;\n}\n\n.demoUserButton:hover {\n border-color: var(--mzn-color-primary);\n}\n\n.demoUserButton span:last-child {\n color: var(--mzn-color-text-secondary);\n font-size: 12px;\n}\n","'use client';\n\nimport {\n useCallback,\n useEffect,\n useState,\n type ChangeEvent,\n type FormEvent,\n type ReactElement,\n} from 'react';\nimport { Button, Input, Typography } from '@mezzanine-ui/react';\nimport { LoginIcon } from '@mezzanine-ui/icons';\nimport {\n listApiTestMembers,\n type ApiPublicMember,\n} from '@rytass/bpm-core-client';\nimport { useAuth } from '../../lib/auth-provider';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport styles from './login.module.scss';\n\nexport interface LoginViewProps {\n /**\n * Logo image URL. Renders an inline `<img>` so the view stays framework\n * agnostic (no `next/image` dependency). Defaults to\n * `/rytass-logo.png` — host should serve a static asset at that path or\n * override via this prop.\n */\n readonly logoSrc?: string;\n /**\n * Pre-fill the identifier input. Defaults to the seeded demo account\n * email so the form is usable out of the box.\n */\n readonly defaultIdentifier?: string;\n /**\n * Pre-fill the password input. Defaults to the seeded demo password\n * (`'demo'`). Production hosts should pass an empty string.\n */\n readonly defaultPassword?: string;\n /**\n * Custom redirect target after a successful login. Defaults to reading\n * `?next=` from the host router's search params, falling back to `'/'`.\n */\n readonly defaultNextPath?: string;\n /**\n * Override the BPM admin brand title shown above the form. Defaults to\n * `'BPM Admin'`.\n */\n readonly brandTitle?: string;\n /**\n * Override the brand subtitle shown above the form. Defaults to\n * `'BPM API 登入'`.\n */\n readonly brandSubtitle?: string;\n}\n\nconst DEFAULT_LOGO = '/rytass-logo.png';\nconst DEFAULT_IDENTIFIER = 'lin.ceo@example.internal';\nconst DEFAULT_PASSWORD = 'demo';\n\n/**\n * Login UI for the BPM admin host. Renders the brand mark, identifier /\n * password fields, and a \"test members\" picker fed by\n * `listApiTestMembers()`. Self-contained: composes Mezzanine UI primitives,\n * reads the auth context, and uses the host router adapter to redirect on\n * success.\n *\n * Wrap with `<AuthProvider>` (and indirectly `<RouterAdapterProvider>`)\n * higher in the tree. The `pages/login` subpath ships a thin Next.js\n * wrapper that exports `default` (Server Component) and `metadata`.\n */\nexport function LoginView({\n logoSrc = DEFAULT_LOGO,\n defaultIdentifier = DEFAULT_IDENTIFIER,\n defaultPassword = DEFAULT_PASSWORD,\n defaultNextPath,\n brandTitle = 'BPM Admin',\n brandSubtitle = 'BPM API 登入',\n}: LoginViewProps = {}): ReactElement {\n const router = useRouterAdapter();\n const { loading, login, member } = useAuth();\n const [testMembers, setTestMembers] = useState<readonly ApiPublicMember[]>(\n [],\n );\n const [error, setError] = useState<string | null>(null);\n const [identifier, setIdentifier] = useState(defaultIdentifier);\n const [password, setPassword] = useState(defaultPassword);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (loading || !member) return;\n router.replace(resolveNextPath(defaultNextPath));\n }, [defaultNextPath, loading, member, router]);\n\n useEffect((): void => {\n void (async () => {\n try {\n setTestMembers(await listApiTestMembers());\n } catch {\n setTestMembers([]);\n }\n })();\n }, []);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>): Promise<void> => {\n event.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n await login({ identifier, password });\n router.replace(resolveNextPath(defaultNextPath));\n } catch (loginError: unknown) {\n setError(readErrorMessage(loginError));\n } finally {\n setSubmitting(false);\n }\n },\n [defaultNextPath, identifier, login, password, router],\n );\n\n function handleIdentifierChange(event: ChangeEvent<HTMLInputElement>): void {\n setIdentifier(event.target.value);\n }\n function handlePasswordChange(event: ChangeEvent<HTMLInputElement>): void {\n setPassword(event.target.value);\n }\n\n return (\n <main className={styles.loginPage}>\n <section className={styles.loginPanel}>\n <div className={styles.brand}>\n <img alt=\"\" className={styles.brandLogo} src={logoSrc} />\n <div>\n <Typography variant=\"h3\">{brandTitle}</Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n {brandSubtitle}\n </Typography>\n </div>\n </div>\n\n <form className={styles.form} onSubmit={handleSubmit}>\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 帳號\n </Typography>\n <Input\n fullWidth\n name=\"identifier\"\n onChange={handleIdentifierChange}\n placeholder=\"member id 或 email\"\n value={identifier}\n />\n </label>\n\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 密碼\n </Typography>\n <Input\n fullWidth\n inputType=\"password\"\n name=\"password\"\n onChange={handlePasswordChange}\n value={password}\n variant=\"password\"\n />\n </label>\n\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n <Button\n disabled={submitting}\n icon={LoginIcon}\n iconType=\"leading\"\n type=\"submit\"\n variant=\"base-primary\"\n >\n 登入\n </Button>\n </form>\n\n {testMembers.length ? (\n <div className={styles.demoUsers}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 測試帳號\n </Typography>\n <div className={styles.demoUserList}>\n {testMembers.map((testMember) => (\n <button\n className={styles.demoUserButton}\n key={testMember.memberId}\n onClick={(): void => setIdentifier(testMember.email)}\n type=\"button\"\n >\n <span>{testMember.name}</span>\n <span>{testMember.email}</span>\n </button>\n ))}\n </div>\n </div>\n ) : null}\n </section>\n </main>\n );\n}\n\nfunction resolveNextPath(fallback: string | undefined): string {\n if (fallback && fallback.startsWith('/') && !fallback.startsWith('//')) {\n return fallback;\n }\n const params = readBrowserSearchParams();\n const next = params.get('next');\n if (!next || !next.startsWith('/') || next.startsWith('//')) {\n return '/';\n }\n return next;\n}\n\nfunction readBrowserSearchParams(): URLSearchParams {\n if (typeof window === 'undefined') return new URLSearchParams();\n return new URLSearchParams(window.location.search);\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '登入失敗';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"login-C6qlTC6F.js","names":[],"sources":["../../src/views/login/login.module.scss","../../src/views/login/LoginView.tsx"],"sourcesContent":[".loginPage {\n align-items: center;\n background: var(--mzn-color-bg-body);\n display: flex;\n min-height: 100vh;\n justify-content: center;\n padding: 32px;\n}\n\n.loginPanel {\n border: 1px solid var(--mzn-color-border);\n border-radius: 8px;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 28px;\n max-width: 440px;\n padding: 32px;\n width: 100%;\n}\n\n.brand {\n align-items: center;\n display: flex;\n gap: 14px;\n}\n\n.brandLogo {\n border-radius: 8px;\n height: 40px;\n width: 40px;\n object-fit: contain;\n}\n\n.form {\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n\n.demoUsers {\n border-top: 1px solid var(--mzn-color-border);\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding-top: 20px;\n}\n\n.demoUserList {\n display: grid;\n gap: 8px;\n}\n\n.demoUserButton {\n background: transparent;\n border: 1px solid var(--mzn-color-border);\n border-radius: 6px;\n color: inherit;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n font: inherit;\n gap: 2px;\n padding: 10px 12px;\n text-align: left;\n}\n\n.demoUserButton:hover {\n border-color: var(--mzn-color-primary);\n}\n\n.demoUserButton span:last-child {\n color: var(--mzn-color-text-secondary);\n font-size: 12px;\n}\n","'use client';\n\nimport {\n useCallback,\n useEffect,\n useState,\n type ChangeEvent,\n type FormEvent,\n type ReactElement,\n} from 'react';\nimport { Button, Input, Typography } from '@mezzanine-ui/react';\nimport { LoginIcon } from '@mezzanine-ui/icons';\nimport {\n listApiTestMembers,\n type ApiPublicMember,\n} from '@rytass/bpm-core-client';\nimport { useAuth } from '../../lib/auth-provider';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport styles from './login.module.scss';\n\nexport interface LoginViewProps {\n /**\n * Logo image URL. Renders an inline `<img>` so the view stays framework\n * agnostic (no `next/image` dependency). Defaults to\n * `/rytass-logo.png` — host should serve a static asset at that path or\n * override via this prop.\n */\n readonly logoSrc?: string;\n /**\n * Pre-fill the identifier input. Defaults to the seeded demo account\n * email so the form is usable out of the box.\n */\n readonly defaultIdentifier?: string;\n /**\n * Pre-fill the password input. Defaults to the seeded demo password\n * (`'demo'`). Production hosts should pass an empty string.\n */\n readonly defaultPassword?: string;\n /**\n * Custom redirect target after a successful login. Defaults to reading\n * `?next=` from the host router's search params, falling back to `'/'`.\n */\n readonly defaultNextPath?: string;\n /**\n * Override the BPM admin brand title shown above the form. Defaults to\n * `'BPM Admin'`.\n */\n readonly brandTitle?: string;\n /**\n * Override the brand subtitle shown above the form. Defaults to\n * `'BPM API 登入'`.\n */\n readonly brandSubtitle?: string;\n}\n\nconst DEFAULT_LOGO = '/rytass-logo.png';\nconst DEFAULT_IDENTIFIER = 'lin.ceo@example.internal';\nconst DEFAULT_PASSWORD = 'demo';\n\n/**\n * Login UI for the BPM admin host. Renders the brand mark, identifier /\n * password fields, and a \"test members\" picker fed by\n * `listApiTestMembers()`. Self-contained: composes Mezzanine UI primitives,\n * reads the auth context, and uses the host router adapter to redirect on\n * success.\n *\n * Wrap with `<AuthProvider>` (and indirectly `<RouterAdapterProvider>`)\n * higher in the tree. The `pages/login` subpath ships a thin Next.js\n * wrapper that exports `default` (Server Component) and `metadata`.\n */\nexport function LoginView({\n logoSrc = DEFAULT_LOGO,\n defaultIdentifier = DEFAULT_IDENTIFIER,\n defaultPassword = DEFAULT_PASSWORD,\n defaultNextPath,\n brandTitle = 'BPM Admin',\n brandSubtitle = 'BPM API 登入',\n}: LoginViewProps = {}): ReactElement {\n const router = useRouterAdapter();\n const { loading, login, member } = useAuth();\n const [testMembers, setTestMembers] = useState<readonly ApiPublicMember[]>(\n [],\n );\n const [error, setError] = useState<string | null>(null);\n const [identifier, setIdentifier] = useState(defaultIdentifier);\n const [password, setPassword] = useState(defaultPassword);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (loading || !member) return;\n router.replace(resolveNextPath(defaultNextPath));\n }, [defaultNextPath, loading, member, router]);\n\n useEffect((): void => {\n void (async () => {\n try {\n setTestMembers(await listApiTestMembers());\n } catch {\n setTestMembers([]);\n }\n })();\n }, []);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>): Promise<void> => {\n event.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n await login({ identifier, password });\n router.replace(resolveNextPath(defaultNextPath));\n } catch (loginError: unknown) {\n setError(readErrorMessage(loginError));\n } finally {\n setSubmitting(false);\n }\n },\n [defaultNextPath, identifier, login, password, router],\n );\n\n function handleIdentifierChange(event: ChangeEvent<HTMLInputElement>): void {\n setIdentifier(event.target.value);\n }\n function handlePasswordChange(event: ChangeEvent<HTMLInputElement>): void {\n setPassword(event.target.value);\n }\n\n return (\n <main className={styles.loginPage}>\n <section className={styles.loginPanel}>\n <div className={styles.brand}>\n <img alt=\"\" className={styles.brandLogo} src={logoSrc} />\n <div>\n <Typography variant=\"h3\">{brandTitle}</Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n {brandSubtitle}\n </Typography>\n </div>\n </div>\n\n <form className={styles.form} onSubmit={handleSubmit}>\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 帳號\n </Typography>\n <Input\n fullWidth\n name=\"identifier\"\n onChange={handleIdentifierChange}\n placeholder=\"member id 或 email\"\n value={identifier}\n />\n </label>\n\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 密碼\n </Typography>\n <Input\n fullWidth\n inputType=\"password\"\n name=\"password\"\n onChange={handlePasswordChange}\n value={password}\n variant=\"password\"\n />\n </label>\n\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n <Button\n disabled={submitting}\n icon={LoginIcon}\n iconType=\"leading\"\n type=\"submit\"\n variant=\"base-primary\"\n >\n 登入\n </Button>\n </form>\n\n {testMembers.length ? (\n <div className={styles.demoUsers}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 測試帳號\n </Typography>\n <div className={styles.demoUserList}>\n {testMembers.map((testMember) => (\n <button\n className={styles.demoUserButton}\n key={testMember.memberId}\n onClick={(): void => setIdentifier(testMember.email)}\n type=\"button\"\n >\n <span>{testMember.name}</span>\n <span>{testMember.email}</span>\n </button>\n ))}\n </div>\n </div>\n ) : null}\n </section>\n </main>\n );\n}\n\nfunction resolveNextPath(fallback: string | undefined): string {\n if (fallback && fallback.startsWith('/') && !fallback.startsWith('//')) {\n return fallback;\n }\n const params = readBrowserSearchParams();\n const next = params.get('next');\n if (!next || !next.startsWith('/') || next.startsWith('//')) {\n return '/';\n }\n return next;\n}\n\nfunction readBrowserSearchParams(): URLSearchParams {\n if (typeof window === 'undefined') return new URLSearchParams();\n return new URLSearchParams(window.location.search);\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '登入失敗';\n}\n"],"mappings":";;;;;;;;;;;;;;;;;GCuDM,IAAe,oBACf,IAAqB,4BACrB,IAAmB;AAazB,SAAgB,EAAU,EACxB,aAAU,GACV,uBAAoB,GACpB,qBAAkB,GAClB,oBACA,gBAAa,aACb,mBAAgB,iBACE,CAAC,GAAiB;CACpC,IAAM,IAAS,EAAiB,GAC1B,EAAE,YAAS,UAAO,cAAW,EAAQ,GACrC,CAAC,GAAa,KAAkB,EACpC,CAAC,CACH,GACM,CAAC,GAAO,KAAY,EAAwB,IAAI,GAChD,CAAC,GAAY,KAAiB,EAAS,CAAiB,GACxD,CAAC,GAAU,KAAe,EAAS,CAAe,GAClD,CAAC,GAAY,KAAiB,EAAS,EAAK;CAOlD,AALA,QAAsB;EAChB,MAAY,KAChB,EAAO,QAAQ,EAAgB,CAAe,CAAC;CACjD,GAAG;EAAC;EAAiB;EAAS;EAAQ;CAAM,CAAC,GAE7C,QAAsB;EACpB,CAAM,YAAY;GAChB,IAAI;IACF,EAAe,MAAM,EAAmB,CAAC;GAC3C,QAAQ;IACN,EAAe,CAAC,CAAC;GACnB;EACF,EAAA,CAAG;CACL,GAAG,CAAC,CAAC;CAEL,IAAM,IAAe,EACnB,OAAO,MAAqD;EAG1D,AAFA,EAAM,eAAe,GACrB,EAAS,IAAI,GACb,EAAc,EAAI;EAClB,IAAI;GAEF,AADA,MAAM,EAAM;IAAE;IAAY;GAAS,CAAC,GACpC,EAAO,QAAQ,EAAgB,CAAe,CAAC;EACjD,SAAS,GAAqB;GAC5B,EAAS,EAAiB,CAAU,CAAC;EACvC,UAAU;GACR,EAAc,EAAK;EACrB;CACF,GACA;EAAC;EAAiB;EAAY;EAAO;EAAU;CAAM,CACvD;CAEA,SAAS,EAAuB,GAA4C;EAC1E,EAAc,EAAM,OAAO,KAAK;CAClC;CACA,SAAS,EAAqB,GAA4C;EACxE,EAAY,EAAM,OAAO,KAAK;CAChC;CAEA,OACE,kBAAC,QAAD;EAAM,WAAW,EAAO;EACtB,UAAA,kBAAC,WAAD;GAAS,WAAW,EAAO;GAA3B,UAAA;IACE,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAvB,UAAA,CACE,kBAAC,OAAD;MAAK,KAAI;MAAG,WAAW,EAAO;MAAW,KAAK;KAAU,CAAA,GACxD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MAAY,SAAQ;MAAM,UAAA;KAAuB,CAAA,GACjD,kBAAC,GAAD;MAAY,OAAM;MAAe,SAAQ;MACtC,UAAA;KACS,CAAA,CACT,EAAA,CAAA,CACF;;IAEL,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAM,UAAU;KAAxC,UAAA;MACE,kBAAC,SAAD,EAAA,UAAA,CACE,kBAAC,GAAD;OAAY,OAAM;OAAe,SAAQ;OAAU,UAAA;MAEvC,CAAA,GACZ,kBAAC,GAAD;OACE,WAAA;OACA,MAAK;OACL,UAAU;OACV,aAAY;OACZ,OAAO;MACR,CAAA,CACI,EAAA,CAAA;MAEP,kBAAC,SAAD,EAAA,UAAA,CACE,kBAAC,GAAD;OAAY,OAAM;OAAe,SAAQ;OAAU,UAAA;MAEvC,CAAA,GACZ,kBAAC,GAAD;OACE,WAAA;OACA,WAAU;OACV,MAAK;OACL,UAAU;OACV,OAAO;OACP,SAAQ;MACT,CAAA,CACI,EAAA,CAAA;MAEN,IACC,kBAAC,GAAD;OAAY,OAAM;OAAa,SAAQ;OACpC,UAAA;MACS,CAAA,IACV;MAEJ,kBAAC,GAAD;OACE,UAAU;OACV,MAAM;OACN,UAAS;OACT,MAAK;OACL,SAAQ;OACT,UAAA;MAEO,CAAA;KACJ;;IAEL,EAAY,SACX,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAvB,UAAA,CACE,kBAAC,GAAD;MAAY,OAAM;MAAe,SAAQ;MAAU,UAAA;KAEvC,CAAA,GACZ,kBAAC,OAAD;MAAK,WAAW,EAAO;MACpB,UAAA,EAAY,KAAK,MAChB,kBAAC,UAAD;OACE,WAAW,EAAO;OAElB,eAAqB,EAAc,EAAW,KAAK;OACnD,MAAK;OAJP,UAAA,CAME,kBAAC,QAAD,EAAA,UAAO,EAAW,KAAW,CAAA,GAC7B,kBAAC,QAAD,EAAA,UAAO,EAAW,MAAY,CAAA,CACxB;MAND,GAAA,EAAW,QAMV,CACT;KACE,CAAA,CACF;IACH,CAAA,IAAA;GACG;;CACL,CAAA;AAEV;AAEA,SAAS,EAAgB,GAAsC;CAC7D,IAAI,KAAY,EAAS,WAAW,GAAG,KAAK,CAAC,EAAS,WAAW,IAAI,GACnE,OAAO;CAGT,IAAM,IADS,EACF,CAAA,CAAO,IAAI,MAAM;CAI9B,OAHI,CAAC,KAAQ,CAAC,EAAK,WAAW,GAAG,KAAK,EAAK,WAAW,IAAI,IACjD,MAEF;AACT;AAEA,SAAS,IAA2C;CAElD,OADI,OAAO,SAAW,MAAoB,IAAI,gBAAgB,IACvD,IAAI,gBAAgB,OAAO,SAAS,MAAM;AACnD;AAEA,SAAS,EAAiB,GAAwB;CAChD,OAAO,aAAiB,QAAQ,EAAM,UAAU;AAClD"}
@@ -177,7 +177,7 @@ var W = {
177
177
  if (!e) return;
178
178
  k.current = null;
179
179
  let t = O.current, n = R.nodes.find((t) => t.id === e);
180
- !t || !n || t.setCenter(n.position.x + (n.width ?? K) / 2, n.position.y + (n.initialHeight ?? Ee) / 2, {
180
+ t && n && t.setCenter(n.position.x + (n.width ?? K) / 2, n.position.y + (n.initialHeight ?? Ee) / 2, {
181
181
  duration: 200,
182
182
  zoom: t.getZoom()
183
183
  });
@@ -2084,4 +2084,4 @@ function Qt(e) {
2084
2084
  //#endregion
2085
2085
  export { mt as t };
2086
2086
 
2087
- //# sourceMappingURL=orgs-Cr_7zsAD.js.map
2087
+ //# sourceMappingURL=orgs-BpqVu5ka.js.map