@flamingo-stack/openframe-frontend-core 0.0.585 → 0.0.586-1986.5486.1

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 (119) hide show
  1. package/dist/{chunk-276BXVOB.js → chunk-2Y5UT5VF.js} +2 -2
  2. package/dist/{chunk-CTZP2NJQ.js → chunk-3HYHYKNL.js} +4 -4
  3. package/dist/{chunk-7554QJ6R.js → chunk-3JVYM4ZN.js} +5 -5
  4. package/dist/{chunk-QIVZG4XK.cjs → chunk-3WR5R6H6.cjs} +16 -16
  5. package/dist/{chunk-QIVZG4XK.cjs.map → chunk-3WR5R6H6.cjs.map} +1 -1
  6. package/dist/{chunk-BU2KLFRB.cjs → chunk-4VZFJKPT.cjs} +3 -3
  7. package/dist/{chunk-BU2KLFRB.cjs.map → chunk-4VZFJKPT.cjs.map} +1 -1
  8. package/dist/{chunk-VSXFBO4D.js → chunk-5OIXAV4P.js} +2 -2
  9. package/dist/{chunk-GG76BPXJ.js → chunk-6EZGJZVH.js} +2 -2
  10. package/dist/{chunk-HBI7AWUE.cjs → chunk-6ZNWY6WW.cjs} +17 -17
  11. package/dist/{chunk-HBI7AWUE.cjs.map → chunk-6ZNWY6WW.cjs.map} +1 -1
  12. package/dist/{chunk-3F7V7GFU.cjs → chunk-A6ETQEWK.cjs} +405 -293
  13. package/dist/chunk-A6ETQEWK.cjs.map +1 -0
  14. package/dist/{chunk-DZM7KTHE.cjs → chunk-BMORFCT2.cjs} +34 -34
  15. package/dist/{chunk-DZM7KTHE.cjs.map → chunk-BMORFCT2.cjs.map} +1 -1
  16. package/dist/{chunk-4TN6C7ZG.cjs → chunk-C3MRLZUI.cjs} +33 -33
  17. package/dist/{chunk-4TN6C7ZG.cjs.map → chunk-C3MRLZUI.cjs.map} +1 -1
  18. package/dist/{chunk-BNZFLIEG.js → chunk-DQUEVRDU.js} +5 -5
  19. package/dist/{chunk-XK4S47LG.cjs → chunk-EAYMX22G.cjs} +10 -10
  20. package/dist/{chunk-XK4S47LG.cjs.map → chunk-EAYMX22G.cjs.map} +1 -1
  21. package/dist/{chunk-36GXR7BR.js → chunk-KLWJRGNN.js} +3 -3
  22. package/dist/{chunk-JKWWACNI.js → chunk-L4WLYGB4.js} +2 -2
  23. package/dist/{chunk-J4MVZ53H.js → chunk-LV6CORVJ.js} +2 -2
  24. package/dist/{chunk-ULGI56BW.cjs → chunk-M36XSGZV.cjs} +13 -13
  25. package/dist/{chunk-ULGI56BW.cjs.map → chunk-M36XSGZV.cjs.map} +1 -1
  26. package/dist/{chunk-HAIRDHWL.cjs → chunk-NISAGFEM.cjs} +3 -3
  27. package/dist/{chunk-HAIRDHWL.cjs.map → chunk-NISAGFEM.cjs.map} +1 -1
  28. package/dist/{chunk-F5SV627B.cjs → chunk-NYLWMAHP.cjs} +4 -4
  29. package/dist/{chunk-F5SV627B.cjs.map → chunk-NYLWMAHP.cjs.map} +1 -1
  30. package/dist/{chunk-HQRKC6P7.js → chunk-OZNFPQT5.js} +2 -2
  31. package/dist/{chunk-VQ5FMCZA.cjs → chunk-P2CKLIOM.cjs} +49 -49
  32. package/dist/{chunk-VQ5FMCZA.cjs.map → chunk-P2CKLIOM.cjs.map} +1 -1
  33. package/dist/{chunk-FCKOWGTE.js → chunk-PLMJVA2H.js} +2 -2
  34. package/dist/{chunk-5YVCIBUH.cjs → chunk-QZYYNBMI.cjs} +17 -17
  35. package/dist/{chunk-5YVCIBUH.cjs.map → chunk-QZYYNBMI.cjs.map} +1 -1
  36. package/dist/{chunk-SCMESLXP.js → chunk-S7YXLZNG.js} +4 -4
  37. package/dist/{chunk-27DK5GCC.cjs → chunk-SSGM2NKA.cjs} +4 -4
  38. package/dist/{chunk-27DK5GCC.cjs.map → chunk-SSGM2NKA.cjs.map} +1 -1
  39. package/dist/{chunk-FQJBV5ON.cjs → chunk-V7ZJTUV2.cjs} +3 -3
  40. package/dist/{chunk-FQJBV5ON.cjs.map → chunk-V7ZJTUV2.cjs.map} +1 -1
  41. package/dist/{chunk-6VFO4JUH.cjs → chunk-XMK24INA.cjs} +3 -3
  42. package/dist/{chunk-6VFO4JUH.cjs.map → chunk-XMK24INA.cjs.map} +1 -1
  43. package/dist/{chunk-UG6SHUGE.js → chunk-XMTGLQSD.js} +2 -2
  44. package/dist/{chunk-LNKBNY3A.js → chunk-YEQAA6I4.js} +2 -2
  45. package/dist/{chunk-WXL2AR5I.js → chunk-YYC7V7YC.js} +2023 -1911
  46. package/dist/chunk-YYC7V7YC.js.map +1 -0
  47. package/dist/components/case-studies/index.cjs +8 -8
  48. package/dist/components/case-studies/index.js +2 -2
  49. package/dist/components/contact/index.cjs +3 -3
  50. package/dist/components/contact/index.js +2 -2
  51. package/dist/components/docs/index.cjs +6 -6
  52. package/dist/components/docs/index.js +5 -5
  53. package/dist/components/embeds/index.cjs +3 -3
  54. package/dist/components/embeds/index.js +2 -2
  55. package/dist/components/faq/index.cjs +3 -3
  56. package/dist/components/faq/index.js +2 -2
  57. package/dist/components/features/auth/account-details-fields.d.ts +34 -0
  58. package/dist/components/features/auth/account-details-fields.d.ts.map +1 -0
  59. package/dist/components/features/auth/complete-account-form.d.ts.map +1 -1
  60. package/dist/components/features/auth/create-organization-form.d.ts +43 -6
  61. package/dist/components/features/auth/create-organization-form.d.ts.map +1 -1
  62. package/dist/components/features/auth/index.d.ts +2 -0
  63. package/dist/components/features/auth/index.d.ts.map +1 -1
  64. package/dist/components/features/auth/labeled-divider.d.ts +6 -0
  65. package/dist/components/features/auth/labeled-divider.d.ts.map +1 -0
  66. package/dist/components/features/auth/login-form.d.ts +32 -9
  67. package/dist/components/features/auth/login-form.d.ts.map +1 -1
  68. package/dist/components/features/auth/openframe-sso-signup-form.d.ts.map +1 -1
  69. package/dist/components/features/auth/sso-providers.d.ts +1 -1
  70. package/dist/components/features/auth/sso-providers.d.ts.map +1 -1
  71. package/dist/components/features/index.cjs +6 -2
  72. package/dist/components/features/index.cjs.map +1 -1
  73. package/dist/components/features/index.js +5 -1
  74. package/dist/components/help-center-pages/index.cjs +22 -22
  75. package/dist/components/help-center-pages/index.js +13 -13
  76. package/dist/components/index.cjs +33 -29
  77. package/dist/components/index.cjs.map +1 -1
  78. package/dist/components/index.js +16 -12
  79. package/dist/components/index.js.map +1 -1
  80. package/dist/components/meeting-scheduler/index.cjs +18 -18
  81. package/dist/components/meeting-scheduler/index.js +1 -1
  82. package/dist/components/navigation/index.cjs +5 -5
  83. package/dist/components/navigation/index.js +4 -4
  84. package/dist/components/onboarding-guides/index.cjs +5 -5
  85. package/dist/components/onboarding-guides/index.js +4 -4
  86. package/dist/components/tickets/index.cjs +6 -6
  87. package/dist/components/tickets/index.js +5 -5
  88. package/dist/components/ui/index.cjs +2 -2
  89. package/dist/components/ui/index.js +1 -1
  90. package/dist/index.cjs +10 -6
  91. package/dist/index.cjs.map +1 -1
  92. package/dist/index.js +9 -5
  93. package/dist/index.js.map +1 -1
  94. package/package.json +1 -1
  95. package/src/components/features/auth/account-details-fields.tsx +124 -0
  96. package/src/components/features/auth/complete-account-form.tsx +13 -52
  97. package/src/components/features/auth/create-organization-form.tsx +128 -38
  98. package/src/components/features/auth/index.ts +2 -0
  99. package/src/components/features/auth/labeled-divider.tsx +16 -0
  100. package/src/components/features/auth/login-form.tsx +102 -23
  101. package/src/components/features/auth/openframe-sso-signup-form.tsx +11 -43
  102. package/src/components/features/auth/sso-providers.tsx +3 -3
  103. package/src/stories/auth/Login.stories.tsx +15 -5
  104. package/dist/chunk-3F7V7GFU.cjs.map +0 -1
  105. package/dist/chunk-WXL2AR5I.js.map +0 -1
  106. /package/dist/{chunk-276BXVOB.js.map → chunk-2Y5UT5VF.js.map} +0 -0
  107. /package/dist/{chunk-CTZP2NJQ.js.map → chunk-3HYHYKNL.js.map} +0 -0
  108. /package/dist/{chunk-7554QJ6R.js.map → chunk-3JVYM4ZN.js.map} +0 -0
  109. /package/dist/{chunk-VSXFBO4D.js.map → chunk-5OIXAV4P.js.map} +0 -0
  110. /package/dist/{chunk-GG76BPXJ.js.map → chunk-6EZGJZVH.js.map} +0 -0
  111. /package/dist/{chunk-BNZFLIEG.js.map → chunk-DQUEVRDU.js.map} +0 -0
  112. /package/dist/{chunk-36GXR7BR.js.map → chunk-KLWJRGNN.js.map} +0 -0
  113. /package/dist/{chunk-JKWWACNI.js.map → chunk-L4WLYGB4.js.map} +0 -0
  114. /package/dist/{chunk-J4MVZ53H.js.map → chunk-LV6CORVJ.js.map} +0 -0
  115. /package/dist/{chunk-HQRKC6P7.js.map → chunk-OZNFPQT5.js.map} +0 -0
  116. /package/dist/{chunk-FCKOWGTE.js.map → chunk-PLMJVA2H.js.map} +0 -0
  117. /package/dist/{chunk-SCMESLXP.js.map → chunk-S7YXLZNG.js.map} +0 -0
  118. /package/dist/{chunk-UG6SHUGE.js.map → chunk-XMTGLQSD.js.map} +0 -0
  119. /package/dist/{chunk-LNKBNY3A.js.map → chunk-YEQAA6I4.js.map} +0 -0
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  SoftwareInfo,
10
10
  SoftwareSourceBadge,
11
11
  ToolBadge
12
- } from "./chunk-LNKBNY3A.js";
12
+ } from "./chunk-YEQAA6I4.js";
13
13
  import {
14
14
  AppHeader,
15
15
  AppLayout,
@@ -28,14 +28,14 @@ import {
28
28
  SlidingSidebar,
29
29
  TicketAlertsButton,
30
30
  TopNavigation
31
- } from "./chunk-36GXR7BR.js";
31
+ } from "./chunk-KLWJRGNN.js";
32
32
  import {
33
33
  MobileNavigationDropdown,
34
34
  MultiLevelNavigation,
35
35
  StickySectionNav,
36
36
  useSectionNavigation
37
- } from "./chunk-GG76BPXJ.js";
38
- import "./chunk-VSXFBO4D.js";
37
+ } from "./chunk-6EZGJZVH.js";
38
+ import "./chunk-5OIXAV4P.js";
39
39
  import {
40
40
  ADMIN_APPROVAL_REQUEST_CONTEXT_TYPE,
41
41
  AIEnrichButton,
@@ -50,6 +50,7 @@ import {
50
50
  AccordionContent,
51
51
  AccordionItem,
52
52
  AccordionTrigger,
53
+ AccountDetailsFields,
53
54
  AdminFormModal,
54
55
  Alert,
55
56
  AlertDescription,
@@ -218,6 +219,7 @@ import {
218
219
  InviteLinkInvalidModal,
219
220
  JsonDetailList,
220
221
  KnowledgeBaseLinksManager,
222
+ LabeledDivider,
221
223
  LazyMount,
222
224
  ListLoader,
223
225
  ListPageContainer,
@@ -578,7 +580,7 @@ import {
578
580
  withFirstTouchAttribution,
579
581
  withWalkthroughOpenParam,
580
582
  writeDismissCookie
581
- } from "./chunk-WXL2AR5I.js";
583
+ } from "./chunk-YYC7V7YC.js";
582
584
  import "./chunk-L2SLFCXP.js";
583
585
  import "./chunk-BJXDHKUX.js";
584
586
  import {
@@ -1665,6 +1667,7 @@ export {
1665
1667
  AccordionContent,
1666
1668
  AccordionItem,
1667
1669
  AccordionTrigger,
1670
+ AccountDetailsFields,
1668
1671
  ActionsMenu,
1669
1672
  ActionsMenuDropdown,
1670
1673
  AdminContentCard,
@@ -2091,6 +2094,7 @@ export {
2091
2094
  LOG_SEVERITY_COLORS,
2092
2095
  LOG_SEVERITY_LABELS,
2093
2096
  Label,
2097
+ LabeledDivider,
2094
2098
  LaptopIcon,
2095
2099
  LazyMount,
2096
2100
  LinkedInIcon,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/logs-list.tsx","../src/components/log-severity-dot.tsx","../src/types/logs.types.ts","../src/assets/index.ts"],"sourcesContent":["import { type FC, forwardRef, useRef } from 'react';\nimport type { LogsListProps, LogEntry } from '../types/logs.types';\nimport { cn } from '../utils/cn';\nimport { LogSeverityDot } from './log-severity-dot';\nimport { ToolIcon } from './tool-icon';\n\nconst formatTimestamp = (timestamp: string | Date): string => {\n const date = timestamp instanceof Date ? timestamp : new Date(timestamp);\n\n // UTC getters so the timestamp is identical on server (UTC) and client\n // (local) — otherwise React #418 hydration mismatch.\n const year = date.getUTCFullYear();\n const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n const day = String(date.getUTCDate()).padStart(2, '0');\n const hours = String(date.getUTCHours()).padStart(2, '0');\n const minutes = String(date.getUTCMinutes()).padStart(2, '0');\n\n return `${year}/${month}/${day},${hours}:${minutes}`;\n};\n\nconst LogCard: FC<{\n log: LogEntry;\n isLast: boolean;\n showConnector: boolean;\n onClick?: () => void;\n}> = ({ log, isLast, showConnector, onClick }) => {\n return (\n <div className=\"relative\">\n <div\n className={cn(\n 'relative box-border flex w-full items-start gap-3 rounded px-1 py-2',\n 'cursor-pointer transition-colors hover:bg-ods-bg-hover/50',\n )}\n onClick={onClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }}\n >\n <LogSeverityDot severity={log.severity} size=\"md\" />\n\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"text-ods-text-primary text-h6\">{log.title}</p>\n <div className=\"flex items-center gap-2\">\n <p className=\"text-ods-text-secondary text-h5\">{formatTimestamp(log.timestamp)}</p>\n {log.toolType && <ToolIcon toolType={log.toolType} size={16} />}\n </div>\n </div>\n </div>\n\n {showConnector && !isLast && (\n <div\n className=\"absolute left-[15px] w-[2px] bg-ods-border\"\n style={{\n top: '28px',\n bottom: '-10px',\n }}\n aria-hidden=\"true\"\n />\n )}\n </div>\n );\n};\n\nexport const LogsList = forwardRef<HTMLDivElement, LogsListProps>(\n (\n {\n logs,\n maxHeight = '400px',\n showConnector = true,\n onLogClick,\n loading = false,\n emptyMessage = 'No logs to display',\n className,\n },\n ref,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null);\n\n const isFullHeight = maxHeight === '100%';\n\n const getContainerStyles = () => {\n if (isFullHeight) return undefined;\n return { maxHeight, minHeight: '200px' };\n };\n\n const getContainerClasses = () => {\n if (isFullHeight) return 'h-full';\n return '';\n };\n\n if (loading) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-4',\n 'flex items-center justify-center',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div className=\"text-ods-text-muted text-h6\">Loading logs...</div>\n </div>\n );\n }\n\n if (logs.length === 0) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-4',\n 'flex items-center justify-center',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div className=\"text-ods-text-muted text-h6\">{emptyMessage}</div>\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n 'relative rounded-lg border border-ods-border bg-ods-card',\n 'flex flex-col overflow-hidden',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div ref={containerRef} className=\"flex-1 overflow-y-auto px-4 py-3\">\n {logs.map((log, index) => (\n <LogCard\n key={log.id}\n log={log}\n isLast={index === logs.length - 1}\n showConnector={showConnector}\n onClick={() => onLogClick?.(log)}\n />\n ))}\n </div>\n </div>\n );\n },\n);\n\nLogsList.displayName = 'LogsList';\n","import { forwardRef } from 'react';\nimport { type LogSeverityDotProps, LOG_SEVERITY_COLORS, LOG_SEVERITY_LABELS } from '../types/logs.types';\nimport { cn } from '../utils/cn';\n\nexport const LogSeverityDot = forwardRef<HTMLDivElement, LogSeverityDotProps>(\n ({ severity, size = 'md', className }, ref) => {\n const sizeClasses = {\n sm: 'w-4 h-4',\n md: 'w-6 h-6',\n lg: 'w-8 h-8',\n };\n\n const dotSizeClasses = {\n sm: 'w-2 h-2',\n md: 'w-3 h-3',\n lg: 'w-4 h-4',\n };\n\n return (\n <div\n ref={ref}\n className={cn('relative flex shrink-0 items-center justify-center', sizeClasses[size], className)}\n aria-label={`${LOG_SEVERITY_LABELS[severity]} severity`}\n >\n <div\n className={cn('rounded-full', dotSizeClasses[size])}\n style={{ backgroundColor: LOG_SEVERITY_COLORS[severity] }}\n />\n </div>\n );\n },\n);\n\nLogSeverityDot.displayName = 'LogSeverityDot';\n","import type { ToolType } from './tool.types';\n\nexport type LogSeverity = 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL';\n\nexport interface LogEntry {\n id: string;\n ingestDay: string;\n eventType: string;\n severity: LogSeverity;\n title: string;\n timestamp: string | Date;\n toolType?: ToolType;\n toolIcon?: string;\n message?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface LogsListProps {\n logs: LogEntry[];\n maxHeight?: string | number;\n showConnector?: boolean;\n onLogClick?: (log: LogEntry) => void;\n loading?: boolean;\n emptyMessage?: string;\n className?: string;\n}\n\nexport interface LogSeverityDotProps {\n severity: LogSeverity;\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n}\n\nexport const LOG_SEVERITY_COLORS: Record<LogSeverity, string> = {\n DEBUG: '#888888',\n INFO: '#888888',\n WARNING: '#e1b32f',\n ERROR: '#f36666',\n CRITICAL: '#b43b3b',\n};\n\nexport const LOG_SEVERITY_LABELS: Record<LogSeverity, string> = {\n DEBUG: 'Debug',\n INFO: 'Info',\n WARNING: 'Warning',\n ERROR: 'Error',\n CRITICAL: 'Critical',\n};\n","// Assets exports\n// Font files and other static assets\n// Platform utilities will be available when needed\n\nexport const assets = {} as const;\nexport * from './fae-avatar';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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","names":["forwardRef","jsx","forwardRef"]}
1
+ {"version":3,"sources":["../src/components/logs-list.tsx","../src/components/log-severity-dot.tsx","../src/types/logs.types.ts","../src/assets/index.ts"],"sourcesContent":["import { type FC, forwardRef, useRef } from 'react';\nimport type { LogsListProps, LogEntry } from '../types/logs.types';\nimport { cn } from '../utils/cn';\nimport { LogSeverityDot } from './log-severity-dot';\nimport { ToolIcon } from './tool-icon';\n\nconst formatTimestamp = (timestamp: string | Date): string => {\n const date = timestamp instanceof Date ? timestamp : new Date(timestamp);\n\n // UTC getters so the timestamp is identical on server (UTC) and client\n // (local) — otherwise React #418 hydration mismatch.\n const year = date.getUTCFullYear();\n const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n const day = String(date.getUTCDate()).padStart(2, '0');\n const hours = String(date.getUTCHours()).padStart(2, '0');\n const minutes = String(date.getUTCMinutes()).padStart(2, '0');\n\n return `${year}/${month}/${day},${hours}:${minutes}`;\n};\n\nconst LogCard: FC<{\n log: LogEntry;\n isLast: boolean;\n showConnector: boolean;\n onClick?: () => void;\n}> = ({ log, isLast, showConnector, onClick }) => {\n return (\n <div className=\"relative\">\n <div\n className={cn(\n 'relative box-border flex w-full items-start gap-3 rounded px-1 py-2',\n 'cursor-pointer transition-colors hover:bg-ods-bg-hover/50',\n )}\n onClick={onClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }}\n >\n <LogSeverityDot severity={log.severity} size=\"md\" />\n\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"text-ods-text-primary text-h6\">{log.title}</p>\n <div className=\"flex items-center gap-2\">\n <p className=\"text-ods-text-secondary text-h5\">{formatTimestamp(log.timestamp)}</p>\n {log.toolType && <ToolIcon toolType={log.toolType} size={16} />}\n </div>\n </div>\n </div>\n\n {showConnector && !isLast && (\n <div\n className=\"absolute left-[15px] w-[2px] bg-ods-border\"\n style={{\n top: '28px',\n bottom: '-10px',\n }}\n aria-hidden=\"true\"\n />\n )}\n </div>\n );\n};\n\nexport const LogsList = forwardRef<HTMLDivElement, LogsListProps>(\n (\n {\n logs,\n maxHeight = '400px',\n showConnector = true,\n onLogClick,\n loading = false,\n emptyMessage = 'No logs to display',\n className,\n },\n ref,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null);\n\n const isFullHeight = maxHeight === '100%';\n\n const getContainerStyles = () => {\n if (isFullHeight) return undefined;\n return { maxHeight, minHeight: '200px' };\n };\n\n const getContainerClasses = () => {\n if (isFullHeight) return 'h-full';\n return '';\n };\n\n if (loading) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-4',\n 'flex items-center justify-center',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div className=\"text-ods-text-muted text-h6\">Loading logs...</div>\n </div>\n );\n }\n\n if (logs.length === 0) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-4',\n 'flex items-center justify-center',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div className=\"text-ods-text-muted text-h6\">{emptyMessage}</div>\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n 'relative rounded-lg border border-ods-border bg-ods-card',\n 'flex flex-col overflow-hidden',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div ref={containerRef} className=\"flex-1 overflow-y-auto px-4 py-3\">\n {logs.map((log, index) => (\n <LogCard\n key={log.id}\n log={log}\n isLast={index === logs.length - 1}\n showConnector={showConnector}\n onClick={() => onLogClick?.(log)}\n />\n ))}\n </div>\n </div>\n );\n },\n);\n\nLogsList.displayName = 'LogsList';\n","import { forwardRef } from 'react';\nimport { type LogSeverityDotProps, LOG_SEVERITY_COLORS, LOG_SEVERITY_LABELS } from '../types/logs.types';\nimport { cn } from '../utils/cn';\n\nexport const LogSeverityDot = forwardRef<HTMLDivElement, LogSeverityDotProps>(\n ({ severity, size = 'md', className }, ref) => {\n const sizeClasses = {\n sm: 'w-4 h-4',\n md: 'w-6 h-6',\n lg: 'w-8 h-8',\n };\n\n const dotSizeClasses = {\n sm: 'w-2 h-2',\n md: 'w-3 h-3',\n lg: 'w-4 h-4',\n };\n\n return (\n <div\n ref={ref}\n className={cn('relative flex shrink-0 items-center justify-center', sizeClasses[size], className)}\n aria-label={`${LOG_SEVERITY_LABELS[severity]} severity`}\n >\n <div\n className={cn('rounded-full', dotSizeClasses[size])}\n style={{ backgroundColor: LOG_SEVERITY_COLORS[severity] }}\n />\n </div>\n );\n },\n);\n\nLogSeverityDot.displayName = 'LogSeverityDot';\n","import type { ToolType } from './tool.types';\n\nexport type LogSeverity = 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL';\n\nexport interface LogEntry {\n id: string;\n ingestDay: string;\n eventType: string;\n severity: LogSeverity;\n title: string;\n timestamp: string | Date;\n toolType?: ToolType;\n toolIcon?: string;\n message?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface LogsListProps {\n logs: LogEntry[];\n maxHeight?: string | number;\n showConnector?: boolean;\n onLogClick?: (log: LogEntry) => void;\n loading?: boolean;\n emptyMessage?: string;\n className?: string;\n}\n\nexport interface LogSeverityDotProps {\n severity: LogSeverity;\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n}\n\nexport const LOG_SEVERITY_COLORS: Record<LogSeverity, string> = {\n DEBUG: '#888888',\n INFO: '#888888',\n WARNING: '#e1b32f',\n ERROR: '#f36666',\n CRITICAL: '#b43b3b',\n};\n\nexport const LOG_SEVERITY_LABELS: Record<LogSeverity, string> = {\n DEBUG: 'Debug',\n INFO: 'Info',\n WARNING: 'Warning',\n ERROR: 'Error',\n CRITICAL: 'Critical',\n};\n","// Assets exports\n// Font files and other static assets\n// Platform utilities will be available when needed\n\nexport const assets = {} as const;\nexport * from './fae-avatar';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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","names":["forwardRef","jsx","forwardRef"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.585",
3
+ "version": "0.0.586-1986.5486.1",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,124 @@
1
+ 'use client';
2
+
3
+ import type { KeyboardEvent } from 'react';
4
+ import { useDeferredError } from '../../../hooks/ui/use-deferred-error';
5
+ import { Input } from '../../ui/input';
6
+ import { PasswordInput } from '../../ui/password-input';
7
+
8
+ export interface AccountDetailsFieldsProps {
9
+ firstName: string;
10
+ lastName: string;
11
+ password: string;
12
+ confirmPassword: string;
13
+ onFirstNameChange: (value: string) => void;
14
+ onLastNameChange: (value: string) => void;
15
+ onPasswordChange: (value: string) => void;
16
+ onConfirmPasswordChange: (value: string) => void;
17
+ errors?: {
18
+ firstName?: string;
19
+ lastName?: string;
20
+ password?: string;
21
+ confirmPassword?: string;
22
+ };
23
+ disabled?: boolean;
24
+ onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
25
+ /**
26
+ * `paired` puts the two names on one row and the two passwords on another; `stacked` gives each
27
+ * field its own row. Paired is unconditional, with no breakpoint — the approved design pairs
28
+ * them at ~514px and Tailwind's `sm` is 640px, which would stack them on every phone.
29
+ */
30
+ layout?: 'stacked' | 'paired';
31
+ }
32
+
33
+ /**
34
+ * The name-and-password block every account-creating form collects.
35
+ *
36
+ * Shared so the four fields cannot drift apart across the forms that render them — they already
37
+ * had, with one copy wiring `useDeferredError` for blur and another not, so the same field
38
+ * surfaced its error at a different moment depending on which screen you reached it from.
39
+ */
40
+ export function AccountDetailsFields({
41
+ firstName,
42
+ lastName,
43
+ password,
44
+ confirmPassword,
45
+ onFirstNameChange,
46
+ onLastNameChange,
47
+ onPasswordChange,
48
+ onConfirmPasswordChange,
49
+ errors,
50
+ disabled = false,
51
+ onKeyDown,
52
+ layout = 'stacked',
53
+ }: AccountDetailsFieldsProps) {
54
+ const firstNameErr = useDeferredError(errors?.firstName, firstName);
55
+ const lastNameErr = useDeferredError(errors?.lastName, lastName);
56
+ const passwordErr = useDeferredError(errors?.password, password);
57
+ const confirmErr = useDeferredError(errors?.confirmPassword, confirmPassword);
58
+
59
+ const names = [
60
+ <Input
61
+ key="firstName"
62
+ label="First Name"
63
+ placeholder="Enter First Name"
64
+ value={firstName}
65
+ error={firstNameErr.error}
66
+ disabled={disabled}
67
+ onBlur={firstNameErr.onBlur}
68
+ onChange={event => onFirstNameChange(event.target.value)}
69
+ onKeyDown={onKeyDown}
70
+ />,
71
+ <Input
72
+ key="lastName"
73
+ label="Last Name"
74
+ placeholder="Enter Last Name"
75
+ value={lastName}
76
+ error={lastNameErr.error}
77
+ disabled={disabled}
78
+ onBlur={lastNameErr.onBlur}
79
+ onChange={event => onLastNameChange(event.target.value)}
80
+ onKeyDown={onKeyDown}
81
+ />,
82
+ ];
83
+
84
+ const passwords = [
85
+ <PasswordInput
86
+ key="password"
87
+ label="Password"
88
+ placeholder="Enter Password"
89
+ value={password}
90
+ error={passwordErr.error}
91
+ disabled={disabled}
92
+ onBlur={passwordErr.onBlur}
93
+ onChange={event => onPasswordChange(event.target.value)}
94
+ onKeyDown={onKeyDown}
95
+ />,
96
+ <PasswordInput
97
+ key="confirmPassword"
98
+ label="Confirm Password"
99
+ placeholder="Confirm Password"
100
+ value={confirmPassword}
101
+ error={confirmErr.error}
102
+ disabled={disabled}
103
+ onBlur={confirmErr.onBlur}
104
+ onChange={event => onConfirmPasswordChange(event.target.value)}
105
+ onKeyDown={onKeyDown}
106
+ />,
107
+ ];
108
+
109
+ if (layout === 'stacked') {
110
+ return (
111
+ <>
112
+ {names}
113
+ {passwords}
114
+ </>
115
+ );
116
+ }
117
+
118
+ return (
119
+ <>
120
+ <div className="grid grid-cols-2 gap-[var(--spacing-system-l)]">{names}</div>
121
+ <div className="grid grid-cols-2 gap-[var(--spacing-system-l)]">{passwords}</div>
122
+ </>
123
+ );
124
+ }
@@ -1,11 +1,10 @@
1
1
  'use client';
2
2
 
3
3
  import type { KeyboardEvent, ReactNode } from 'react';
4
- import { useDeferredError } from '../../../hooks/ui/use-deferred-error';
5
4
  import { cn } from '../../../utils/cn';
6
5
  import { Button } from '../../ui/button';
7
- import { Input } from '../../ui/input';
8
- import { PasswordInput } from '../../ui/password-input';
6
+ import { AccountDetailsFields } from './account-details-fields';
7
+ import { LabeledDivider } from './labeled-divider';
9
8
  import type { AuthSsoProvider } from './sso-providers';
10
9
  import { SsoProviderButtons } from './sso-providers';
11
10
 
@@ -79,12 +78,6 @@ export function CompleteAccountForm({
79
78
  }: CompleteAccountFormProps) {
80
79
  const fieldsDisabled = disabled || loading;
81
80
 
82
- // Validation messages are deferred while the user is typing (shown on blur or after a pause).
83
- const firstNameErr = useDeferredError(errors?.firstName, firstName);
84
- const lastNameErr = useDeferredError(errors?.lastName, lastName);
85
- const passwordErr = useDeferredError(errors?.password, password);
86
- const confirmErr = useDeferredError(errors?.confirmPassword, confirmPassword);
87
-
88
81
  const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
89
82
  if (event.key === 'Enter' && !fieldsDisabled && !submitDisabled) {
90
83
  onSubmit();
@@ -113,53 +106,21 @@ export function CompleteAccountForm({
113
106
  actionLabel={ssoActionLabel}
114
107
  disabled={fieldsDisabled}
115
108
  />
116
- <div className="flex items-center gap-[var(--spacing-system-s)]">
117
- <div className="h-px flex-1 bg-ods-border" />
118
- <span className="text-ods-text-secondary text-h6">{dividerLabel}</span>
119
- <div className="h-px flex-1 bg-ods-border" />
120
- </div>
109
+ <LabeledDivider label={dividerLabel} />
121
110
  </>
122
111
  )}
123
112
 
124
- {/* Name + password fields — single column on every breakpoint */}
125
- <Input
126
- label="First Name"
127
- placeholder="Enter First Name"
128
- value={firstName}
129
- error={firstNameErr.error}
130
- disabled={fieldsDisabled}
131
- onBlur={firstNameErr.onBlur}
132
- onChange={event => onFirstNameChange(event.target.value)}
133
- onKeyDown={handleKeyDown}
134
- />
135
- <Input
136
- label="Last Name"
137
- placeholder="Enter Last Name"
138
- value={lastName}
139
- error={lastNameErr.error}
140
- disabled={fieldsDisabled}
141
- onBlur={lastNameErr.onBlur}
142
- onChange={event => onLastNameChange(event.target.value)}
143
- onKeyDown={handleKeyDown}
144
- />
145
- <PasswordInput
146
- label="Password"
147
- placeholder="Enter Password"
148
- value={password}
149
- error={passwordErr.error}
150
- disabled={fieldsDisabled}
151
- onBlur={passwordErr.onBlur}
152
- onChange={event => onPasswordChange(event.target.value)}
153
- onKeyDown={handleKeyDown}
154
- />
155
- <PasswordInput
156
- label="Confirm Password"
157
- placeholder="Confirm Password"
158
- value={confirmPassword}
159
- error={confirmErr.error}
113
+ <AccountDetailsFields
114
+ firstName={firstName}
115
+ lastName={lastName}
116
+ password={password}
117
+ confirmPassword={confirmPassword}
118
+ onFirstNameChange={onFirstNameChange}
119
+ onLastNameChange={onLastNameChange}
120
+ onPasswordChange={onPasswordChange}
121
+ onConfirmPasswordChange={onConfirmPasswordChange}
122
+ errors={errors}
160
123
  disabled={fieldsDisabled}
161
- onBlur={confirmErr.onBlur}
162
- onChange={event => onConfirmPasswordChange(event.target.value)}
163
124
  onKeyDown={handleKeyDown}
164
125
  />
165
126
 
@@ -6,29 +6,65 @@ import { cn } from '../../../utils/cn';
6
6
  import { Button } from '../../ui/button';
7
7
  import { CheckboxBlock } from '../../ui/checkbox-block';
8
8
  import { Input } from '../../ui/input';
9
+ import { AccountDetailsFields } from './account-details-fields';
10
+ import { LabeledDivider } from './labeled-divider';
9
11
  import type { AuthSsoProvider } from './sso-providers';
10
12
  import { SsoProviderButtons } from './sso-providers';
11
13
  import { TermsAgreementLabel } from './terms-agreement-label';
12
14
 
13
15
  export interface CreateOrganizationFormProps {
14
- /** Controlled field values */
15
- email: string;
16
+ /**
17
+ * Controlled field values. Omit `email` entirely for flows that neither collect nor show an
18
+ * address — the native Apple signup, where the provider asserted it and may only have handed the
19
+ * app a relay alias the user has never seen. Pass it with `emailReadOnly` to show it uneditable.
20
+ */
21
+ email?: string;
16
22
  organizationName: string;
17
23
  domain: string;
18
24
  agreedToTerms: boolean;
19
- /** Change handlers */
20
- onEmailChange: (value: string) => void;
25
+ // Change handlers
26
+ /** Omit together with `email` when the form collects no address. */
27
+ onEmailChange?: (value: string) => void;
21
28
  onOrganizationNameChange: (value: string) => void;
22
29
  onDomainChange: (value: string) => void;
23
30
  onAgreedToTermsChange: (checked: boolean) => void;
24
31
  /** Primary submit ("Continue") */
25
32
  onSubmit: () => void;
33
+ /**
34
+ * Personal details and credentials, collected on the same screen as the organization. Supply the
35
+ * four handlers to render them; omit them and the form stays organization-only (the SSO paths,
36
+ * where the provider is the credential and there is no password to set).
37
+ */
38
+ firstName?: string;
39
+ lastName?: string;
40
+ password?: string;
41
+ confirmPassword?: string;
42
+ onFirstNameChange?: (value: string) => void;
43
+ onLastNameChange?: (value: string) => void;
44
+ onPasswordChange?: (value: string) => void;
45
+ onConfirmPasswordChange?: (value: string) => void;
46
+ /**
47
+ * Renders the email as a read-only field instead of an input, for flows where the address was
48
+ * fixed by an earlier step and this form cannot change it — a signup that collected it on a
49
+ * previous step, or an SSO login where the provider asserted it and the server reads it from the
50
+ * session. `onEmailChange` is not called in this mode.
51
+ */
52
+ emailReadOnly?: boolean;
53
+ /** Label above the read-only email, e.g. "Signed in with Google". Ignored unless `emailReadOnly`. */
54
+ emailReadOnlyLabel?: string;
55
+ /** Overrides the default heading. */
56
+ title?: string;
57
+ /** Overrides the default sub-heading. */
58
+ subtitle?: ReactNode;
26
59
  /** Suffix rendered inside the domain input, e.g. ".openframe.ai" */
27
60
  domainSuffix?: string;
28
61
  domainPlaceholder?: string;
29
62
  termsUrl?: string;
30
63
  privacyPolicyUrl?: string;
31
64
  submitLabel?: string;
65
+ /** Renders a back action beside the submit when supplied (e.g. to return to an earlier step). */
66
+ onBack?: () => void;
67
+ backLabel?: string;
32
68
  /** Disables just the primary submit (fields stay editable). */
33
69
  submitDisabled?: boolean;
34
70
  loading?: boolean;
@@ -38,6 +74,10 @@ export interface CreateOrganizationFormProps {
38
74
  organizationName?: string;
39
75
  domain?: string;
40
76
  terms?: string;
77
+ firstName?: string;
78
+ lastName?: string;
79
+ password?: string;
80
+ confirmPassword?: string;
41
81
  };
42
82
  /** Informational status under the email field (e.g. live availability). `errors.email` wins. */
43
83
  emailStatus?: { message: string; variant: 'error' | 'warning' | 'success' | 'muted' };
@@ -54,7 +94,7 @@ export interface CreateOrganizationFormProps {
54
94
  onSsoClick?: (provider: AuthSsoProvider) => void;
55
95
  /** Disables the provider buttons (e.g. until the form validates). */
56
96
  ssoDisabled?: boolean;
57
- /** Verb prefix for provider buttons, e.g. "Continue with". Ignored for "openframe". */
97
+ /** Verb prefix for provider buttons, e.g. "Continue with". */
58
98
  ssoActionLabel?: string;
59
99
  /** Divider text between the primary submit and the SSO buttons. */
60
100
  dividerLabel?: string;
@@ -76,11 +116,25 @@ export function CreateOrganizationForm({
76
116
  onDomainChange,
77
117
  onAgreedToTermsChange,
78
118
  onSubmit,
119
+ firstName = '',
120
+ lastName = '',
121
+ password = '',
122
+ confirmPassword = '',
123
+ onFirstNameChange,
124
+ onLastNameChange,
125
+ onPasswordChange,
126
+ onConfirmPasswordChange,
127
+ emailReadOnly = false,
128
+ emailReadOnlyLabel = 'Email',
129
+ title = 'Create Organization',
130
+ subtitle = 'Start your journey with OpenFrame.',
79
131
  domainSuffix,
80
132
  domainPlaceholder = 'company-name',
81
133
  termsUrl = '#',
82
134
  privacyPolicyUrl = '#',
83
135
  submitLabel = 'Continue',
136
+ onBack,
137
+ backLabel = 'Back',
84
138
  submitDisabled = false,
85
139
  loading = false,
86
140
  disabled = false,
@@ -99,12 +153,14 @@ export function CreateOrganizationForm({
99
153
  const fieldsDisabled = disabled || loading;
100
154
 
101
155
  // Validation messages are deferred while the user is typing (shown on blur or after a pause).
102
- const emailErr = useDeferredError(errors?.email, email);
156
+ const emailErr = useDeferredError(errors?.email, email ?? '');
103
157
  const orgNameErr = useDeferredError(errors?.organizationName, organizationName);
104
158
  const domainErr = useDeferredError(errors?.domain, domain);
105
-
106
159
  const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
107
- if (event.key === 'Enter' && !fieldsDisabled) {
160
+ // `submitDisabled` too, not just `fieldsDisabled`: Enter must be the same gate as the button.
161
+ // The fields stay editable while the form is incomplete, so checking only `fieldsDisabled`
162
+ // let Enter submit a form the button was still refusing.
163
+ if (event.key === 'Enter' && !fieldsDisabled && !submitDisabled) {
108
164
  onSubmit();
109
165
  }
110
166
  };
@@ -118,23 +174,27 @@ export function CreateOrganizationForm({
118
174
  >
119
175
  {/* Header */}
120
176
  <div className="flex flex-col">
121
- <h1 className="tracking-[-0.64px] text-ods-text-primary text-h2">Create Organization</h1>
122
- <p className="text-ods-text-secondary text-h4">Start your journey with OpenFrame.</p>
177
+ <h1 className="tracking-[-0.64px] text-ods-text-primary text-h2">{title}</h1>
178
+ <p className="text-ods-text-secondary text-h4">{subtitle}</p>
123
179
  </div>
124
180
 
125
181
  {/* Email + Organization Name — single column on every breakpoint */}
126
- <Input
127
- type="email"
128
- label="Email"
129
- placeholder="username@mail.com"
130
- value={email}
131
- error={emailErr.error ?? emailStatus?.message}
132
- errorVariant={emailErr.error ? 'error' : emailStatus?.variant}
133
- disabled={fieldsDisabled}
134
- onBlur={emailErr.onBlur}
135
- onChange={event => onEmailChange(event.target.value)}
136
- onKeyDown={handleKeyDown}
137
- />
182
+ {email === undefined ? null : emailReadOnly ? (
183
+ <Input type="email" label={emailReadOnlyLabel} value={email} readOnly disabled />
184
+ ) : (
185
+ <Input
186
+ type="email"
187
+ label="Email"
188
+ placeholder="username@mail.com"
189
+ value={email}
190
+ error={emailErr.error ?? emailStatus?.message}
191
+ errorVariant={emailErr.error ? 'error' : emailStatus?.variant}
192
+ disabled={fieldsDisabled}
193
+ onBlur={emailErr.onBlur}
194
+ onChange={event => onEmailChange?.(event.target.value)}
195
+ onKeyDown={handleKeyDown}
196
+ />
197
+ )}
138
198
  <Input
139
199
  label="Organization Name"
140
200
  placeholder="Your Company Name"
@@ -163,6 +223,25 @@ export function CreateOrganizationForm({
163
223
  {domainSlot && <div className="pt-[var(--spacing-system-s)]">{domainSlot}</div>}
164
224
  </div>
165
225
 
226
+ {/* All four handlers or none: the account block is one decision, and checking them here
227
+ rather than through a derived boolean is what lets TypeScript narrow them. */}
228
+ {onFirstNameChange && onLastNameChange && onPasswordChange && onConfirmPasswordChange && (
229
+ <AccountDetailsFields
230
+ layout="paired"
231
+ firstName={firstName}
232
+ lastName={lastName}
233
+ password={password}
234
+ confirmPassword={confirmPassword}
235
+ onFirstNameChange={onFirstNameChange}
236
+ onLastNameChange={onLastNameChange}
237
+ onPasswordChange={onPasswordChange}
238
+ onConfirmPasswordChange={onConfirmPasswordChange}
239
+ errors={errors}
240
+ disabled={fieldsDisabled}
241
+ onKeyDown={handleKeyDown}
242
+ />
243
+ )}
244
+
166
245
  {/* Terms & Privacy — deliberately NOT `truncateLabel`. That prop suits a
167
246
  one-line value; this label is a sentence carrying the Terms and Privacy
168
247
  Policy links, and ellipsizing it clipped the row to "Agree to Terms &
@@ -178,26 +257,37 @@ export function CreateOrganizationForm({
178
257
  onCheckedChange={onAgreedToTermsChange}
179
258
  />
180
259
 
181
- {/* Actions */}
182
- <Button
183
- type="button"
184
- variant="accent"
185
- fullWidth
186
- loading={loading}
187
- disabled={disabled || submitDisabled}
188
- onClick={onSubmit}
189
- >
190
- {submitLabel}
191
- </Button>
260
+ {/* Actions — optional back + submit */}
261
+ <div className="flex items-center gap-[var(--spacing-system-l)]">
262
+ {onBack && (
263
+ <Button
264
+ type="button"
265
+ variant="transparent"
266
+ fullWidth
267
+ className="flex-1"
268
+ disabled={fieldsDisabled}
269
+ onClick={onBack}
270
+ >
271
+ {backLabel}
272
+ </Button>
273
+ )}
274
+ <Button
275
+ type="button"
276
+ variant="accent"
277
+ fullWidth
278
+ className="flex-1"
279
+ loading={loading}
280
+ disabled={disabled || submitDisabled}
281
+ onClick={onSubmit}
282
+ >
283
+ {submitLabel}
284
+ </Button>
285
+ </div>
192
286
 
193
287
  {/* SSO registration alternatives */}
194
288
  {hasSso && (
195
289
  <>
196
- <div className="flex items-center gap-[var(--spacing-system-s)]">
197
- <div className="h-px flex-1 bg-ods-border" />
198
- <span className="text-ods-text-secondary text-h6">{dividerLabel}</span>
199
- <div className="h-px flex-1 bg-ods-border" />
200
- </div>
290
+ <LabeledDivider label={dividerLabel} />
201
291
  <SsoProviderButtons
202
292
  providers={ssoProviders}
203
293
  onSsoClick={onSsoClick}
@@ -1,3 +1,4 @@
1
+ export * from './account-details-fields';
1
2
  export * from './auth-benefits-panel';
2
3
  export * from './auth-branding';
3
4
  export * from './auth-shell';
@@ -5,6 +6,7 @@ export * from './back-to-login-link';
5
6
  export * from './complete-account-form';
6
7
  export * from './create-organization-form';
7
8
  export * from './invite-link-invalid-modal';
9
+ export * from './labeled-divider';
8
10
  export * from './login-form';
9
11
  export * from './openframe-sso-login-form';
10
12
  export * from './openframe-sso-signup-form';
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+
3
+ export interface LabeledDividerProps {
4
+ label: string;
5
+ }
6
+
7
+ /** A horizontal rule with a centred label. */
8
+ export function LabeledDivider({ label }: LabeledDividerProps) {
9
+ return (
10
+ <div className="flex items-center gap-[var(--spacing-system-s)]">
11
+ <div className="h-px flex-1 bg-ods-border" />
12
+ <span className="text-ods-text-secondary text-h6">{label}</span>
13
+ <div className="h-px flex-1 bg-ods-border" />
14
+ </div>
15
+ );
16
+ }