@tatchi-xyz/sdk 0.32.1 → 0.32.3

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 (57) hide show
  1. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-D2eRb2-S.css → PasskeyAuthMenu-mMygL3xX.css} +137 -47
  2. package/dist/cjs/react/components/PasskeyAuthMenu/PasskeyAuthMenu-mMygL3xX.css.map +1 -0
  3. package/dist/cjs/react/components/PasskeyAuthMenu/client.js +2 -3
  4. package/dist/cjs/react/components/PasskeyAuthMenu/client.js.map +1 -1
  5. package/dist/cjs/react/components/PasskeyAuthMenu/controller/mode.js +7 -2
  6. package/dist/cjs/react/components/PasskeyAuthMenu/controller/mode.js.map +1 -1
  7. package/dist/cjs/react/components/PasskeyAuthMenu/controller/usePasskeyAuthMenuController.js +4 -1
  8. package/dist/cjs/react/components/PasskeyAuthMenu/controller/usePasskeyAuthMenuController.js.map +1 -1
  9. package/dist/cjs/react/components/PasskeyAuthMenu/hydrationContext.js +20 -0
  10. package/dist/cjs/react/components/PasskeyAuthMenu/hydrationContext.js.map +1 -0
  11. package/dist/cjs/react/components/PasskeyAuthMenu/passkeyAuthMenuCompat.js +1 -1
  12. package/dist/cjs/react/components/PasskeyAuthMenu/shell.js +64 -30
  13. package/dist/cjs/react/components/PasskeyAuthMenu/shell.js.map +1 -1
  14. package/dist/cjs/react/components/PasskeyAuthMenu/skeleton.js +155 -101
  15. package/dist/cjs/react/components/PasskeyAuthMenu/skeleton.js.map +1 -1
  16. package/dist/cjs/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js +5 -1
  17. package/dist/cjs/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js.map +1 -1
  18. package/dist/cjs/react/index.js +2 -2
  19. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-qTHAv58Z.css → PasskeyAuthMenu-BihXvuII.css} +137 -47
  20. package/dist/esm/react/components/PasskeyAuthMenu/PasskeyAuthMenu-BihXvuII.css.map +1 -0
  21. package/dist/esm/react/components/PasskeyAuthMenu/client.js +2 -3
  22. package/dist/esm/react/components/PasskeyAuthMenu/client.js.map +1 -1
  23. package/dist/esm/react/components/PasskeyAuthMenu/controller/mode.js +7 -3
  24. package/dist/esm/react/components/PasskeyAuthMenu/controller/mode.js.map +1 -1
  25. package/dist/esm/react/components/PasskeyAuthMenu/controller/usePasskeyAuthMenuController.js +4 -1
  26. package/dist/esm/react/components/PasskeyAuthMenu/controller/usePasskeyAuthMenuController.js.map +1 -1
  27. package/dist/esm/react/components/PasskeyAuthMenu/hydrationContext.js +17 -0
  28. package/dist/esm/react/components/PasskeyAuthMenu/hydrationContext.js.map +1 -0
  29. package/dist/esm/react/components/PasskeyAuthMenu/passkeyAuthMenuCompat.js +1 -1
  30. package/dist/esm/react/components/PasskeyAuthMenu/shell.js +64 -30
  31. package/dist/esm/react/components/PasskeyAuthMenu/shell.js.map +1 -1
  32. package/dist/esm/react/components/PasskeyAuthMenu/skeleton.js +155 -101
  33. package/dist/esm/react/components/PasskeyAuthMenu/skeleton.js.map +1 -1
  34. package/dist/esm/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js +5 -1
  35. package/dist/esm/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js.map +1 -1
  36. package/dist/esm/react/index.js +2 -2
  37. package/dist/esm/react/styles/styles.css +136 -46
  38. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  39. package/dist/types/src/react/components/PasskeyAuthMenu/client.d.ts +0 -1
  40. package/dist/types/src/react/components/PasskeyAuthMenu/client.d.ts.map +1 -1
  41. package/dist/types/src/react/components/PasskeyAuthMenu/controller/mode.d.ts +6 -1
  42. package/dist/types/src/react/components/PasskeyAuthMenu/controller/mode.d.ts.map +1 -1
  43. package/dist/types/src/react/components/PasskeyAuthMenu/controller/usePasskeyAuthMenuController.d.ts.map +1 -1
  44. package/dist/types/src/react/components/PasskeyAuthMenu/hydrationContext.d.ts +10 -0
  45. package/dist/types/src/react/components/PasskeyAuthMenu/hydrationContext.d.ts.map +1 -0
  46. package/dist/types/src/react/components/PasskeyAuthMenu/shell.d.ts +2 -1
  47. package/dist/types/src/react/components/PasskeyAuthMenu/shell.d.ts.map +1 -1
  48. package/dist/types/src/react/components/PasskeyAuthMenu/skeleton.d.ts +5 -1
  49. package/dist/types/src/react/components/PasskeyAuthMenu/skeleton.d.ts.map +1 -1
  50. package/dist/types/src/react/components/PasskeyAuthMenu/ui/ContentSwitcher.d.ts.map +1 -1
  51. package/dist/workers/offline-export-sw.js +156 -1
  52. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  53. package/dist/workers/web3authn-signer.worker.js +1360 -2
  54. package/dist/workers/web3authn-vrf.worker.js +2857 -2
  55. package/package.json +4 -2
  56. package/dist/cjs/react/components/PasskeyAuthMenu/PasskeyAuthMenu-D2eRb2-S.css.map +0 -1
  57. package/dist/esm/react/components/PasskeyAuthMenu/PasskeyAuthMenu-qTHAv58Z.css.map +0 -1
@@ -37,9 +37,13 @@ function getModeTitle(mode, headings) {
37
37
  * - No IndexedDB/wallet-prefill logic yet (intentionally).
38
38
  * - Pure state transitions to keep the baseline bundle small and predictable.
39
39
  */
40
- function useAuthMenuMode({ defaultMode, accountExists, currentValue, setCurrentValue, headings }) {
40
+ function useAuthMenuMode({ defaultMode, accountExists, currentValue, setCurrentValue, headings, forceInitialRegister = false }) {
41
41
  const preferredDefaultMode = resolveDefaultMode(accountExists, defaultMode);
42
- const [mode, setMode] = react.default.useState(preferredDefaultMode);
42
+ const [mode, setMode] = react.default.useState(() => {
43
+ if (typeof defaultMode === "number") return defaultMode;
44
+ if (forceInitialRegister) return require_authMenuTypes.AuthMenuMode.Register;
45
+ return preferredDefaultMode;
46
+ });
43
47
  const title = react.default.useMemo(() => getModeTitle(mode, headings), [mode, headings]);
44
48
  const onSegmentChange = (nextMode) => {
45
49
  setMode(nextMode);
@@ -63,5 +67,6 @@ function useAuthMenuMode({ defaultMode, accountExists, currentValue, setCurrentV
63
67
  }
64
68
 
65
69
  //#endregion
70
+ exports.getModeTitle = getModeTitle;
66
71
  exports.useAuthMenuMode = useAuthMenuMode;
67
72
  //# sourceMappingURL=mode.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mode.js","names":["AuthMenuMode","defaults: Record<AuthMenuMode, AuthMenuTitle>","React"],"sources":["../../../../../../src/react/components/PasskeyAuthMenu/controller/mode.ts"],"sourcesContent":["import React from 'react';\nimport type { AuthMenuHeadings } from '../types';\nimport { AuthMenuMode } from '../types';\n\nexport interface AuthMenuTitle {\n title: string;\n subtitle: string;\n}\n\nexport function resolveDefaultMode(\n accountExists: boolean,\n requested?: AuthMenuMode | null,\n): AuthMenuMode {\n if (typeof requested === 'number') return requested;\n return accountExists ? AuthMenuMode.Login : AuthMenuMode.Register;\n}\n\nexport function getModeTitle(mode: AuthMenuMode, headings?: AuthMenuHeadings | null): AuthMenuTitle {\n const defaults: Record<AuthMenuMode, AuthMenuTitle> = {\n [AuthMenuMode.Login]: { title: 'Login', subtitle: 'Login with Passkey' },\n [AuthMenuMode.Register]: { title: 'Register Account', subtitle: 'Create a wallet with Passkey' },\n [AuthMenuMode.Sync]: { title: 'Sync Account', subtitle: 'Sync a wallet to this device with Passkey' },\n } as const;\n\n if (headings) {\n if (mode === AuthMenuMode.Login && headings.login) return headings.login;\n if (mode === AuthMenuMode.Register && headings.registration) return headings.registration;\n if (mode === AuthMenuMode.Sync && headings.syncAccount) return headings.syncAccount;\n }\n\n return defaults[mode] ?? defaults[AuthMenuMode.Login];\n}\n\nexport interface UseAuthMenuModeArgs {\n defaultMode?: AuthMenuMode;\n accountExists: boolean;\n currentValue: string;\n setCurrentValue: (v: string) => void;\n headings?: AuthMenuHeadings | null;\n}\n\nexport interface UseAuthMenuModeResult {\n mode: AuthMenuMode;\n setMode: React.Dispatch<React.SetStateAction<AuthMenuMode>>;\n title: AuthMenuTitle;\n onSegmentChange: (next: AuthMenuMode) => void;\n onInputChange: (val: string) => void;\n resetToDefault: () => void;\n}\n\n/**\n * `useAuthMenuMode`\n *\n * Minimal mode/title controller for PasskeyAuthMenu.\n * - No IndexedDB/wallet-prefill logic yet (intentionally).\n * - Pure state transitions to keep the baseline bundle small and predictable.\n */\nexport function useAuthMenuMode({\n defaultMode,\n accountExists,\n currentValue,\n setCurrentValue,\n headings,\n}: UseAuthMenuModeArgs): UseAuthMenuModeResult {\n const preferredDefaultMode = resolveDefaultMode(accountExists, defaultMode);\n const [mode, setMode] = React.useState<AuthMenuMode>(preferredDefaultMode);\n const title = React.useMemo(() => getModeTitle(mode, headings), [mode, headings]);\n\n const onSegmentChange = (nextMode: AuthMenuMode) => {\n setMode(nextMode);\n };\n\n const onInputChange = (val: string) => {\n setCurrentValue(val);\n };\n\n const resetToDefault = () => {\n const nextMode = resolveDefaultMode(accountExists, defaultMode);\n setMode(nextMode);\n setCurrentValue('');\n };\n\n return { mode, setMode, title, onSegmentChange, onInputChange, resetToDefault };\n}\n\nexport default useAuthMenuMode;\n"],"mappings":";;;;;;AASA,SAAgB,mBACd,eACA,WACc;AACd,KAAI,OAAO,cAAc,SAAU,QAAO;AAC1C,QAAO,gBAAgBA,mCAAa,QAAQA,mCAAa;;AAG3D,SAAgB,aAAa,MAAoB,UAAmD;CAClG,MAAMC,WAAgD;GACnDD,mCAAa,QAAQ;GAAE,OAAO;GAAS,UAAU;;GACjDA,mCAAa,WAAW;GAAE,OAAO;GAAoB,UAAU;;GAC/DA,mCAAa,OAAO;GAAE,OAAO;GAAgB,UAAU;;;AAG1D,KAAI,UAAU;AACZ,MAAI,SAASA,mCAAa,SAAS,SAAS,MAAO,QAAO,SAAS;AACnE,MAAI,SAASA,mCAAa,YAAY,SAAS,aAAc,QAAO,SAAS;AAC7E,MAAI,SAASA,mCAAa,QAAQ,SAAS,YAAa,QAAO,SAAS;;AAG1E,QAAO,SAAS,SAAS,SAASA,mCAAa;;;;;;;;;AA2BjD,SAAgB,gBAAgB,EAC9B,aACA,eACA,cACA,iBACA,YAC6C;CAC7C,MAAM,uBAAuB,mBAAmB,eAAe;CAC/D,MAAM,CAAC,MAAM,WAAWE,cAAM,SAAuB;CACrD,MAAM,QAAQA,cAAM,cAAc,aAAa,MAAM,WAAW,CAAC,MAAM;CAEvE,MAAM,mBAAmB,aAA2B;AAClD,UAAQ;;CAGV,MAAM,iBAAiB,QAAgB;AACrC,kBAAgB;;CAGlB,MAAM,uBAAuB;EAC3B,MAAM,WAAW,mBAAmB,eAAe;AACnD,UAAQ;AACR,kBAAgB;;AAGlB,QAAO;EAAE;EAAM;EAAS;EAAO;EAAiB;EAAe"}
1
+ {"version":3,"file":"mode.js","names":["AuthMenuMode","defaults: Record<AuthMenuMode, AuthMenuTitle>","React"],"sources":["../../../../../../src/react/components/PasskeyAuthMenu/controller/mode.ts"],"sourcesContent":["import React from 'react';\nimport type { AuthMenuHeadings } from '../types';\nimport { AuthMenuMode } from '../types';\n\nexport interface AuthMenuTitle {\n title: string;\n subtitle: string;\n}\n\nexport function resolveDefaultMode(\n accountExists: boolean,\n requested?: AuthMenuMode | null,\n): AuthMenuMode {\n if (typeof requested === 'number') return requested;\n return accountExists ? AuthMenuMode.Login : AuthMenuMode.Register;\n}\n\nexport function getModeTitle(mode: AuthMenuMode, headings?: AuthMenuHeadings | null): AuthMenuTitle {\n const defaults: Record<AuthMenuMode, AuthMenuTitle> = {\n [AuthMenuMode.Login]: { title: 'Login', subtitle: 'Login with Passkey' },\n [AuthMenuMode.Register]: { title: 'Register Account', subtitle: 'Create a wallet with Passkey' },\n [AuthMenuMode.Sync]: { title: 'Sync Account', subtitle: 'Sync a wallet to this device with Passkey' },\n } as const;\n\n if (headings) {\n if (mode === AuthMenuMode.Login && headings.login) return headings.login;\n if (mode === AuthMenuMode.Register && headings.registration) return headings.registration;\n if (mode === AuthMenuMode.Sync && headings.syncAccount) return headings.syncAccount;\n }\n\n return defaults[mode] ?? defaults[AuthMenuMode.Login];\n}\n\nexport interface UseAuthMenuModeArgs {\n defaultMode?: AuthMenuMode;\n accountExists: boolean;\n currentValue: string;\n setCurrentValue: (v: string) => void;\n headings?: AuthMenuHeadings | null;\n /**\n * When true, forces the initial client render to start in Register mode, even if\n * `accountExists` suggests Login. This is used to align hydration with the shell skeleton.\n */\n forceInitialRegister?: boolean;\n}\n\nexport interface UseAuthMenuModeResult {\n mode: AuthMenuMode;\n setMode: React.Dispatch<React.SetStateAction<AuthMenuMode>>;\n title: AuthMenuTitle;\n onSegmentChange: (next: AuthMenuMode) => void;\n onInputChange: (val: string) => void;\n resetToDefault: () => void;\n}\n\n/**\n * `useAuthMenuMode`\n *\n * Minimal mode/title controller for PasskeyAuthMenu.\n * - No IndexedDB/wallet-prefill logic yet (intentionally).\n * - Pure state transitions to keep the baseline bundle small and predictable.\n */\nexport function useAuthMenuMode({\n defaultMode,\n accountExists,\n currentValue,\n setCurrentValue,\n headings,\n forceInitialRegister = false,\n}: UseAuthMenuModeArgs): UseAuthMenuModeResult {\n const preferredDefaultMode = resolveDefaultMode(accountExists, defaultMode);\n const [mode, setMode] = React.useState<AuthMenuMode>(() => {\n if (typeof defaultMode === 'number') return defaultMode;\n if (forceInitialRegister) return AuthMenuMode.Register;\n return preferredDefaultMode;\n });\n const title = React.useMemo(() => getModeTitle(mode, headings), [mode, headings]);\n\n const onSegmentChange = (nextMode: AuthMenuMode) => {\n setMode(nextMode);\n };\n\n const onInputChange = (val: string) => {\n setCurrentValue(val);\n };\n\n const resetToDefault = () => {\n const nextMode = resolveDefaultMode(accountExists, defaultMode);\n setMode(nextMode);\n setCurrentValue('');\n };\n\n return { mode, setMode, title, onSegmentChange, onInputChange, resetToDefault };\n}\n\nexport default useAuthMenuMode;\n"],"mappings":";;;;;;AASA,SAAgB,mBACd,eACA,WACc;AACd,KAAI,OAAO,cAAc,SAAU,QAAO;AAC1C,QAAO,gBAAgBA,mCAAa,QAAQA,mCAAa;;AAG3D,SAAgB,aAAa,MAAoB,UAAmD;CAClG,MAAMC,WAAgD;GACnDD,mCAAa,QAAQ;GAAE,OAAO;GAAS,UAAU;;GACjDA,mCAAa,WAAW;GAAE,OAAO;GAAoB,UAAU;;GAC/DA,mCAAa,OAAO;GAAE,OAAO;GAAgB,UAAU;;;AAG1D,KAAI,UAAU;AACZ,MAAI,SAASA,mCAAa,SAAS,SAAS,MAAO,QAAO,SAAS;AACnE,MAAI,SAASA,mCAAa,YAAY,SAAS,aAAc,QAAO,SAAS;AAC7E,MAAI,SAASA,mCAAa,QAAQ,SAAS,YAAa,QAAO,SAAS;;AAG1E,QAAO,SAAS,SAAS,SAASA,mCAAa;;;;;;;;;AAgCjD,SAAgB,gBAAgB,EAC9B,aACA,eACA,cACA,iBACA,UACA,uBAAuB,SACsB;CAC7C,MAAM,uBAAuB,mBAAmB,eAAe;CAC/D,MAAM,CAAC,MAAM,WAAWE,cAAM,eAA6B;AACzD,MAAI,OAAO,gBAAgB,SAAU,QAAO;AAC5C,MAAI,qBAAsB,QAAOF,mCAAa;AAC9C,SAAO;;CAET,MAAM,QAAQE,cAAM,cAAc,aAAa,MAAM,WAAW,CAAC,MAAM;CAEvE,MAAM,mBAAmB,aAA2B;AAClD,UAAQ;;CAGV,MAAM,iBAAiB,QAAgB;AACrC,kBAAgB;;CAGlB,MAAM,uBAAuB;EAC3B,MAAM,WAAW,mBAAmB,eAAe;AACnD,UAAQ;AACR,kBAAgB;;AAGlB,QAAO;EAAE;EAAM;EAAS;EAAO;EAAiB;EAAe"}
@@ -1,6 +1,7 @@
1
1
  const require_rolldown_runtime = require('../../../_virtual/rolldown_runtime.js');
2
2
  const require_authMenuTypes = require('../authMenuTypes.js');
3
3
  const require_mode = require('./mode.js');
4
+ const require_hydrationContext = require('../hydrationContext.js');
4
5
  const require_proceedEligibility = require('./proceedEligibility.js');
5
6
  let react = require("react");
6
7
  react = require_rolldown_runtime.__toESM(react);
@@ -10,12 +11,14 @@ function usePasskeyAuthMenuController(props, runtime) {
10
11
  const secure = typeof window !== "undefined" ? window.isSecureContext : true;
11
12
  const currentValue = runtime.inputUsername;
12
13
  const setCurrentValue = runtime.setInputUsername;
14
+ const forceInitialRegister = require_hydrationContext.usePasskeyAuthMenuForceInitialRegister();
13
15
  const { mode, setMode, title, onSegmentChange: onSegmentChangeBase, onInputChange: onInputChangeBase, resetToDefault } = require_mode.useAuthMenuMode({
14
16
  defaultMode: props.defaultMode,
15
17
  accountExists: runtime.accountExists,
16
18
  currentValue,
17
19
  setCurrentValue,
18
- headings: props.headings
20
+ headings: props.headings,
21
+ forceInitialRegister
19
22
  });
20
23
  const latestValueRef = react.default.useRef(currentValue);
21
24
  react.default.useEffect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"usePasskeyAuthMenuController.js","names":["useAuthMenuMode","React","AuthMenuMode","getProceedEligibility","linkDevice: PasskeyAuthMenuLinkDeviceController"],"sources":["../../../../../../src/react/components/PasskeyAuthMenu/controller/usePasskeyAuthMenuController.ts"],"sourcesContent":["import React from 'react';\nimport type { DeviceLinkingSSEEvent } from '@/core/types/sdkSentEvents';\nimport type { PasskeyAuthMenuRuntime } from '../adapters/tatchi';\nimport { AuthMenuMode, type PasskeyAuthMenuProps } from '../types';\nimport { useAuthMenuMode } from './mode';\nimport { getProceedEligibility } from './proceedEligibility';\n\nexport interface PasskeyAuthMenuLinkDeviceController {\n isOpen: boolean;\n onClose: () => void;\n onEvent: (event: DeviceLinkingSSEEvent) => void;\n onError: (error: Error) => void;\n}\n\nexport interface PasskeyAuthMenuController {\n mode: AuthMenuMode;\n title: { title: string; subtitle: string };\n waiting: boolean;\n showScanDevice: boolean;\n showEmailRecovery: boolean;\n currentValue: string;\n postfixText?: string;\n isUsingExistingAccount?: boolean;\n secure: boolean;\n canShowContinue: boolean;\n canSubmit: boolean;\n onSegmentChange: (next: AuthMenuMode) => void;\n onInputChange: (val: string) => void;\n onProceed: () => void;\n onResetToStart: () => void;\n openScanDevice: () => void;\n openEmailRecovery: () => void;\n closeEmailRecovery: () => void;\n closeLinkDeviceView: (reason: 'user' | 'flow') => void;\n linkDevice: PasskeyAuthMenuLinkDeviceController;\n}\n\nexport function usePasskeyAuthMenuController(\n props: Pick<\n PasskeyAuthMenuProps,\n 'onLogin' | 'onRegister' | 'onSyncAccount' | 'defaultMode' | 'headings' | 'linkDeviceOptions'\n >,\n runtime: PasskeyAuthMenuRuntime,\n): PasskeyAuthMenuController {\n const secure = typeof window !== 'undefined' ? window.isSecureContext : true;\n const currentValue = runtime.inputUsername;\n const setCurrentValue = runtime.setInputUsername;\n\n const { mode, setMode, title, onSegmentChange: onSegmentChangeBase, onInputChange: onInputChangeBase, resetToDefault } = useAuthMenuMode({\n defaultMode: props.defaultMode,\n accountExists: runtime.accountExists,\n currentValue,\n setCurrentValue,\n headings: props.headings,\n });\n\n const latestValueRef = React.useRef<string>(currentValue);\n React.useEffect(() => {\n latestValueRef.current = currentValue;\n }, [currentValue]);\n\n // Recent-login prefill state (from lazy feature island).\n const prefilledFromRecentRef = React.useRef(false);\n const prefilledValueRef = React.useRef<string>('');\n const prevModeRef = React.useRef<AuthMenuMode | null>(null);\n const lastUserSelectedModeRef = React.useRef<AuthMenuMode | null>(null);\n\n const clearPrefillMarkers = React.useCallback(() => {\n prefilledFromRecentRef.current = false;\n prefilledValueRef.current = '';\n }, []);\n\n const onSegmentChange = React.useCallback(\n (next: AuthMenuMode) => {\n lastUserSelectedModeRef.current = next;\n if (mode === AuthMenuMode.Login && next !== AuthMenuMode.Login) {\n if (prefilledFromRecentRef.current && currentValue === prefilledValueRef.current) {\n setCurrentValue('');\n }\n clearPrefillMarkers();\n }\n onSegmentChangeBase(next);\n },\n [mode, currentValue, setCurrentValue, onSegmentChangeBase, clearPrefillMarkers],\n );\n\n const onInputChange = React.useCallback(\n (val: string) => {\n if (val !== prefilledValueRef.current) {\n prefilledFromRecentRef.current = false;\n }\n onInputChangeBase(val);\n },\n [onInputChangeBase],\n );\n\n const { canShowContinue, canSubmit } = getProceedEligibility({\n mode,\n currentValue,\n accountExists: runtime.accountExists,\n secure,\n });\n\n const [waiting, setWaiting] = React.useState(false);\n const [showScanDevice, setShowScanDevice] = React.useState(false);\n const [showEmailRecovery, setShowEmailRecovery] = React.useState(false);\n\n // If the user is attempting to register but we discover the account already exists,\n // automatically switch them to the Login tab.\n React.useEffect(() => {\n if (waiting) return;\n if (mode !== AuthMenuMode.Register) return;\n if (!runtime.accountExists) return;\n if (lastUserSelectedModeRef.current === AuthMenuMode.Register) return;\n setMode(AuthMenuMode.Login);\n }, [mode, runtime.accountExists, setMode, waiting]);\n\n // Lazy feature-island: entering Login can prefill the last used account username.\n React.useEffect(() => {\n const prevMode = prevModeRef.current;\n prevModeRef.current = mode;\n\n const enteringLogin = mode === AuthMenuMode.Login && prevMode !== AuthMenuMode.Login;\n if (!enteringLogin) return;\n if (latestValueRef.current.trim().length > 0) return;\n\n let cancelled = false;\n void import('../features/recentLoginPrefill')\n .then(async (m) => {\n const result = await m.getRecentLoginPrefill(runtime.tatchiPasskey);\n if (cancelled || !result?.username) return;\n if (prevModeRef.current !== AuthMenuMode.Login) return;\n if (latestValueRef.current.trim().length > 0) return;\n\n setCurrentValue(result.username);\n prefilledFromRecentRef.current = true;\n prefilledValueRef.current = result.username;\n })\n .catch(() => {});\n\n return () => {\n cancelled = true;\n };\n }, [mode, runtime.tatchiPasskey, setCurrentValue]);\n\n const fallbackOnEvent = React.useCallback((event: DeviceLinkingSSEEvent) => {\n console.log('ShowQRCode event:', event);\n }, []);\n\n const fallbackOnError = React.useCallback((error: Error) => {\n console.error('ShowQRCode error:', error);\n }, []);\n\n const handleLinkDeviceEvent = props.linkDeviceOptions?.onEvent ?? fallbackOnEvent;\n const handleLinkDeviceError = props.linkDeviceOptions?.onError ?? fallbackOnError;\n const handleLinkDeviceCancelled = props.linkDeviceOptions?.onCancelled;\n\n const stopLinkDeviceFlow = React.useCallback(() => {\n const stopper = runtime.stopDevice2LinkingFlow;\n if (!stopper) return;\n void stopper().catch(() => {});\n }, [runtime.stopDevice2LinkingFlow]);\n\n const closeLinkDeviceView = React.useCallback(\n (reason: 'user' | 'flow') => {\n stopLinkDeviceFlow();\n setShowScanDevice(false);\n if (reason === 'user') {\n handleLinkDeviceCancelled?.();\n }\n },\n [stopLinkDeviceFlow, handleLinkDeviceCancelled],\n );\n\n const onResetToStart = React.useCallback(() => {\n setWaiting(false);\n if (showScanDevice) {\n closeLinkDeviceView('user');\n } else {\n setShowScanDevice(false);\n }\n setShowEmailRecovery(false);\n lastUserSelectedModeRef.current = null;\n resetToDefault();\n setCurrentValue('');\n clearPrefillMarkers();\n }, [showScanDevice, closeLinkDeviceView, resetToDefault, setCurrentValue, clearPrefillMarkers]);\n\n const onProceed = React.useCallback(() => {\n if (!canSubmit) return;\n\n setWaiting(true);\n\n void (async () => {\n try {\n if (mode === AuthMenuMode.Sync) {\n await props.onSyncAccount?.();\n setWaiting(false);\n setMode(AuthMenuMode.Login);\n } else if (mode === AuthMenuMode.Login) {\n await props.onLogin?.();\n setWaiting(false);\n closeLinkDeviceView('flow');\n setMode(AuthMenuMode.Login);\n } else {\n await props.onRegister?.();\n setWaiting(false);\n setMode(AuthMenuMode.Login);\n }\n } catch {\n if (mode === AuthMenuMode.Login) {\n setWaiting(false);\n closeLinkDeviceView('flow');\n setMode(mode);\n return;\n }\n onResetToStart();\n }\n })();\n }, [\n canSubmit,\n mode,\n props.onSyncAccount,\n props.onLogin,\n props.onRegister,\n setMode,\n closeLinkDeviceView,\n onResetToStart,\n ]);\n\n const openScanDevice = React.useCallback(() => {\n setShowEmailRecovery(false);\n setShowScanDevice(true);\n }, []);\n\n const openEmailRecovery = React.useCallback(() => {\n stopLinkDeviceFlow();\n setShowScanDevice(false);\n setShowEmailRecovery(true);\n }, [stopLinkDeviceFlow]);\n\n const closeEmailRecovery = React.useCallback(() => {\n setShowEmailRecovery(false);\n }, []);\n\n const linkDevice: PasskeyAuthMenuLinkDeviceController = React.useMemo(\n () => ({\n isOpen: showScanDevice,\n onClose: () => closeLinkDeviceView('flow'),\n onEvent: handleLinkDeviceEvent,\n onError: handleLinkDeviceError,\n }),\n [showScanDevice, closeLinkDeviceView, handleLinkDeviceEvent, handleLinkDeviceError],\n );\n\n return {\n mode,\n title,\n waiting,\n showScanDevice,\n showEmailRecovery,\n currentValue,\n postfixText: runtime.displayPostfix,\n isUsingExistingAccount: runtime.isUsingExistingAccount,\n secure,\n canShowContinue,\n canSubmit,\n onSegmentChange,\n onInputChange,\n onProceed,\n onResetToStart,\n openScanDevice,\n openEmailRecovery,\n closeEmailRecovery,\n closeLinkDeviceView,\n linkDevice,\n };\n}\n\nexport default usePasskeyAuthMenuController;\n"],"mappings":";;;;;;;;AAqCA,SAAgB,6BACd,OAIA,SAC2B;CAC3B,MAAM,SAAS,OAAO,WAAW,cAAc,OAAO,kBAAkB;CACxE,MAAM,eAAe,QAAQ;CAC7B,MAAM,kBAAkB,QAAQ;CAEhC,MAAM,EAAE,MAAM,SAAS,OAAO,iBAAiB,qBAAqB,eAAe,mBAAmB,mBAAmBA,6BAAgB;EACvI,aAAa,MAAM;EACnB,eAAe,QAAQ;EACvB;EACA;EACA,UAAU,MAAM;;CAGlB,MAAM,iBAAiBC,cAAM,OAAe;AAC5C,eAAM,gBAAgB;AACpB,iBAAe,UAAU;IACxB,CAAC;CAGJ,MAAM,yBAAyBA,cAAM,OAAO;CAC5C,MAAM,oBAAoBA,cAAM,OAAe;CAC/C,MAAM,cAAcA,cAAM,OAA4B;CACtD,MAAM,0BAA0BA,cAAM,OAA4B;CAElE,MAAM,sBAAsBA,cAAM,kBAAkB;AAClD,yBAAuB,UAAU;AACjC,oBAAkB,UAAU;IAC3B;CAEH,MAAM,kBAAkBA,cAAM,aAC3B,SAAuB;AACtB,0BAAwB,UAAU;AAClC,MAAI,SAASC,mCAAa,SAAS,SAASA,mCAAa,OAAO;AAC9D,OAAI,uBAAuB,WAAW,iBAAiB,kBAAkB,QACvE,iBAAgB;AAElB;;AAEF,sBAAoB;IAEtB;EAAC;EAAM;EAAc;EAAiB;EAAqB;;CAG7D,MAAM,gBAAgBD,cAAM,aACzB,QAAgB;AACf,MAAI,QAAQ,kBAAkB,QAC5B,wBAAuB,UAAU;AAEnC,oBAAkB;IAEpB,CAAC;CAGH,MAAM,EAAE,iBAAiB,cAAcE,iDAAsB;EAC3D;EACA;EACA,eAAe,QAAQ;EACvB;;CAGF,MAAM,CAAC,SAAS,cAAcF,cAAM,SAAS;CAC7C,MAAM,CAAC,gBAAgB,qBAAqBA,cAAM,SAAS;CAC3D,MAAM,CAAC,mBAAmB,wBAAwBA,cAAM,SAAS;AAIjE,eAAM,gBAAgB;AACpB,MAAI,QAAS;AACb,MAAI,SAASC,mCAAa,SAAU;AACpC,MAAI,CAAC,QAAQ,cAAe;AAC5B,MAAI,wBAAwB,YAAYA,mCAAa,SAAU;AAC/D,UAAQA,mCAAa;IACpB;EAAC;EAAM,QAAQ;EAAe;EAAS;;AAG1C,eAAM,gBAAgB;EACpB,MAAM,WAAW,YAAY;AAC7B,cAAY,UAAU;EAEtB,MAAM,gBAAgB,SAASA,mCAAa,SAAS,aAAaA,mCAAa;AAC/E,MAAI,CAAC,cAAe;AACpB,MAAI,eAAe,QAAQ,OAAO,SAAS,EAAG;EAE9C,IAAI,YAAY;AAChB,uCAAK,sCACF,KAAK,OAAO,MAAM;GACjB,MAAM,SAAS,MAAM,EAAE,sBAAsB,QAAQ;AACrD,OAAI,aAAa,CAAC,QAAQ,SAAU;AACpC,OAAI,YAAY,YAAYA,mCAAa,MAAO;AAChD,OAAI,eAAe,QAAQ,OAAO,SAAS,EAAG;AAE9C,mBAAgB,OAAO;AACvB,0BAAuB,UAAU;AACjC,qBAAkB,UAAU,OAAO;KAEpC,YAAY;AAEf,eAAa;AACX,eAAY;;IAEb;EAAC;EAAM,QAAQ;EAAe;;CAEjC,MAAM,kBAAkBD,cAAM,aAAa,UAAiC;AAC1E,UAAQ,IAAI,qBAAqB;IAChC;CAEH,MAAM,kBAAkBA,cAAM,aAAa,UAAiB;AAC1D,UAAQ,MAAM,qBAAqB;IAClC;CAEH,MAAM,wBAAwB,MAAM,mBAAmB,WAAW;CAClE,MAAM,wBAAwB,MAAM,mBAAmB,WAAW;CAClE,MAAM,4BAA4B,MAAM,mBAAmB;CAE3D,MAAM,qBAAqBA,cAAM,kBAAkB;EACjD,MAAM,UAAU,QAAQ;AACxB,MAAI,CAAC,QAAS;AACd,EAAK,UAAU,YAAY;IAC1B,CAAC,QAAQ;CAEZ,MAAM,sBAAsBA,cAAM,aAC/B,WAA4B;AAC3B;AACA,oBAAkB;AAClB,MAAI,WAAW,OACb;IAGJ,CAAC,oBAAoB;CAGvB,MAAM,iBAAiBA,cAAM,kBAAkB;AAC7C,aAAW;AACX,MAAI,eACF,qBAAoB;MAEpB,mBAAkB;AAEpB,uBAAqB;AACrB,0BAAwB,UAAU;AAClC;AACA,kBAAgB;AAChB;IACC;EAAC;EAAgB;EAAqB;EAAgB;EAAiB;;CAE1E,MAAM,YAAYA,cAAM,kBAAkB;AACxC,MAAI,CAAC,UAAW;AAEhB,aAAW;AAEX,GAAM,YAAY;AAChB,OAAI;AACF,QAAI,SAASC,mCAAa,MAAM;AAC9B,WAAM,MAAM;AACZ,gBAAW;AACX,aAAQA,mCAAa;eACZ,SAASA,mCAAa,OAAO;AACtC,WAAM,MAAM;AACZ,gBAAW;AACX,yBAAoB;AACpB,aAAQA,mCAAa;WAChB;AACL,WAAM,MAAM;AACZ,gBAAW;AACX,aAAQA,mCAAa;;WAEjB;AACN,QAAI,SAASA,mCAAa,OAAO;AAC/B,gBAAW;AACX,yBAAoB;AACpB,aAAQ;AACR;;AAEF;;;IAGH;EACD;EACA;EACA,MAAM;EACN,MAAM;EACN,MAAM;EACN;EACA;EACA;;CAGF,MAAM,iBAAiBD,cAAM,kBAAkB;AAC7C,uBAAqB;AACrB,oBAAkB;IACjB;CAEH,MAAM,oBAAoBA,cAAM,kBAAkB;AAChD;AACA,oBAAkB;AAClB,uBAAqB;IACpB,CAAC;CAEJ,MAAM,qBAAqBA,cAAM,kBAAkB;AACjD,uBAAqB;IACpB;CAEH,MAAMG,aAAkDH,cAAM,eACrD;EACL,QAAQ;EACR,eAAe,oBAAoB;EACnC,SAAS;EACT,SAAS;KAEX;EAAC;EAAgB;EAAqB;EAAuB;;AAG/D,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA,aAAa,QAAQ;EACrB,wBAAwB,QAAQ;EAChC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA"}
1
+ {"version":3,"file":"usePasskeyAuthMenuController.js","names":["usePasskeyAuthMenuForceInitialRegister","useAuthMenuMode","React","AuthMenuMode","getProceedEligibility","linkDevice: PasskeyAuthMenuLinkDeviceController"],"sources":["../../../../../../src/react/components/PasskeyAuthMenu/controller/usePasskeyAuthMenuController.ts"],"sourcesContent":["import React from 'react';\nimport type { DeviceLinkingSSEEvent } from '@/core/types/sdkSentEvents';\nimport type { PasskeyAuthMenuRuntime } from '../adapters/tatchi';\nimport { AuthMenuMode, type PasskeyAuthMenuProps } from '../types';\nimport { usePasskeyAuthMenuForceInitialRegister } from '../hydrationContext';\nimport { useAuthMenuMode } from './mode';\nimport { getProceedEligibility } from './proceedEligibility';\n\nexport interface PasskeyAuthMenuLinkDeviceController {\n isOpen: boolean;\n onClose: () => void;\n onEvent: (event: DeviceLinkingSSEEvent) => void;\n onError: (error: Error) => void;\n}\n\nexport interface PasskeyAuthMenuController {\n mode: AuthMenuMode;\n title: { title: string; subtitle: string };\n waiting: boolean;\n showScanDevice: boolean;\n showEmailRecovery: boolean;\n currentValue: string;\n postfixText?: string;\n isUsingExistingAccount?: boolean;\n secure: boolean;\n canShowContinue: boolean;\n canSubmit: boolean;\n onSegmentChange: (next: AuthMenuMode) => void;\n onInputChange: (val: string) => void;\n onProceed: () => void;\n onResetToStart: () => void;\n openScanDevice: () => void;\n openEmailRecovery: () => void;\n closeEmailRecovery: () => void;\n closeLinkDeviceView: (reason: 'user' | 'flow') => void;\n linkDevice: PasskeyAuthMenuLinkDeviceController;\n}\n\nexport function usePasskeyAuthMenuController(\n props: Pick<\n PasskeyAuthMenuProps,\n 'onLogin' | 'onRegister' | 'onSyncAccount' | 'defaultMode' | 'headings' | 'linkDeviceOptions'\n >,\n runtime: PasskeyAuthMenuRuntime,\n): PasskeyAuthMenuController {\n const secure = typeof window !== 'undefined' ? window.isSecureContext : true;\n const currentValue = runtime.inputUsername;\n const setCurrentValue = runtime.setInputUsername;\n const forceInitialRegister = usePasskeyAuthMenuForceInitialRegister();\n\n const { mode, setMode, title, onSegmentChange: onSegmentChangeBase, onInputChange: onInputChangeBase, resetToDefault } = useAuthMenuMode({\n defaultMode: props.defaultMode,\n accountExists: runtime.accountExists,\n currentValue,\n setCurrentValue,\n headings: props.headings,\n forceInitialRegister,\n });\n\n const latestValueRef = React.useRef<string>(currentValue);\n React.useEffect(() => {\n latestValueRef.current = currentValue;\n }, [currentValue]);\n\n // Recent-login prefill state (from lazy feature island).\n const prefilledFromRecentRef = React.useRef(false);\n const prefilledValueRef = React.useRef<string>('');\n const prevModeRef = React.useRef<AuthMenuMode | null>(null);\n const lastUserSelectedModeRef = React.useRef<AuthMenuMode | null>(null);\n\n const clearPrefillMarkers = React.useCallback(() => {\n prefilledFromRecentRef.current = false;\n prefilledValueRef.current = '';\n }, []);\n\n const onSegmentChange = React.useCallback(\n (next: AuthMenuMode) => {\n lastUserSelectedModeRef.current = next;\n if (mode === AuthMenuMode.Login && next !== AuthMenuMode.Login) {\n if (prefilledFromRecentRef.current && currentValue === prefilledValueRef.current) {\n setCurrentValue('');\n }\n clearPrefillMarkers();\n }\n onSegmentChangeBase(next);\n },\n [mode, currentValue, setCurrentValue, onSegmentChangeBase, clearPrefillMarkers],\n );\n\n const onInputChange = React.useCallback(\n (val: string) => {\n if (val !== prefilledValueRef.current) {\n prefilledFromRecentRef.current = false;\n }\n onInputChangeBase(val);\n },\n [onInputChangeBase],\n );\n\n const { canShowContinue, canSubmit } = getProceedEligibility({\n mode,\n currentValue,\n accountExists: runtime.accountExists,\n secure,\n });\n\n const [waiting, setWaiting] = React.useState(false);\n const [showScanDevice, setShowScanDevice] = React.useState(false);\n const [showEmailRecovery, setShowEmailRecovery] = React.useState(false);\n\n // If the user is attempting to register but we discover the account already exists,\n // automatically switch them to the Login tab.\n React.useEffect(() => {\n if (waiting) return;\n if (mode !== AuthMenuMode.Register) return;\n if (!runtime.accountExists) return;\n if (lastUserSelectedModeRef.current === AuthMenuMode.Register) return;\n setMode(AuthMenuMode.Login);\n }, [mode, runtime.accountExists, setMode, waiting]);\n\n // Lazy feature-island: entering Login can prefill the last used account username.\n React.useEffect(() => {\n const prevMode = prevModeRef.current;\n prevModeRef.current = mode;\n\n const enteringLogin = mode === AuthMenuMode.Login && prevMode !== AuthMenuMode.Login;\n if (!enteringLogin) return;\n if (latestValueRef.current.trim().length > 0) return;\n\n let cancelled = false;\n void import('../features/recentLoginPrefill')\n .then(async (m) => {\n const result = await m.getRecentLoginPrefill(runtime.tatchiPasskey);\n if (cancelled || !result?.username) return;\n if (prevModeRef.current !== AuthMenuMode.Login) return;\n if (latestValueRef.current.trim().length > 0) return;\n\n setCurrentValue(result.username);\n prefilledFromRecentRef.current = true;\n prefilledValueRef.current = result.username;\n })\n .catch(() => {});\n\n return () => {\n cancelled = true;\n };\n }, [mode, runtime.tatchiPasskey, setCurrentValue]);\n\n const fallbackOnEvent = React.useCallback((event: DeviceLinkingSSEEvent) => {\n console.log('ShowQRCode event:', event);\n }, []);\n\n const fallbackOnError = React.useCallback((error: Error) => {\n console.error('ShowQRCode error:', error);\n }, []);\n\n const handleLinkDeviceEvent = props.linkDeviceOptions?.onEvent ?? fallbackOnEvent;\n const handleLinkDeviceError = props.linkDeviceOptions?.onError ?? fallbackOnError;\n const handleLinkDeviceCancelled = props.linkDeviceOptions?.onCancelled;\n\n const stopLinkDeviceFlow = React.useCallback(() => {\n const stopper = runtime.stopDevice2LinkingFlow;\n if (!stopper) return;\n void stopper().catch(() => {});\n }, [runtime.stopDevice2LinkingFlow]);\n\n const closeLinkDeviceView = React.useCallback(\n (reason: 'user' | 'flow') => {\n stopLinkDeviceFlow();\n setShowScanDevice(false);\n if (reason === 'user') {\n handleLinkDeviceCancelled?.();\n }\n },\n [stopLinkDeviceFlow, handleLinkDeviceCancelled],\n );\n\n const onResetToStart = React.useCallback(() => {\n setWaiting(false);\n if (showScanDevice) {\n closeLinkDeviceView('user');\n } else {\n setShowScanDevice(false);\n }\n setShowEmailRecovery(false);\n lastUserSelectedModeRef.current = null;\n resetToDefault();\n setCurrentValue('');\n clearPrefillMarkers();\n }, [showScanDevice, closeLinkDeviceView, resetToDefault, setCurrentValue, clearPrefillMarkers]);\n\n const onProceed = React.useCallback(() => {\n if (!canSubmit) return;\n\n setWaiting(true);\n\n void (async () => {\n try {\n if (mode === AuthMenuMode.Sync) {\n await props.onSyncAccount?.();\n setWaiting(false);\n setMode(AuthMenuMode.Login);\n } else if (mode === AuthMenuMode.Login) {\n await props.onLogin?.();\n setWaiting(false);\n closeLinkDeviceView('flow');\n setMode(AuthMenuMode.Login);\n } else {\n await props.onRegister?.();\n setWaiting(false);\n setMode(AuthMenuMode.Login);\n }\n } catch {\n if (mode === AuthMenuMode.Login) {\n setWaiting(false);\n closeLinkDeviceView('flow');\n setMode(mode);\n return;\n }\n onResetToStart();\n }\n })();\n }, [\n canSubmit,\n mode,\n props.onSyncAccount,\n props.onLogin,\n props.onRegister,\n setMode,\n closeLinkDeviceView,\n onResetToStart,\n ]);\n\n const openScanDevice = React.useCallback(() => {\n setShowEmailRecovery(false);\n setShowScanDevice(true);\n }, []);\n\n const openEmailRecovery = React.useCallback(() => {\n stopLinkDeviceFlow();\n setShowScanDevice(false);\n setShowEmailRecovery(true);\n }, [stopLinkDeviceFlow]);\n\n const closeEmailRecovery = React.useCallback(() => {\n setShowEmailRecovery(false);\n }, []);\n\n const linkDevice: PasskeyAuthMenuLinkDeviceController = React.useMemo(\n () => ({\n isOpen: showScanDevice,\n onClose: () => closeLinkDeviceView('flow'),\n onEvent: handleLinkDeviceEvent,\n onError: handleLinkDeviceError,\n }),\n [showScanDevice, closeLinkDeviceView, handleLinkDeviceEvent, handleLinkDeviceError],\n );\n\n return {\n mode,\n title,\n waiting,\n showScanDevice,\n showEmailRecovery,\n currentValue,\n postfixText: runtime.displayPostfix,\n isUsingExistingAccount: runtime.isUsingExistingAccount,\n secure,\n canShowContinue,\n canSubmit,\n onSegmentChange,\n onInputChange,\n onProceed,\n onResetToStart,\n openScanDevice,\n openEmailRecovery,\n closeEmailRecovery,\n closeLinkDeviceView,\n linkDevice,\n };\n}\n\nexport default usePasskeyAuthMenuController;\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.js');
2
+ let react = require("react");
3
+ react = require_rolldown_runtime.__toESM(react);
4
+
5
+ //#region src/react/components/PasskeyAuthMenu/hydrationContext.ts
6
+ /**
7
+ * Internal context used by the SSR-safe shell to hint the client controller about
8
+ * initial hydration strategy (e.g., align first render with the skeleton).
9
+ *
10
+ * Default: false (normal behavior).
11
+ */
12
+ const PasskeyAuthMenuHydrationContext = react.default.createContext(false);
13
+ function usePasskeyAuthMenuForceInitialRegister() {
14
+ return react.default.useContext(PasskeyAuthMenuHydrationContext);
15
+ }
16
+
17
+ //#endregion
18
+ exports.PasskeyAuthMenuHydrationContext = PasskeyAuthMenuHydrationContext;
19
+ exports.usePasskeyAuthMenuForceInitialRegister = usePasskeyAuthMenuForceInitialRegister;
20
+ //# sourceMappingURL=hydrationContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydrationContext.js","names":["React"],"sources":["../../../../../src/react/components/PasskeyAuthMenu/hydrationContext.ts"],"sourcesContent":["import React from 'react';\n\n/**\n * Internal context used by the SSR-safe shell to hint the client controller about\n * initial hydration strategy (e.g., align first render with the skeleton).\n *\n * Default: false (normal behavior).\n */\nexport const PasskeyAuthMenuHydrationContext = React.createContext<boolean>(false);\n\nexport function usePasskeyAuthMenuForceInitialRegister(): boolean {\n return React.useContext(PasskeyAuthMenuHydrationContext);\n}\n\n"],"mappings":";;;;;;;;;;;AAQA,MAAa,kCAAkCA,cAAM,cAAuB;AAE5E,SAAgB,yCAAkD;AAChE,QAAOA,cAAM,WAAW"}
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
+ const require_authMenuTypes = require('./authMenuTypes.js');
2
3
  const require_skeleton = require('./skeleton.js');
3
4
  const require_shell = require('./shell.js');
4
- const require_authMenuTypes = require('./authMenuTypes.js');
5
5
 
6
6
  //#region src/react/components/PasskeyAuthMenu/passkeyAuthMenuCompat.ts
7
7
  var passkeyAuthMenuCompat_default = require_shell.PasskeyAuthMenu;
@@ -1,17 +1,37 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.js');
3
3
  const require_ThemeProvider = require('../theme/ThemeProvider.js');
4
+ require('./PasskeyAuthMenu.js');
4
5
  const require_themeScope = require('./themeScope.js');
6
+ const require_authMenuTypes = require('./authMenuTypes.js');
5
7
  const require_skeleton = require('./skeleton.js');
6
8
  const require_preload = require('./preload.js');
9
+ const require_hydrationContext = require('./hydrationContext.js');
7
10
  let react = require("react");
8
11
  react = require_rolldown_runtime.__toESM(react);
9
12
  let react_jsx_runtime = require("react/jsx-runtime");
10
13
  react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
11
14
 
12
15
  //#region src/react/components/PasskeyAuthMenu/shell.tsx
13
- function createClientLazy() {
14
- return react.default.lazy(() => Promise.resolve().then(() => require("./client.js")).then((m) => ({ default: m.PasskeyAuthMenuClient })));
16
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.default.useLayoutEffect : react.default.useEffect;
17
+ const clientLazyCache = /* @__PURE__ */ new Map();
18
+ let didClientMountOnce = false;
19
+ let didAutoPreloadClientChunk = false;
20
+ function autoPreloadClientChunk() {
21
+ if (didAutoPreloadClientChunk) return;
22
+ didAutoPreloadClientChunk = true;
23
+ require_preload.preloadPasskeyAuthMenu();
24
+ }
25
+ if (typeof window !== "undefined" && typeof document !== "undefined") autoPreloadClientChunk();
26
+ function getClientLazy(retryKey) {
27
+ const existing = clientLazyCache.get(retryKey);
28
+ if (existing) return existing;
29
+ const next = react.default.lazy(() => Promise.resolve().then(() => require("./client.js")).then((m) => ({ default: m.PasskeyAuthMenuClient })));
30
+ clientLazyCache.set(retryKey, next);
31
+ return next;
32
+ }
33
+ function invalidateClientLazy(retryKey) {
34
+ clientLazyCache.delete(retryKey);
15
35
  }
16
36
  var LazyErrorBoundary = class extends react.default.Component {
17
37
  state = { error: null };
@@ -22,6 +42,9 @@ var LazyErrorBoundary = class extends react.default.Component {
22
42
  this.setState({ error: null });
23
43
  this.props.onRetry();
24
44
  };
45
+ componentDidCatch(error) {
46
+ this.props.onError?.(error);
47
+ }
25
48
  render() {
26
49
  if (this.state.error) return this.props.fallback({
27
50
  error: this.state.error,
@@ -37,43 +60,54 @@ var LazyErrorBoundary = class extends react.default.Component {
37
60
  * - Client: lazy-loads the full implementation after mount.
38
61
  */
39
62
  const PasskeyAuthMenu = (props) => {
40
- const [isClient, setIsClient] = react.default.useState(false);
63
+ const [isClient, setIsClient] = react.default.useState(() => {
64
+ if (typeof window === "undefined") return false;
65
+ return didClientMountOnce;
66
+ });
67
+ const forceInitialRegisterRef = react.default.useRef(!didClientMountOnce && (props.defaultMode == null || props.defaultMode === require_authMenuTypes.AuthMenuMode.Register));
41
68
  const [retryKey, setRetryKey] = react.default.useState(0);
42
- const ClientLazy = react.default.useMemo(() => createClientLazy(), [retryKey]);
69
+ const ClientLazy = react.default.useMemo(() => getClientLazy(retryKey), [retryKey]);
43
70
  const { theme } = require_ThemeProvider.useTheme();
44
- react.default.useEffect(() => {
71
+ useIsomorphicLayoutEffect(() => {
72
+ didClientMountOnce = true;
45
73
  setIsClient(true);
46
- require_preload.preloadPasskeyAuthMenu();
74
+ autoPreloadClientChunk();
47
75
  }, []);
48
76
  const skeleton = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_skeleton.PasskeyAuthMenuSkeletonInner, {
49
77
  className: props.className,
50
- style: props.style
78
+ style: props.style,
79
+ defaultMode: props.defaultMode,
80
+ headings: props.headings
51
81
  });
52
82
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_themeScope.PasskeyAuthMenuThemeScope, {
53
83
  theme,
54
- children: isClient ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LazyErrorBoundary, {
55
- onRetry: () => setRetryKey((k) => k + 1),
56
- fallback: ({ retry }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [skeleton, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57
- style: {
58
- marginTop: 10,
59
- fontSize: 12,
60
- textAlign: "center",
61
- opacity: .9
62
- },
63
- children: [
64
- "Failed to load menu.",
65
- " ",
66
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
67
- type: "button",
68
- onClick: retry,
69
- style: { textDecoration: "underline" },
70
- children: "Retry"
71
- })
72
- ]
73
- })] }),
74
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Suspense, {
75
- fallback: skeleton,
76
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClientLazy, { ...props })
84
+ children: isClient ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_hydrationContext.PasskeyAuthMenuHydrationContext.Provider, {
85
+ value: forceInitialRegisterRef.current,
86
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LazyErrorBoundary, {
87
+ onRetry: () => setRetryKey((k) => k + 1),
88
+ onError: () => invalidateClientLazy(retryKey),
89
+ fallback: ({ retry }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [skeleton, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
90
+ style: {
91
+ marginTop: 10,
92
+ fontSize: 12,
93
+ textAlign: "center",
94
+ opacity: .9
95
+ },
96
+ children: [
97
+ "Failed to load menu.",
98
+ " ",
99
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
100
+ type: "button",
101
+ onClick: retry,
102
+ style: { textDecoration: "underline" },
103
+ children: "Retry"
104
+ })
105
+ ]
106
+ })] }),
107
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Suspense, {
108
+ fallback: skeleton,
109
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClientLazy, { ...props })
110
+ })
77
111
  })
78
112
  }) : skeleton
79
113
  });
@@ -1 +1 @@
1
- {"version":3,"file":"shell.js","names":["React","PasskeyAuthMenu: React.FC<PasskeyAuthMenuProps>","useTheme","PasskeyAuthMenuSkeletonInner","PasskeyAuthMenuThemeScope"],"sources":["../../../../../src/react/components/PasskeyAuthMenu/shell.tsx"],"sourcesContent":["import React from 'react';\nimport { PasskeyAuthMenuSkeletonInner } from './skeleton';\nimport { PasskeyAuthMenuThemeScope } from './themeScope';\nimport type { PasskeyAuthMenuProps } from './types';\nimport { useTheme } from '../theme';\nimport { preloadPasskeyAuthMenu } from './preload';\n\nfunction createClientLazy() {\n return React.lazy(() => import('./client').then((m) => ({ default: m.PasskeyAuthMenuClient })));\n}\n\nclass LazyErrorBoundary extends React.Component<\n {\n fallback: (args: { error: Error; retry: () => void }) => React.ReactNode;\n onRetry: () => void;\n children: React.ReactNode;\n },\n { error: Error | null }\n> {\n state: { error: Error | null } = { error: null };\n\n static getDerivedStateFromError(error: Error): { error: Error } {\n return { error };\n }\n\n retry = () => {\n this.setState({ error: null });\n this.props.onRetry();\n };\n\n render() {\n if (this.state.error) {\n return this.props.fallback({ error: this.state.error, retry: this.retry });\n }\n return this.props.children;\n }\n}\n\n/**\n * `PasskeyAuthMenu` — SSR-safe shell.\n *\n * - Server: renders a skeleton only.\n * - Client: lazy-loads the full implementation after mount.\n */\nexport const PasskeyAuthMenu: React.FC<PasskeyAuthMenuProps> = (props) => {\n const [isClient, setIsClient] = React.useState(false);\n const [retryKey, setRetryKey] = React.useState(0);\n const ClientLazy = React.useMemo(() => createClientLazy(), [retryKey]);\n\n // Align with the SDK Theme boundary when present (TatchiPasskeyProvider wraps one by default).\n // Falls back to system preference when used standalone.\n const { theme } = useTheme();\n\n React.useEffect(() => {\n setIsClient(true);\n // Start fetching the client chunk immediately; the skeleton remains as the Suspense fallback.\n preloadPasskeyAuthMenu();\n }, []);\n\n const skeleton = (\n <PasskeyAuthMenuSkeletonInner className={props.className} style={props.style} />\n );\n\n return (\n <PasskeyAuthMenuThemeScope theme={theme}>\n {isClient ? (\n <LazyErrorBoundary\n onRetry={() => setRetryKey((k) => k + 1)}\n fallback={({ retry }) => (\n <div>\n {skeleton}\n <div style={{ marginTop: 10, fontSize: 12, textAlign: 'center', opacity: 0.9 }}>\n Failed to load menu.{' '}\n <button type=\"button\" onClick={retry} style={{ textDecoration: 'underline' }}>\n Retry\n </button>\n </div>\n </div>\n )}\n >\n <React.Suspense\n fallback={skeleton}\n >\n <ClientLazy {...props} />\n </React.Suspense>\n </LazyErrorBoundary>\n ) : (\n skeleton\n )}\n </PasskeyAuthMenuThemeScope>\n );\n};\n\nexport default PasskeyAuthMenu;\n"],"mappings":";;;;;;;;;;;;AAOA,SAAS,mBAAmB;AAC1B,QAAOA,cAAM,gDAAW,gBAAmB,MAAM,OAAO,EAAE,SAAS,EAAE;;AAGvE,IAAM,oBAAN,cAAgCA,cAAM,UAOpC;CACA,QAAiC,EAAE,OAAO;CAE1C,OAAO,yBAAyB,OAAgC;AAC9D,SAAO,EAAE;;CAGX,cAAc;AACZ,OAAK,SAAS,EAAE,OAAO;AACvB,OAAK,MAAM;;CAGb,SAAS;AACP,MAAI,KAAK,MAAM,MACb,QAAO,KAAK,MAAM,SAAS;GAAE,OAAO,KAAK,MAAM;GAAO,OAAO,KAAK;;AAEpE,SAAO,KAAK,MAAM;;;;;;;;;AAUtB,MAAaC,mBAAmD,UAAU;CACxE,MAAM,CAAC,UAAU,eAAeD,cAAM,SAAS;CAC/C,MAAM,CAAC,UAAU,eAAeA,cAAM,SAAS;CAC/C,MAAM,aAAaA,cAAM,cAAc,oBAAoB,CAAC;CAI5D,MAAM,EAAE,UAAUE;AAElB,eAAM,gBAAgB;AACpB,cAAY;AAEZ;IACC;CAEH,MAAM,WACJ,2CAACC;EAA6B,WAAW,MAAM;EAAW,OAAO,MAAM;;AAGzE,QACE,2CAACC;EAAiC;YAC/B,WACC,2CAAC;GACC,eAAe,aAAa,MAAM,IAAI;GACtC,WAAW,EAAE,YACX,4CAAC,oBACE,UACD,4CAAC;IAAI,OAAO;KAAE,WAAW;KAAI,UAAU;KAAI,WAAW;KAAU,SAAS;;;KAAO;KACzD;KACrB,2CAAC;MAAO,MAAK;MAAS,SAAS;MAAO,OAAO,EAAE,gBAAgB;gBAAe;;;;aAOpF,2CAACJ,cAAM;IACL,UAAU;cAEV,2CAAC,cAAW,GAAI;;OAIpB;;;AAMR,oBAAe"}
1
+ {"version":3,"file":"shell.js","names":["React","preloadPasskeyAuthMenu","PasskeyAuthMenu: React.FC<PasskeyAuthMenuProps>","AuthMenuMode","useTheme","PasskeyAuthMenuSkeletonInner","PasskeyAuthMenuThemeScope","PasskeyAuthMenuHydrationContext"],"sources":["../../../../../src/react/components/PasskeyAuthMenu/shell.tsx"],"sourcesContent":["import React from 'react';\nimport './PasskeyAuthMenu.css';\nimport { PasskeyAuthMenuSkeletonInner } from './skeleton';\nimport { PasskeyAuthMenuThemeScope } from './themeScope';\nimport { AuthMenuMode, type PasskeyAuthMenuProps } from './types';\nimport { useTheme } from '../theme';\nimport { preloadPasskeyAuthMenu } from './preload';\nimport { PasskeyAuthMenuHydrationContext } from './hydrationContext';\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;\n\ntype PasskeyAuthMenuClientComponent = React.ComponentType<PasskeyAuthMenuProps>;\n\nconst clientLazyCache = new Map<number, React.LazyExoticComponent<PasskeyAuthMenuClientComponent>>();\n\nlet didClientMountOnce = false;\n\nlet didAutoPreloadClientChunk = false;\nfunction autoPreloadClientChunk() {\n if (didAutoPreloadClientChunk) return;\n didAutoPreloadClientChunk = true;\n void preloadPasskeyAuthMenu();\n}\n\n// If this module is imported in a browser bundle, start fetching the client chunk immediately.\n// This reduces the chance of a first-mount Suspense fallback flash without affecting SSR.\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n autoPreloadClientChunk();\n}\n\nfunction getClientLazy(retryKey: number): React.LazyExoticComponent<PasskeyAuthMenuClientComponent> {\n const existing = clientLazyCache.get(retryKey);\n if (existing) return existing;\n\n const next = React.lazy(() =>\n import('./client').then((m) => ({ default: m.PasskeyAuthMenuClient })),\n ) as unknown as React.LazyExoticComponent<PasskeyAuthMenuClientComponent>;\n\n clientLazyCache.set(retryKey, next);\n return next;\n}\n\nfunction invalidateClientLazy(retryKey: number) {\n clientLazyCache.delete(retryKey);\n}\n\nclass LazyErrorBoundary extends React.Component<\n {\n fallback: (args: { error: Error; retry: () => void }) => React.ReactNode;\n onRetry: () => void;\n onError?: (error: Error) => void;\n children: React.ReactNode;\n },\n { error: Error | null }\n> {\n state: { error: Error | null } = { error: null };\n\n static getDerivedStateFromError(error: Error): { error: Error } {\n return { error };\n }\n\n retry = () => {\n this.setState({ error: null });\n this.props.onRetry();\n };\n\n componentDidCatch(error: Error) {\n this.props.onError?.(error);\n }\n\n render() {\n if (this.state.error) {\n return this.props.fallback({ error: this.state.error, retry: this.retry });\n }\n return this.props.children;\n }\n}\n\n/**\n * `PasskeyAuthMenu` — SSR-safe shell.\n *\n * - Server: renders a skeleton only.\n * - Client: lazy-loads the full implementation after mount.\n */\nexport const PasskeyAuthMenu: React.FC<PasskeyAuthMenuProps> = (props) => {\n const [isClient, setIsClient] = React.useState(() => {\n if (typeof window === 'undefined') return false;\n return didClientMountOnce;\n });\n const forceInitialRegisterRef = React.useRef(\n !didClientMountOnce && (props.defaultMode == null || props.defaultMode === AuthMenuMode.Register),\n );\n const [retryKey, setRetryKey] = React.useState(0);\n const ClientLazy = React.useMemo(() => getClientLazy(retryKey), [retryKey]);\n\n // Align with the SDK Theme boundary when present (TatchiPasskeyProvider wraps one by default).\n // Falls back to system preference when used standalone.\n const { theme } = useTheme();\n\n useIsomorphicLayoutEffect(() => {\n didClientMountOnce = true;\n setIsClient(true);\n // Start fetching the client chunk immediately; the skeleton remains as the Suspense fallback.\n autoPreloadClientChunk();\n }, []);\n\n const skeleton = (\n <PasskeyAuthMenuSkeletonInner\n className={props.className}\n style={props.style}\n defaultMode={props.defaultMode}\n headings={props.headings}\n />\n );\n\n return (\n <PasskeyAuthMenuThemeScope theme={theme}>\n {isClient ? (\n <PasskeyAuthMenuHydrationContext.Provider value={forceInitialRegisterRef.current}>\n <LazyErrorBoundary\n onRetry={() => setRetryKey((k) => k + 1)}\n onError={() => invalidateClientLazy(retryKey)}\n fallback={({ retry }) => (\n <div>\n {skeleton}\n <div style={{ marginTop: 10, fontSize: 12, textAlign: 'center', opacity: 0.9 }}>\n Failed to load menu.{' '}\n <button type=\"button\" onClick={retry} style={{ textDecoration: 'underline' }}>\n Retry\n </button>\n </div>\n </div>\n )}\n >\n <React.Suspense fallback={skeleton}>\n <ClientLazy {...props} />\n </React.Suspense>\n </LazyErrorBoundary>\n </PasskeyAuthMenuHydrationContext.Provider>\n ) : (\n skeleton\n )}\n </PasskeyAuthMenuThemeScope>\n );\n};\n\nexport default PasskeyAuthMenu;\n"],"mappings":";;;;;;;;;;;;;;;AASA,MAAM,4BAA4B,OAAO,WAAW,cAAcA,cAAM,kBAAkBA,cAAM;AAIhG,MAAM,kCAAkB,IAAI;AAE5B,IAAI,qBAAqB;AAEzB,IAAI,4BAA4B;AAChC,SAAS,yBAAyB;AAChC,KAAI,0BAA2B;AAC/B,6BAA4B;AAC5B,CAAKC;;AAKP,IAAI,OAAO,WAAW,eAAe,OAAO,aAAa,YACvD;AAGF,SAAS,cAAc,UAA6E;CAClG,MAAM,WAAW,gBAAgB,IAAI;AACrC,KAAI,SAAU,QAAO;CAErB,MAAM,OAAOD,cAAM,gDACjB,gBAAmB,MAAM,OAAO,EAAE,SAAS,EAAE;AAG/C,iBAAgB,IAAI,UAAU;AAC9B,QAAO;;AAGT,SAAS,qBAAqB,UAAkB;AAC9C,iBAAgB,OAAO;;AAGzB,IAAM,oBAAN,cAAgCA,cAAM,UAQpC;CACA,QAAiC,EAAE,OAAO;CAE1C,OAAO,yBAAyB,OAAgC;AAC9D,SAAO,EAAE;;CAGX,cAAc;AACZ,OAAK,SAAS,EAAE,OAAO;AACvB,OAAK,MAAM;;CAGb,kBAAkB,OAAc;AAC9B,OAAK,MAAM,UAAU;;CAGvB,SAAS;AACP,MAAI,KAAK,MAAM,MACb,QAAO,KAAK,MAAM,SAAS;GAAE,OAAO,KAAK,MAAM;GAAO,OAAO,KAAK;;AAEpE,SAAO,KAAK,MAAM;;;;;;;;;AAUtB,MAAaE,mBAAmD,UAAU;CACxE,MAAM,CAAC,UAAU,eAAeF,cAAM,eAAe;AACnD,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAO;;CAET,MAAM,0BAA0BA,cAAM,OACpC,CAAC,uBAAuB,MAAM,eAAe,QAAQ,MAAM,gBAAgBG,mCAAa;CAE1F,MAAM,CAAC,UAAU,eAAeH,cAAM,SAAS;CAC/C,MAAM,aAAaA,cAAM,cAAc,cAAc,WAAW,CAAC;CAIjE,MAAM,EAAE,UAAUI;AAElB,iCAAgC;AAC9B,uBAAqB;AACrB,cAAY;AAEZ;IACC;CAEH,MAAM,WACJ,2CAACC;EACC,WAAW,MAAM;EACjB,OAAO,MAAM;EACb,aAAa,MAAM;EACnB,UAAU,MAAM;;AAIpB,QACE,2CAACC;EAAiC;YAC/B,WACC,2CAACC,yDAAgC;GAAS,OAAO,wBAAwB;aACvE,2CAAC;IACC,eAAe,aAAa,MAAM,IAAI;IACtC,eAAe,qBAAqB;IACpC,WAAW,EAAE,YACX,4CAAC,oBACE,UACD,4CAAC;KAAI,OAAO;MAAE,WAAW;MAAI,UAAU;MAAI,WAAW;MAAU,SAAS;;;MAAO;MACzD;MACrB,2CAAC;OAAO,MAAK;OAAS,SAAS;OAAO,OAAO,EAAE,gBAAgB;iBAAe;;;;cAOpF,2CAACP,cAAM;KAAS,UAAU;eACxB,2CAAC,cAAW,GAAI;;;OAKtB;;;AAMR,oBAAe"}
@@ -1,120 +1,174 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.js');
3
3
  const require_ThemeProvider = require('../theme/ThemeProvider.js');
4
- require('./PasskeyAuthMenu.js');
4
+ const require_ArrowLeft = require('./ui/icons/ArrowLeft.js');
5
+ const require_Mail = require('./ui/icons/Mail.js');
6
+ const require_QRCodeIcon = require('../QRCodeIcon.js');
5
7
  const require_themeScope = require('./themeScope.js');
8
+ const require_authMenuTypes = require('./authMenuTypes.js');
9
+ const require_mode = require('./controller/mode.js');
6
10
  let react = require("react");
7
11
  react = require_rolldown_runtime.__toESM(react);
8
12
  let react_jsx_runtime = require("react/jsx-runtime");
9
13
  react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
10
14
 
11
15
  //#region src/react/components/PasskeyAuthMenu/skeleton.tsx
12
- const PasskeyAuthMenuSkeletonInner = react.default.forwardRef(({ className, style }, ref) => {
13
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16
+ const PasskeyAuthMenuSkeletonInner = react.default.forwardRef(({ className, style, defaultMode, headings }, ref) => {
17
+ const mode = typeof defaultMode === "number" ? defaultMode : require_authMenuTypes.AuthMenuMode.Register;
18
+ const title = require_mode.getModeTitle(mode, headings ?? null);
19
+ const placeholder = mode === require_authMenuTypes.AuthMenuMode.Register ? "Pick a username" : mode === require_authMenuTypes.AuthMenuMode.Sync ? "Leave blank to discover accounts" : "Enter your username";
20
+ const segHelpText = mode === require_authMenuTypes.AuthMenuMode.Login ? "Sign in with your passkey" : mode === require_authMenuTypes.AuthMenuMode.Sync ? "Sync account (iCloud/Chrome sync)" : "Create a new account";
21
+ const segActiveWidth = "calc((100% - 18px) / 3)";
22
+ const segActiveX = mode === require_authMenuTypes.AuthMenuMode.Login ? `calc(5px + ${segActiveWidth} + 4px)` : mode === require_authMenuTypes.AuthMenuMode.Sync ? `calc(5px + ${segActiveWidth} + 4px + ${segActiveWidth} + 4px)` : "5px";
23
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14
24
  ref,
15
25
  className: `w3a-signup-menu-root w3a-skeleton${className ? ` ${className}` : ""}`,
16
26
  style,
17
- children: [
18
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
19
- className: "w3a-header",
20
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21
- className: "w3a-skeleton-block w3a-title-skeleton",
22
- style: {
23
- width: "60%",
24
- height: "24px",
25
- marginBottom: "8px"
26
- }
27
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
28
- className: "w3a-skeleton-block w3a-subtitle-skeleton",
29
- style: {
30
- width: "80%",
31
- height: "16px"
32
- }
33
- })]
34
- }),
35
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
36
- className: "w3a-passkey-row",
37
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
38
- className: "w3a-input-pill w3a-skeleton-input",
39
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
40
- className: "w3a-skeleton-block",
41
- style: {
42
- width: "40%",
43
- height: "18px",
44
- marginLeft: "12px"
45
- }
46
- })
47
- })
48
- }),
49
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
50
- className: "w3a-segmented-root",
51
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
52
- className: "w3a-seg-track",
53
- children: [
54
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
55
- className: "w3a-seg-button",
56
- children: "Register"
57
- }),
58
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
59
- className: "w3a-seg-button",
60
- children: "Login"
61
- }),
62
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
63
- className: "w3a-seg-button",
64
- children: "Sync"
65
- })
66
- ]
27
+ "data-mode": mode,
28
+ "data-waiting": "false",
29
+ "data-scan-device": "false",
30
+ "data-email-recovery": "false",
31
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
32
+ className: "w3a-content-switcher",
33
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
34
+ "aria-label": "Back",
35
+ type: "button",
36
+ className: "w3a-back-button",
37
+ disabled: true,
38
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ArrowLeft.ArrowLeftIcon, {
39
+ size: 18,
40
+ strokeWidth: 2.25,
41
+ style: { display: "block" }
67
42
  })
68
- }),
69
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
70
- className: "w3a-seg-help-row",
43
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
44
+ className: "w3a-content-area",
71
45
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
72
- className: "w3a-skeleton-block",
73
- style: {
74
- width: "50%",
75
- height: "14px",
76
- margin: "0 auto"
77
- }
78
- })
79
- }),
80
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
81
- className: "w3a-scan-device-row",
82
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
83
- className: "w3a-section-divider",
84
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
85
- className: "w3a-section-divider-text",
86
- children: "Already have an account?"
46
+ className: "w3a-content-sizer",
47
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
48
+ className: "w3a-signin-menu",
49
+ children: [
50
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
51
+ className: "w3a-header",
52
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
53
+ className: "w3a-title",
54
+ children: title.title
55
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
56
+ className: "w3a-subhead",
57
+ children: title.subtitle
58
+ })] })
59
+ }),
60
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
61
+ className: "w3a-passkey-row",
62
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
63
+ className: "w3a-input-pill",
64
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
65
+ className: "w3a-input-wrap",
66
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
67
+ type: "text",
68
+ name: "passkey",
69
+ disabled: true,
70
+ placeholder,
71
+ className: "w3a-input",
72
+ "aria-disabled": "true",
73
+ autoCapitalize: "none",
74
+ autoCorrect: "off",
75
+ spellCheck: false,
76
+ inputMode: "text",
77
+ style: { pointerEvents: "none" }
78
+ })
79
+ })
80
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
81
+ style: {
82
+ position: "relative",
83
+ display: "inline-block"
84
+ },
85
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
86
+ "aria-label": "Continue",
87
+ type: "button",
88
+ className: "w3a-arrow-btn no-transition",
89
+ disabled: true
90
+ })
91
+ })]
92
+ }),
93
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
94
+ className: "w3a-seg",
95
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
96
+ className: "w3a-seg-active",
97
+ style: {
98
+ width: segActiveWidth,
99
+ transform: `translateX(${segActiveX})`,
100
+ opacity: .9,
101
+ background: "var(--w3a-passkey-auth-menu2-seg-active-bg)"
102
+ }
103
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
104
+ className: "w3a-seg-grid",
105
+ children: [
106
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
107
+ type: "button",
108
+ "aria-pressed": mode === require_authMenuTypes.AuthMenuMode.Register,
109
+ className: `w3a-seg-btn${mode === require_authMenuTypes.AuthMenuMode.Register ? " is-active" : ""} register`,
110
+ disabled: true,
111
+ children: "Register"
112
+ }),
113
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
114
+ type: "button",
115
+ "aria-pressed": mode === require_authMenuTypes.AuthMenuMode.Login,
116
+ className: `w3a-seg-btn${mode === require_authMenuTypes.AuthMenuMode.Login ? " is-active" : ""} login`,
117
+ disabled: true,
118
+ children: "Login"
119
+ }),
120
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
121
+ type: "button",
122
+ "aria-pressed": mode === require_authMenuTypes.AuthMenuMode.Sync,
123
+ className: `w3a-seg-btn${mode === require_authMenuTypes.AuthMenuMode.Sync ? " is-active" : ""} sync`,
124
+ disabled: true,
125
+ children: "Sync"
126
+ })
127
+ ]
128
+ })]
129
+ }),
130
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
131
+ className: "w3a-seg-help-row",
132
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
133
+ className: "w3a-seg-help",
134
+ "aria-live": "polite",
135
+ children: segHelpText
136
+ })
137
+ }),
138
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
139
+ className: "w3a-scan-device-row",
140
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
141
+ className: "w3a-section-divider",
142
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
143
+ className: "w3a-section-divider-text",
144
+ children: "Already have an account?"
145
+ })
146
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
147
+ className: "w3a-secondary-actions",
148
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
149
+ className: "w3a-link-device-btn",
150
+ disabled: true,
151
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_QRCodeIcon.default, {
152
+ width: 18,
153
+ height: 18,
154
+ strokeWidth: 2
155
+ }), "Scan and Link Device"]
156
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
157
+ className: "w3a-link-device-btn",
158
+ disabled: true,
159
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Mail.MailIcon, {
160
+ size: 18,
161
+ strokeWidth: 2,
162
+ style: { display: "block" }
163
+ }), "Recover Account with Email"]
164
+ })]
165
+ })]
166
+ })
167
+ ]
87
168
  })
88
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
89
- className: "w3a-secondary-actions",
90
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
91
- className: "w3a-link-device-btn",
92
- disabled: true,
93
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
94
- className: "w3a-skeleton-block",
95
- style: {
96
- width: "18px",
97
- height: "18px",
98
- marginRight: "8px",
99
- borderRadius: "4px"
100
- }
101
- }), "Scan and Link Device"]
102
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
103
- className: "w3a-link-device-btn",
104
- disabled: true,
105
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
106
- className: "w3a-skeleton-block",
107
- style: {
108
- width: "18px",
109
- height: "18px",
110
- marginRight: "8px",
111
- borderRadius: "9999px"
112
- }
113
- }), "Recover Account with Email"]
114
- })]
115
- })]
116
- })
117
- ]
169
+ })
170
+ })]
171
+ })
118
172
  });
119
173
  });
120
174
  PasskeyAuthMenuSkeletonInner.displayName = "PasskeyAuthMenuSkeletonInner";