@flamingo-stack/openframe-frontend-core 0.0.399 → 0.0.400

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 (116) hide show
  1. package/dist/{chunk-4K5XJ5EJ.js → chunk-463X3AW2.js} +3 -3
  2. package/dist/{chunk-XBCAY6NE.js → chunk-4HAVKWTJ.js} +3 -3
  3. package/dist/{chunk-G5NDKTX6.cjs → chunk-556BG7SX.cjs} +40 -40
  4. package/dist/{chunk-G5NDKTX6.cjs.map → chunk-556BG7SX.cjs.map} +1 -1
  5. package/dist/{chunk-2L6ALD2Q.js → chunk-56XCRZ7I.js} +2 -2
  6. package/dist/{chunk-BSJO5VFV.js → chunk-6VR7BJF6.js} +5 -5
  7. package/dist/{chunk-VOHOA3WV.cjs → chunk-6XQJSN7G.cjs} +15 -15
  8. package/dist/{chunk-VOHOA3WV.cjs.map → chunk-6XQJSN7G.cjs.map} +1 -1
  9. package/dist/{chunk-QNYNXSYQ.cjs → chunk-ABRDOCVN.cjs} +7 -7
  10. package/dist/{chunk-QNYNXSYQ.cjs.map → chunk-ABRDOCVN.cjs.map} +1 -1
  11. package/dist/{chunk-ZSZRJWY3.js → chunk-DH6HTYOV.js} +153 -134
  12. package/dist/chunk-DH6HTYOV.js.map +1 -0
  13. package/dist/{chunk-YWCCKB4J.cjs → chunk-EFTKJFEF.cjs} +5 -5
  14. package/dist/{chunk-YWCCKB4J.cjs.map → chunk-EFTKJFEF.cjs.map} +1 -1
  15. package/dist/{chunk-G3A7QHCX.js → chunk-FHEIG7QO.js} +2 -2
  16. package/dist/{chunk-Z5ERSGP2.js → chunk-I4XG5PJA.js} +2 -2
  17. package/dist/{chunk-D5IHYUBY.cjs → chunk-ILWSJCWD.cjs} +29 -29
  18. package/dist/{chunk-D5IHYUBY.cjs.map → chunk-ILWSJCWD.cjs.map} +1 -1
  19. package/dist/{chunk-JWBRDNYH.cjs → chunk-J4XR6YYZ.cjs} +23 -4
  20. package/dist/chunk-J4XR6YYZ.cjs.map +1 -0
  21. package/dist/{chunk-7OKNKZBW.cjs → chunk-J6IQQJJQ.cjs} +566 -531
  22. package/dist/chunk-J6IQQJJQ.cjs.map +1 -0
  23. package/dist/{chunk-O5NA3ULU.cjs → chunk-KIC4ZEZ7.cjs} +73 -73
  24. package/dist/{chunk-O5NA3ULU.cjs.map → chunk-KIC4ZEZ7.cjs.map} +1 -1
  25. package/dist/{chunk-VVKWNVKE.js → chunk-LAL63W5J.js} +6 -6
  26. package/dist/{chunk-JBLBFJ4N.cjs → chunk-MFRP2UDK.cjs} +32 -32
  27. package/dist/{chunk-JBLBFJ4N.cjs.map → chunk-MFRP2UDK.cjs.map} +1 -1
  28. package/dist/{chunk-A6KGHQRF.js → chunk-MQRTT3DO.js} +6 -6
  29. package/dist/{chunk-4KWIQEZT.js → chunk-MTBFE3JF.js} +2 -2
  30. package/dist/{chunk-RIC4TCPD.cjs → chunk-OPD5V57R.cjs} +19 -19
  31. package/dist/{chunk-RIC4TCPD.cjs.map → chunk-OPD5V57R.cjs.map} +1 -1
  32. package/dist/{chunk-CRRH7RJX.js → chunk-PD5MXNTJ.js} +5 -5
  33. package/dist/{chunk-WBLRUO3F.cjs → chunk-Q3AO2QWK.cjs} +3 -3
  34. package/dist/{chunk-WBLRUO3F.cjs.map → chunk-Q3AO2QWK.cjs.map} +1 -1
  35. package/dist/{chunk-4PEC5KU6.cjs → chunk-QGQ76SSR.cjs} +12 -12
  36. package/dist/{chunk-4PEC5KU6.cjs.map → chunk-QGQ76SSR.cjs.map} +1 -1
  37. package/dist/{chunk-ZDT2MBKE.cjs → chunk-RSFHAFZN.cjs} +40 -40
  38. package/dist/{chunk-ZDT2MBKE.cjs.map → chunk-RSFHAFZN.cjs.map} +1 -1
  39. package/dist/{chunk-4H2ICJYB.js → chunk-RYPCNUXA.js} +4 -4
  40. package/dist/{chunk-FXWURWDU.js → chunk-UFP45JLE.js} +3 -3
  41. package/dist/{chunk-2XVOYDRF.js → chunk-UYBNOHTC.js} +57 -22
  42. package/dist/{chunk-2XVOYDRF.js.map → chunk-UYBNOHTC.js.map} +1 -1
  43. package/dist/{chunk-NCW22SII.cjs → chunk-VTSEL7CJ.cjs} +73 -73
  44. package/dist/{chunk-NCW22SII.cjs.map → chunk-VTSEL7CJ.cjs.map} +1 -1
  45. package/dist/components/case-studies/index.cjs +9 -9
  46. package/dist/components/case-studies/index.js +3 -3
  47. package/dist/components/chat/index.cjs +3 -3
  48. package/dist/components/chat/index.js +2 -2
  49. package/dist/components/contact/index.cjs +4 -4
  50. package/dist/components/contact/index.js +3 -3
  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 +4 -4
  54. package/dist/components/embeds/index.js +3 -3
  55. package/dist/components/faq/index.cjs +5 -5
  56. package/dist/components/faq/index.js +4 -4
  57. package/dist/components/features/auth/auth-benefits-panel.d.ts.map +1 -1
  58. package/dist/components/features/auth/complete-account-form.d.ts.map +1 -1
  59. package/dist/components/features/auth/create-organization-form.d.ts.map +1 -1
  60. package/dist/components/features/auth/login-form.d.ts.map +1 -1
  61. package/dist/components/features/auth/openframe-sso-login-form.d.ts.map +1 -1
  62. package/dist/components/features/auth/openframe-sso-signup-form.d.ts.map +1 -1
  63. package/dist/components/features/auth/password-reset-form.d.ts.map +1 -1
  64. package/dist/components/features/index.cjs +3 -3
  65. package/dist/components/features/index.js +2 -2
  66. package/dist/components/help-center-pages/index.cjs +22 -22
  67. package/dist/components/help-center-pages/index.js +13 -13
  68. package/dist/components/index.cjs +125 -125
  69. package/dist/components/index.js +11 -11
  70. package/dist/components/navigation/index.cjs +3 -3
  71. package/dist/components/navigation/index.js +2 -2
  72. package/dist/components/onboarding-guides/index.cjs +7 -7
  73. package/dist/components/onboarding-guides/index.js +6 -6
  74. package/dist/components/related-content/index.cjs +5 -5
  75. package/dist/components/related-content/index.js +4 -4
  76. package/dist/components/tickets/index.cjs +6 -6
  77. package/dist/components/tickets/index.js +5 -5
  78. package/dist/components/ui/index.cjs +3 -3
  79. package/dist/components/ui/index.js +2 -2
  80. package/dist/hooks/index.cjs +4 -2
  81. package/dist/hooks/index.cjs.map +1 -1
  82. package/dist/hooks/index.js +3 -1
  83. package/dist/hooks/ui/index.d.ts +1 -0
  84. package/dist/hooks/ui/index.d.ts.map +1 -1
  85. package/dist/hooks/ui/use-deferred-error.d.ts +16 -0
  86. package/dist/hooks/ui/use-deferred-error.d.ts.map +1 -0
  87. package/dist/index.cjs +5 -3
  88. package/dist/index.cjs.map +1 -1
  89. package/dist/index.js +4 -2
  90. package/package.json +1 -1
  91. package/src/components/features/auth/auth-benefits-panel.tsx +1 -1
  92. package/src/components/features/auth/complete-account-form.tsx +15 -4
  93. package/src/components/features/auth/create-organization-form.tsx +14 -5
  94. package/src/components/features/auth/login-form.tsx +6 -1
  95. package/src/components/features/auth/openframe-sso-login-form.tsx +9 -2
  96. package/src/components/features/auth/openframe-sso-signup-form.tsx +18 -5
  97. package/src/components/features/auth/password-reset-form.tsx +9 -2
  98. package/src/hooks/ui/index.ts +1 -0
  99. package/src/hooks/ui/use-deferred-error.ts +38 -0
  100. package/src/stories/Input.stories.tsx +1 -1
  101. package/src/stories/auth/CreateOrganization.stories.tsx +2 -1
  102. package/dist/chunk-7OKNKZBW.cjs.map +0 -1
  103. package/dist/chunk-JWBRDNYH.cjs.map +0 -1
  104. package/dist/chunk-ZSZRJWY3.js.map +0 -1
  105. /package/dist/{chunk-4K5XJ5EJ.js.map → chunk-463X3AW2.js.map} +0 -0
  106. /package/dist/{chunk-XBCAY6NE.js.map → chunk-4HAVKWTJ.js.map} +0 -0
  107. /package/dist/{chunk-2L6ALD2Q.js.map → chunk-56XCRZ7I.js.map} +0 -0
  108. /package/dist/{chunk-BSJO5VFV.js.map → chunk-6VR7BJF6.js.map} +0 -0
  109. /package/dist/{chunk-G3A7QHCX.js.map → chunk-FHEIG7QO.js.map} +0 -0
  110. /package/dist/{chunk-Z5ERSGP2.js.map → chunk-I4XG5PJA.js.map} +0 -0
  111. /package/dist/{chunk-VVKWNVKE.js.map → chunk-LAL63W5J.js.map} +0 -0
  112. /package/dist/{chunk-A6KGHQRF.js.map → chunk-MQRTT3DO.js.map} +0 -0
  113. /package/dist/{chunk-4KWIQEZT.js.map → chunk-MTBFE3JF.js.map} +0 -0
  114. /package/dist/{chunk-CRRH7RJX.js.map → chunk-PD5MXNTJ.js.map} +0 -0
  115. /package/dist/{chunk-4H2ICJYB.js.map → chunk-RYPCNUXA.js.map} +0 -0
  116. /package/dist/{chunk-FXWURWDU.js.map → chunk-UFP45JLE.js.map} +0 -0
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type * as React from 'react'
4
4
  import { cn } from '../../../utils/cn'
5
+ import { useDeferredError } from '../../../hooks/ui/use-deferred-error'
5
6
  import { Button } from '../../ui/button'
6
7
  import { Input } from '../../ui/input'
7
8
  import type { AuthSsoProvider } from './sso-providers'
@@ -61,6 +62,9 @@ export function LoginForm({
61
62
  const isSsoMode = !!ssoProviders && ssoProviders.length > 0
62
63
  const fieldDisabled = disabled || loading || isSsoMode
63
64
 
65
+ // Validation messages are deferred while the user is typing (shown on blur or after a pause).
66
+ const emailErr = useDeferredError(errors?.email, email)
67
+
64
68
  const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
65
69
  if (event.key === 'Enter' && !fieldDisabled) {
66
70
  onSubmit()
@@ -86,8 +90,9 @@ export function LoginForm({
86
90
  label="Email"
87
91
  placeholder={emailPlaceholder}
88
92
  value={email}
89
- error={errors?.email}
93
+ error={emailErr.error}
90
94
  disabled={fieldDisabled}
95
+ onBlur={emailErr.onBlur}
91
96
  onChange={(event) => onEmailChange(event.target.value)}
92
97
  onKeyDown={handleKeyDown}
93
98
  />
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type * as React from 'react'
4
4
  import { cn } from '../../../utils/cn'
5
+ import { useDeferredError } from '../../../hooks/ui/use-deferred-error'
5
6
  import { Button } from '../../ui/button'
6
7
  import { Input } from '../../ui/input'
7
8
  import { PasswordInput } from '../../ui/password-input'
@@ -60,6 +61,10 @@ export function OpenFrameSsoLoginForm({
60
61
  }: OpenFrameSsoLoginFormProps) {
61
62
  const fieldsDisabled = disabled || loading
62
63
 
64
+ // Validation messages are deferred while the user is typing (shown on blur or after a pause).
65
+ const emailErr = useDeferredError(errors?.email, email)
66
+ const passwordErr = useDeferredError(errors?.password, password)
67
+
63
68
  const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
64
69
  if (event.key === 'Enter' && !fieldsDisabled && !submitDisabled) {
65
70
  onSubmit()
@@ -84,8 +89,9 @@ export function OpenFrameSsoLoginForm({
84
89
  label={emailLabel}
85
90
  placeholder={emailPlaceholder}
86
91
  value={email}
87
- error={errors?.email}
92
+ error={emailErr.error}
88
93
  disabled={fieldsDisabled}
94
+ onBlur={emailErr.onBlur}
89
95
  onChange={(event) => onEmailChange(event.target.value)}
90
96
  onKeyDown={handleKeyDown}
91
97
  />
@@ -94,8 +100,9 @@ export function OpenFrameSsoLoginForm({
94
100
  label={passwordLabel}
95
101
  placeholder={passwordPlaceholder}
96
102
  value={password}
97
- error={errors?.password}
103
+ error={passwordErr.error}
98
104
  disabled={fieldsDisabled}
105
+ onBlur={passwordErr.onBlur}
99
106
  onChange={(event) => onPasswordChange(event.target.value)}
100
107
  onKeyDown={handleKeyDown}
101
108
  />
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type * as React from 'react'
4
4
  import { cn } from '../../../utils/cn'
5
+ import { useDeferredError } from '../../../hooks/ui/use-deferred-error'
5
6
  import { Button } from '../../ui/button'
6
7
  import { Input } from '../../ui/input'
7
8
  import { PasswordInput } from '../../ui/password-input'
@@ -72,6 +73,13 @@ export function OpenFrameSsoSignUpForm({
72
73
  }: OpenFrameSsoSignUpFormProps) {
73
74
  const fieldsDisabled = disabled || loading
74
75
 
76
+ // Validation messages are deferred while the user is typing (shown on blur or after a pause).
77
+ const emailErr = useDeferredError(errors?.email, email)
78
+ const firstNameErr = useDeferredError(errors?.firstName, firstName)
79
+ const lastNameErr = useDeferredError(errors?.lastName, lastName)
80
+ const passwordErr = useDeferredError(errors?.password, password)
81
+ const confirmErr = useDeferredError(errors?.confirmPassword, confirmPassword)
82
+
75
83
  const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
76
84
  if (event.key === 'Enter' && !fieldsDisabled && !submitDisabled) {
77
85
  onSubmit()
@@ -96,8 +104,9 @@ export function OpenFrameSsoSignUpForm({
96
104
  label={emailLabel}
97
105
  placeholder="username@mail.com"
98
106
  value={email}
99
- error={errors?.email}
107
+ error={emailErr.error}
100
108
  disabled={fieldsDisabled || emailReadOnly}
109
+ onBlur={emailErr.onBlur}
101
110
  onChange={(event) => onEmailChange(event.target.value)}
102
111
  onKeyDown={handleKeyDown}
103
112
  />
@@ -107,8 +116,9 @@ export function OpenFrameSsoSignUpForm({
107
116
  label="First Name"
108
117
  placeholder="Enter First Name"
109
118
  value={firstName}
110
- error={errors?.firstName}
119
+ error={firstNameErr.error}
111
120
  disabled={fieldsDisabled}
121
+ onBlur={firstNameErr.onBlur}
112
122
  onChange={(event) => onFirstNameChange(event.target.value)}
113
123
  onKeyDown={handleKeyDown}
114
124
  />
@@ -116,8 +126,9 @@ export function OpenFrameSsoSignUpForm({
116
126
  label="Last Name"
117
127
  placeholder="Enter Last Name"
118
128
  value={lastName}
119
- error={errors?.lastName}
129
+ error={lastNameErr.error}
120
130
  disabled={fieldsDisabled}
131
+ onBlur={lastNameErr.onBlur}
121
132
  onChange={(event) => onLastNameChange(event.target.value)}
122
133
  onKeyDown={handleKeyDown}
123
134
  />
@@ -125,8 +136,9 @@ export function OpenFrameSsoSignUpForm({
125
136
  label="Password"
126
137
  placeholder="Enter Password"
127
138
  value={password}
128
- error={errors?.password}
139
+ error={passwordErr.error}
129
140
  disabled={fieldsDisabled}
141
+ onBlur={passwordErr.onBlur}
130
142
  onChange={(event) => onPasswordChange(event.target.value)}
131
143
  onKeyDown={handleKeyDown}
132
144
  />
@@ -134,8 +146,9 @@ export function OpenFrameSsoSignUpForm({
134
146
  label="Confirm Password"
135
147
  placeholder="Confirm Password"
136
148
  value={confirmPassword}
137
- error={errors?.confirmPassword}
149
+ error={confirmErr.error}
138
150
  disabled={fieldsDisabled}
151
+ onBlur={confirmErr.onBlur}
139
152
  onChange={(event) => onConfirmPasswordChange(event.target.value)}
140
153
  onKeyDown={handleKeyDown}
141
154
  />
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type * as React from 'react'
4
4
  import { cn } from '../../../utils/cn'
5
+ import { useDeferredError } from '../../../hooks/ui/use-deferred-error'
5
6
  import { Button } from '../../ui/button'
6
7
  import { Input } from '../../ui/input'
7
8
  import { BackToLoginLink } from './back-to-login-link'
@@ -66,6 +67,10 @@ export function PasswordResetForm({
66
67
  }: PasswordResetFormProps) {
67
68
  const fieldsDisabled = disabled || loading
68
69
 
70
+ // Validation messages are deferred while the user is typing (shown on blur or after a pause).
71
+ const passwordErr = useDeferredError(errors?.password, password)
72
+ const confirmErr = useDeferredError(errors?.confirmPassword, confirmPassword)
73
+
69
74
  const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
70
75
  if (event.key === 'Enter' && !fieldsDisabled && !submitDisabled) {
71
76
  onSubmit()
@@ -91,8 +96,9 @@ export function PasswordResetForm({
91
96
  label={newPasswordLabel}
92
97
  placeholder={newPasswordPlaceholder}
93
98
  value={password}
94
- error={errors?.password}
99
+ error={passwordErr.error}
95
100
  disabled={fieldsDisabled}
101
+ onBlur={passwordErr.onBlur}
96
102
  onChange={(event) => onPasswordChange(event.target.value)}
97
103
  onKeyDown={handleKeyDown}
98
104
  />
@@ -103,8 +109,9 @@ export function PasswordResetForm({
103
109
  label={confirmPasswordLabel}
104
110
  placeholder={confirmPasswordPlaceholder}
105
111
  value={confirmPassword}
106
- error={errors?.confirmPassword}
112
+ error={confirmErr.error}
107
113
  disabled={fieldsDisabled}
114
+ onBlur={confirmErr.onBlur}
108
115
  onChange={(event) => onConfirmPasswordChange(event.target.value)}
109
116
  onKeyDown={handleKeyDown}
110
117
  />
@@ -1,6 +1,7 @@
1
1
  // UI Hooks exports
2
2
  export * from './use-auto-limit-tags'
3
3
  export * from './use-debounce'
4
+ export * from './use-deferred-error'
4
5
  export * from './use-header-height'
5
6
  export * from './use-horizontal-scrollbar'
6
7
  export * from './use-image-edge-color'
@@ -0,0 +1,38 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+
5
+ export interface UseDeferredErrorResult {
6
+ /** The message to render (undefined while the reveal is deferred or the field is valid). */
7
+ error: string | undefined
8
+ /** Attach to the field's onBlur — reveals validation immediately and keeps it live from then on. */
9
+ onBlur: () => void
10
+ }
11
+
12
+ /**
13
+ * Defers showing a field validation message while the user is still typing.
14
+ *
15
+ * The message is revealed when the field loses focus (touched) or when the
16
+ * value hasn't changed for `delay` ms; every keystroke restarts the timer.
17
+ * Once touched, validation stays live. A message that clears (the value became
18
+ * valid) disappears immediately.
19
+ */
20
+ export function useDeferredError(error: string | undefined, value: string, delay = 1500): UseDeferredErrorResult {
21
+ const [touched, setTouched] = React.useState(false)
22
+ const [paused, setPaused] = React.useState(false)
23
+
24
+ // Typing hides the message and restarts the pause timer.
25
+ React.useEffect(() => {
26
+ if (touched) return
27
+ setPaused(false)
28
+ const timer = setTimeout(() => setPaused(true), delay)
29
+ return () => clearTimeout(timer)
30
+ }, [value, delay, touched])
31
+
32
+ const onBlur = React.useCallback(() => setTouched(true), [])
33
+
34
+ return {
35
+ error: error && (touched || paused) ? error : undefined,
36
+ onBlur,
37
+ }
38
+ }
@@ -244,7 +244,7 @@ export const ErrorState: Story = {
244
244
  />
245
245
  <Input
246
246
  label="Organization Name"
247
- defaultValue="ϕ"
247
+ defaultValue="A"
248
248
  error="Organization Name must be 2-100 characters"
249
249
  />
250
250
  </div>
@@ -99,12 +99,13 @@ export const Filled: Story = {
99
99
 
100
100
  /**
101
101
  * Error state: long messages under the fields wrap up to two lines.
102
+ * Validation is deferred — messages appear after a 1.5s typing pause or on blur.
102
103
  */
103
104
  export const ErrorState: Story = {
104
105
  render: () => (
105
106
  <CreateOrganizationPage
106
107
  email="ada@example.com"
107
- organizationName="ϕ"
108
+ organizationName="A"
108
109
  domainSuffix=".openframe.ai"
109
110
  termsUrl="#terms"
110
111
  privacyPolicyUrl="#privacy"