@intlayer/design-system 9.4.1 → 9.4.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 (215) hide show
  1. package/README.md +1 -1
  2. package/dist/esm/api/index.mjs +2 -2
  3. package/dist/esm/api/useUser/index.mjs +1 -1
  4. package/dist/esm/components/Avatar/index.mjs +1 -1
  5. package/dist/esm/components/Avatar/index.mjs.map +1 -1
  6. package/dist/esm/components/Badge/index.mjs +3 -3
  7. package/dist/esm/components/Badge/index.mjs.map +1 -1
  8. package/dist/esm/components/Breadcrumb/index.mjs +5 -5
  9. package/dist/esm/components/Breadcrumb/index.mjs.map +1 -1
  10. package/dist/esm/components/Browser/Browser.mjs +4 -4
  11. package/dist/esm/components/Browser/Browser.mjs.map +1 -1
  12. package/dist/esm/components/Button/Button.mjs +1 -0
  13. package/dist/esm/components/Button/Button.mjs.map +1 -1
  14. package/dist/esm/components/Carousel/index.mjs +5 -5
  15. package/dist/esm/components/Carousel/index.mjs.map +1 -1
  16. package/dist/esm/components/CollapsibleTable/CollapsibleTable.mjs +5 -5
  17. package/dist/esm/components/CollapsibleTable/CollapsibleTable.mjs.map +1 -1
  18. package/dist/esm/components/Container/index.mjs +2 -2
  19. package/dist/esm/components/Container/index.mjs.map +1 -1
  20. package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
  21. package/dist/esm/components/DictionaryEditor/ItemLayout.mjs +1 -1
  22. package/dist/esm/components/DictionaryEditor/ItemLayout.mjs.map +1 -1
  23. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +7 -7
  24. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
  25. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +1 -1
  26. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +9 -9
  27. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs.map +1 -1
  28. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +4 -4
  29. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs.map +1 -1
  30. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +1 -1
  31. package/dist/esm/components/DictionaryFieldEditor/{ContentEditor.mjs → NodeEditor.mjs} +9 -9
  32. package/dist/esm/components/DictionaryFieldEditor/NodeEditor.mjs.map +1 -0
  33. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +3 -3
  34. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs.map +1 -1
  35. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +2 -2
  36. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs.map +1 -1
  37. package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcher.mjs +2 -2
  38. package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcher.mjs.map +1 -1
  39. package/dist/esm/components/DictionaryFieldEditor/index.mjs +3 -3
  40. package/dist/esm/components/Footer/index.mjs +5 -3
  41. package/dist/esm/components/Footer/index.mjs.map +1 -1
  42. package/dist/esm/components/HeightResizer/index.mjs +1 -1
  43. package/dist/esm/components/HeightResizer/index.mjs.map +1 -1
  44. package/dist/esm/components/IDE/Code.mjs +1 -1
  45. package/dist/esm/components/IDE/Code.mjs.map +1 -1
  46. package/dist/esm/components/IDE/CodeBlockHighlight.mjs +1 -1
  47. package/dist/esm/components/IDE/CodeBlockHighlight.mjs.map +1 -1
  48. package/dist/esm/components/IDE/CodeBlockServer.mjs +1 -1
  49. package/dist/esm/components/IDE/CodeBlockServer.mjs.map +1 -1
  50. package/dist/esm/components/IDE/CodeBlockShiki.mjs +6 -48
  51. package/dist/esm/components/IDE/CodeBlockShiki.mjs.map +1 -1
  52. package/dist/esm/components/IDE/FileList.mjs +1 -1
  53. package/dist/esm/components/IDE/FileList.mjs.map +1 -1
  54. package/dist/esm/components/IDE/FileTree.mjs +1 -1
  55. package/dist/esm/components/IDE/FileTree.mjs.map +1 -1
  56. package/dist/esm/components/IDE/IDE.mjs +10 -7
  57. package/dist/esm/components/IDE/IDE.mjs.map +1 -1
  58. package/dist/esm/components/IDE/MarkDownRender.mjs +4 -3
  59. package/dist/esm/components/IDE/MarkDownRender.mjs.map +1 -1
  60. package/dist/esm/components/IDE/shikiBundle.mjs +61 -0
  61. package/dist/esm/components/IDE/shikiBundle.mjs.map +1 -0
  62. package/dist/esm/components/IDE/shikiLanguages.mjs +2 -39
  63. package/dist/esm/components/IDE/shikiLanguages.mjs.map +1 -1
  64. package/dist/esm/components/IDE/shikiThemes.mjs.map +1 -1
  65. package/dist/esm/components/Input/Checkbox.mjs +4 -4
  66. package/dist/esm/components/Input/Checkbox.mjs.map +1 -1
  67. package/dist/esm/components/Input/Input.mjs +2 -2
  68. package/dist/esm/components/Input/Input.mjs.map +1 -1
  69. package/dist/esm/components/Input/OTPInput.mjs +1 -1
  70. package/dist/esm/components/Input/OTPInput.mjs.map +1 -1
  71. package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs +2 -2
  72. package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs.map +1 -1
  73. package/dist/esm/components/LanguageBackground/LanguageSection.mjs +6 -8
  74. package/dist/esm/components/LanguageBackground/LanguageSection.mjs.map +1 -1
  75. package/dist/esm/components/LanguageBackground/index.mjs +2 -2
  76. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +2 -2
  77. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs.map +1 -1
  78. package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs +8 -3
  79. package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs.map +1 -1
  80. package/dist/esm/components/MarkDownRender/MarkDownRender.mjs +9 -8
  81. package/dist/esm/components/MarkDownRender/MarkDownRender.mjs.map +1 -1
  82. package/dist/esm/components/MarkdownEditor/MarkdownEditor.mjs +2 -2
  83. package/dist/esm/components/MarkdownEditor/MarkdownEditor.mjs.map +1 -1
  84. package/dist/esm/components/MarkdownEditor/extensions.mjs +1 -1
  85. package/dist/esm/components/MarkdownEditor/extensions.mjs.map +1 -1
  86. package/dist/esm/components/MarkdownEditor/generative/AISelector.mjs +3 -3
  87. package/dist/esm/components/MarkdownEditor/generative/AISelector.mjs.map +1 -1
  88. package/dist/esm/components/MarkdownEditor/generative/AISelectorCommands.mjs +2 -2
  89. package/dist/esm/components/MarkdownEditor/generative/AISelectorCommands.mjs.map +1 -1
  90. package/dist/esm/components/MarkdownEditor/generative/GenerativeMenuSwitch.mjs +2 -2
  91. package/dist/esm/components/MarkdownEditor/generative/GenerativeMenuSwitch.mjs.map +1 -1
  92. package/dist/esm/components/MarkdownEditor/novel/extensions/code-block-shiki.mjs +197 -0
  93. package/dist/esm/components/MarkdownEditor/novel/extensions/code-block-shiki.mjs.map +1 -0
  94. package/dist/esm/components/MarkdownEditor/novel/extensions/index.mjs +2 -1
  95. package/dist/esm/components/MarkdownEditor/novel/extensions/index.mjs.map +1 -1
  96. package/dist/esm/components/MarkdownEditor/novel/index.mjs +2 -1
  97. package/dist/esm/components/Modal/Modal.mjs +0 -1
  98. package/dist/esm/components/Modal/Modal.mjs.map +1 -1
  99. package/dist/esm/components/Navbar/DesktopNavbar.mjs +3 -3
  100. package/dist/esm/components/Navbar/DesktopNavbar.mjs.map +1 -1
  101. package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
  102. package/dist/esm/components/Navbar/MobileNavbar.mjs.map +1 -1
  103. package/dist/esm/components/Pattern/GridDistortionPattern.mjs +2 -2
  104. package/dist/esm/components/Pattern/GridDistortionPattern.mjs.map +1 -1
  105. package/dist/esm/components/Pattern/GridPattern.mjs +1 -1
  106. package/dist/esm/components/Pattern/GridPattern.mjs.map +1 -1
  107. package/dist/esm/components/RightDrawer/RightDrawer.mjs +2 -2
  108. package/dist/esm/components/RightDrawer/RightDrawer.mjs.map +1 -1
  109. package/dist/esm/components/Select/Multiselect.mjs +2 -2
  110. package/dist/esm/components/Select/Multiselect.mjs.map +1 -1
  111. package/dist/esm/components/Select/Select.mjs +2 -2
  112. package/dist/esm/components/Select/Select.mjs.map +1 -1
  113. package/dist/esm/components/Status/index.mjs +28 -0
  114. package/dist/esm/components/Status/index.mjs.map +1 -0
  115. package/dist/esm/components/Steps/index.mjs +3 -3
  116. package/dist/esm/components/Steps/index.mjs.map +1 -1
  117. package/dist/esm/components/SwitchSelector/SwitchSelector.mjs +12 -11
  118. package/dist/esm/components/SwitchSelector/SwitchSelector.mjs.map +1 -1
  119. package/dist/esm/components/SwitchSelector/VerticalSwitchSelector.mjs +6 -6
  120. package/dist/esm/components/SwitchSelector/VerticalSwitchSelector.mjs.map +1 -1
  121. package/dist/esm/components/Tab/Tab.mjs +1 -1
  122. package/dist/esm/components/Tab/Tab.mjs.map +1 -1
  123. package/dist/esm/components/TabSelector/TabSelector.mjs +5 -5
  124. package/dist/esm/components/TabSelector/TabSelector.mjs.map +1 -1
  125. package/dist/esm/components/Table/SmartTable.mjs +2 -2
  126. package/dist/esm/components/Table/SmartTable.mjs.map +1 -1
  127. package/dist/esm/components/Table/Table.mjs +1 -1
  128. package/dist/esm/components/Table/Table.mjs.map +1 -1
  129. package/dist/esm/components/Table/TableElements.mjs +2 -2
  130. package/dist/esm/components/Table/TableElements.mjs.map +1 -1
  131. package/dist/esm/components/Tag/index.mjs +1 -1
  132. package/dist/esm/components/Tag/index.mjs.map +1 -1
  133. package/dist/esm/components/TechLogo/TechLogo.mjs +2 -0
  134. package/dist/esm/components/TechLogo/TechLogo.mjs.map +1 -1
  135. package/dist/esm/components/TechLogo/logos/HTMX.mjs +31 -0
  136. package/dist/esm/components/TechLogo/logos/HTMX.mjs.map +1 -0
  137. package/dist/esm/components/TechLogo/logos/Remix.mjs +22 -0
  138. package/dist/esm/components/TechLogo/logos/Remix.mjs.map +1 -0
  139. package/dist/esm/components/TechLogo/techLogos.mjs +5 -1
  140. package/dist/esm/components/TechLogo/techLogos.mjs.map +1 -1
  141. package/dist/esm/components/Terminal/Terminal.mjs +4 -4
  142. package/dist/esm/components/Terminal/Terminal.mjs.map +1 -1
  143. package/dist/esm/components/TextArea/TextArea.mjs.map +1 -1
  144. package/dist/esm/components/Toaster/Toast.mjs +4 -4
  145. package/dist/esm/components/Toaster/Toast.mjs.map +1 -1
  146. package/dist/esm/components/index.mjs +8 -7
  147. package/dist/esm/hooks/usePersistedStore.mjs +6 -18
  148. package/dist/esm/hooks/usePersistedStore.mjs.map +1 -1
  149. package/dist/esm/providers/ReactQueryProvider.mjs +10 -2
  150. package/dist/esm/providers/ReactQueryProvider.mjs.map +1 -1
  151. package/dist/esm/providers/ThemeProvider.mjs +27 -15
  152. package/dist/esm/providers/ThemeProvider.mjs.map +1 -1
  153. package/dist/esm/routes.mjs +24 -6
  154. package/dist/esm/routes.mjs.map +1 -1
  155. package/dist/esm/structured-data/buildItemListJsonLd.mjs +27 -0
  156. package/dist/esm/structured-data/buildItemListJsonLd.mjs.map +1 -0
  157. package/dist/esm/structured-data/index.mjs +2 -1
  158. package/dist/types/components/Badge/index.d.ts.map +1 -1
  159. package/dist/types/components/Button/Button.d.ts +2 -2
  160. package/dist/types/components/Button/Button.d.ts.map +1 -1
  161. package/dist/types/components/Container/index.d.ts.map +1 -1
  162. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts.map +1 -1
  163. package/dist/types/components/DictionaryFieldEditor/NodeEditor.d.ts +10 -0
  164. package/dist/types/components/DictionaryFieldEditor/NodeEditor.d.ts.map +1 -0
  165. package/dist/types/components/DictionaryFieldEditor/index.d.ts +2 -2
  166. package/dist/types/components/Footer/index.d.ts.map +1 -1
  167. package/dist/types/components/Form/FormBase.d.ts +1 -1
  168. package/dist/types/components/IDE/CodeBlockServer.d.ts +1 -1
  169. package/dist/types/components/IDE/CodeBlockServer.d.ts.map +1 -1
  170. package/dist/types/components/IDE/CodeBlockShiki.d.ts.map +1 -1
  171. package/dist/types/components/IDE/MarkDownRender.d.ts +1 -0
  172. package/dist/types/components/IDE/MarkDownRender.d.ts.map +1 -1
  173. package/dist/types/components/IDE/shikiBundle.d.ts +74 -0
  174. package/dist/types/components/IDE/shikiBundle.d.ts.map +1 -0
  175. package/dist/types/components/IDE/shikiLanguages.d.ts +2 -39
  176. package/dist/types/components/IDE/shikiLanguages.d.ts.map +1 -1
  177. package/dist/types/components/IDE/shikiThemes.d.ts +3 -1
  178. package/dist/types/components/IDE/shikiThemes.d.ts.map +1 -1
  179. package/dist/types/components/LanguageBackground/LanguageSection.d.ts +5 -1
  180. package/dist/types/components/LanguageBackground/LanguageSection.d.ts.map +1 -1
  181. package/dist/types/components/LanguageBackground/index.d.ts +2 -2
  182. package/dist/types/components/MarkDownRender/MarkDownIframe.d.ts.map +1 -1
  183. package/dist/types/components/MarkDownRender/MarkDownRender.d.ts.map +1 -1
  184. package/dist/types/components/MarkdownEditor/novel/extensions/code-block-shiki.d.ts +15 -0
  185. package/dist/types/components/MarkdownEditor/novel/extensions/code-block-shiki.d.ts.map +1 -0
  186. package/dist/types/components/MarkdownEditor/novel/extensions/index.d.ts +2 -1
  187. package/dist/types/components/MarkdownEditor/novel/extensions/index.d.ts.map +1 -1
  188. package/dist/types/components/MarkdownEditor/novel/index.d.ts +2 -1
  189. package/dist/types/components/Status/index.d.ts +8 -0
  190. package/dist/types/components/Status/index.d.ts.map +1 -0
  191. package/dist/types/components/SwitchSelector/SwitchSelector.d.ts +3 -3
  192. package/dist/types/components/SwitchSelector/SwitchSelector.d.ts.map +1 -1
  193. package/dist/types/components/Table/TableElements.d.ts.map +1 -1
  194. package/dist/types/components/TechLogo/TechLogo.d.ts.map +1 -1
  195. package/dist/types/components/TechLogo/logos/HTMX.d.ts +6 -0
  196. package/dist/types/components/TechLogo/logos/HTMX.d.ts.map +1 -0
  197. package/dist/types/components/TechLogo/logos/Remix.d.ts +6 -0
  198. package/dist/types/components/TechLogo/logos/Remix.d.ts.map +1 -0
  199. package/dist/types/components/TechLogo/techLogos.d.ts +4 -2
  200. package/dist/types/components/TechLogo/types.d.ts +1 -1
  201. package/dist/types/components/TextArea/TextArea.d.ts +1 -1
  202. package/dist/types/components/index.d.ts +3 -2
  203. package/dist/types/providers/ThemeProvider.d.ts.map +1 -1
  204. package/dist/types/routes.d.ts +21 -3
  205. package/dist/types/routes.d.ts.map +1 -1
  206. package/dist/types/structured-data/buildItemListJsonLd.d.ts +36 -0
  207. package/dist/types/structured-data/buildItemListJsonLd.d.ts.map +1 -0
  208. package/dist/types/structured-data/index.d.ts +2 -1
  209. package/package.json +68 -54
  210. package/src/components/MarkdownEditor/markdown-editor.css +17 -17
  211. package/styles/globals.css +71 -0
  212. package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs.map +0 -1
  213. package/dist/types/components/DictionaryFieldEditor/ContentEditor.d.ts +0 -10
  214. package/dist/types/components/DictionaryFieldEditor/ContentEditor.d.ts.map +0 -1
  215. package/tailwind.css +0 -269
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.mjs","names":[],"sources":["../../../../src/components/Input/Checkbox.tsx"],"sourcesContent":["import { cn } from '@utils/cn';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport type {\n DetailedHTMLProps,\n FC,\n InputHTMLAttributes,\n ReactNode,\n} from 'react';\n\nexport const checkboxVariants = cva(\n [\n 'appearance-none',\n 'relative cursor-pointer border-2',\n 'focus:outline-0',\n 'checked:hover:opacity-80',\n 'ring-offset-background',\n 'hover:bg-neutral-500/10',\n 'disabled:opacity-50',\n\n // Ring + animation\n 'ring-0 transition-all duration-300 ease-in-out hover:ring-4 focus-visible:ring-6',\n\n // centered custom checkmark with text-opposite color\n \"checked:before:absolute checked:before:inset-0 checked:before:content-['✓']\",\n 'checked:before:flex checked:before:items-center checked:before:justify-center',\n 'checked:before:text-text-opposite/80',\n\n // Corner shape\n 'rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl',\n\n \"after:absolute after:-inset-2 after:content-['']\",\n ].join(' '),\n {\n variants: {\n variant: {\n default: '',\n },\n size: {\n xs: 'size-3 rounded-sm',\n sm: 'size-4 rounded-md',\n md: 'size-5 rounded-lg',\n lg: 'size-6 rounded-xl',\n },\n color: {\n primary:\n 'border-primary/30 text-primary ring-primary/20 checked:border-primary checked:bg-primary',\n secondary:\n 'border-secondary/30 text-secondary ring-secondary/20 checked:border-secondary checked:bg-secondary',\n neutral:\n 'border-neutral/30 text-neutral ring-neutral/20 checked:border-neutral checked:bg-neutral',\n light:\n 'border-white/30 text-white ring-white/20 checked:border-white checked:bg-white',\n text: 'border-text/30 text-text ring-text/20 checked:border-text checked:bg-text',\n 'text-inverse':\n 'border-text-inverse/30 text-text-inverse ring-text-inverse/20 checked:border-text-inverse checked:bg-text-inverse',\n dark: 'border-neutral-800/30 text-neutral-800 ring-neutral-800/20 checked:border-neutral-800 checked:bg-neutral-800',\n error:\n 'border-error/30 text-error ring-error/20 checked:border-error checked:bg-error',\n success:\n 'border-success/30 text-success ring-success/20 checked:border-success checked:bg-success',\n custom:\n 'border-custom/30 text-custom ring-custom/20 checked:border-custom checked:bg-custom',\n },\n validationStyleEnabled: {\n disabled: '',\n enabled: 'valid:border-success invalid:border-error',\n },\n },\n defaultVariants: {\n variant: 'default',\n color: 'text',\n validationStyleEnabled: 'disabled',\n size: 'md',\n },\n }\n);\n\nexport type CheckboxSize = 'xs' | 'sm' | 'md' | 'lg';\n\nexport type CheckboxColor =\n | 'primary'\n | 'secondary'\n | 'neutral'\n | 'light'\n | 'text'\n | 'text-inverse'\n | 'dark'\n | 'error'\n | 'success'\n | 'custom';\n\nexport type CheckboxProps = Omit<\n DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,\n 'size'\n> & {\n name: string;\n validationStyleEnabled?: boolean;\n label?: ReactNode;\n} & Omit<\n VariantProps<typeof checkboxVariants>,\n 'validationStyleEnabled' | 'size' | 'color'\n > & {\n size?: CheckboxSize | `${CheckboxSize}`;\n color?: CheckboxColor | `${CheckboxColor}`;\n labelClassName?: string;\n };\n\nconst Input: FC<CheckboxProps> = ({\n validationStyleEnabled = false,\n label,\n size,\n color,\n name,\n variant,\n className,\n labelClassName,\n ...props\n}) => (\n <input\n type=\"checkbox\"\n className={cn(\n checkboxVariants({\n variant,\n size,\n color,\n validationStyleEnabled: validationStyleEnabled ? 'enabled' : 'disabled',\n }),\n className\n )}\n {...props}\n />\n);\n\nexport const Checkbox: FC<CheckboxProps> = (props) => {\n const { label, name, id } = props;\n\n return label ? (\n <label\n htmlFor={id ?? name}\n className={cn(\n 'flex w-full cursor-pointer items-center gap-x-4 font-medium text-sm',\n props.size === 'xs' && 'text-xs',\n props.labelClassName\n )}\n >\n <Input id={id ?? name} {...props} />\n {label}\n </label>\n ) : (\n <Input id={id ?? name} {...props} />\n );\n};\n"],"mappings":";;;;;AASA,MAAa,mBAAmB,IAC9B;CACE;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CAGA;CACA;CACA;CAGA;CAEA;AACF,CAAC,CAAC,KAAK,GAAG,GACV;CACE,UAAU;EACR,SAAS,EACP,SAAS,GACX;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EACA,OAAO;GACL,SACE;GACF,WACE;GACF,SACE;GACF,OACE;GACF,MAAM;GACN,gBACE;GACF,MAAM;GACN,OACE;GACF,SACE;GACF,QACE;EACJ;EACA,wBAAwB;GACtB,UAAU;GACV,SAAS;EACX;CACF;CACA,iBAAiB;EACf,SAAS;EACT,OAAO;EACP,wBAAwB;EACxB,MAAM;CACR;AACF,CACF;AAgCA,MAAM,SAA4B,EAChC,yBAAyB,OACzB,OACA,MACA,OACA,MACA,SACA,WACA,gBACA,GAAG,YAEH,oBAAC,SAAD;CACE,MAAK;CACL,WAAW,GACT,iBAAiB;EACf;EACA;EACA;EACA,wBAAwB,yBAAyB,YAAY;CAC/D,CAAC,GACD,SACF;CACA,GAAI;AACL;AAGH,MAAa,YAA+B,UAAU;CACpD,MAAM,EAAE,OAAO,MAAM,OAAO;CAE5B,OAAO,QACL,qBAAC,SAAD;EACE,SAAS,MAAM;EACf,WAAW,GACT,uEACA,MAAM,SAAS,QAAQ,WACvB,MAAM,cACR;YANF,CAQE,oBAAC,OAAD;GAAO,IAAI,MAAM;GAAM,GAAI;EAAQ,IAClC,KACI;MAEP,oBAAC,OAAD;EAAO,IAAI,MAAM;EAAM,GAAI;CAAQ;AAEvC"}
1
+ {"version":3,"file":"Checkbox.mjs","names":[],"sources":["../../../../src/components/Input/Checkbox.tsx"],"sourcesContent":["import { cn } from '@utils/cn';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport type {\n DetailedHTMLProps,\n FC,\n InputHTMLAttributes,\n ReactNode,\n} from 'react';\n\nexport const checkboxVariants = cva(\n [\n 'appearance-none',\n 'relative cursor-pointer border-2',\n 'focus:outline-0',\n 'checked:hover:opacity-80',\n 'ring-offset-background',\n 'hover:bg-neutral-500/10',\n 'disabled:opacity-50',\n\n // Ring + animation\n 'ring-0 transition-all duration-300 ease-in-out hover:ring-4 focus-visible:ring-6',\n\n // centered custom checkmark with text-opposite color\n \"checked:before:absolute checked:before:inset-0 checked:before:content-['✓']\",\n 'checked:before:flex checked:before:items-center checked:before:justify-center',\n 'checked:before:text-foreground-opposite/80',\n\n // Corner shape\n 'rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl',\n\n \"after:absolute after:-inset-2 after:content-['']\",\n ].join(' '),\n {\n variants: {\n variant: {\n default: '',\n },\n size: {\n xs: 'size-3 rounded-sm',\n sm: 'size-4 rounded-md',\n md: 'size-5 rounded-lg',\n lg: 'size-6 rounded-xl',\n },\n color: {\n primary:\n 'border-primary/30 text-primary ring-primary/20 checked:border-primary checked:bg-primary',\n secondary:\n 'border-secondary/30 text-secondary ring-secondary/20 checked:border-secondary checked:bg-secondary',\n neutral:\n 'border-neutral/30 text-muted-foreground ring-neutral/20 checked:border-neutral checked:bg-neutral',\n light:\n 'border-white/30 text-white ring-white/20 checked:border-white checked:bg-white',\n text: 'border-text/30 text-foreground ring-text/20 checked:border-text checked:bg-text',\n 'text-inverse':\n 'border-text-inverse/30 text-foreground-inverse ring-text-inverse/20 checked:border-text-inverse checked:bg-text-inverse',\n dark: 'border-neutral-800/30 text-neutral-800 ring-neutral-800/20 checked:border-neutral-800 checked:bg-neutral-800',\n error:\n 'border-error/30 text-error ring-error/20 checked:border-error checked:bg-error',\n success:\n 'border-success/30 text-success ring-success/20 checked:border-success checked:bg-success',\n custom:\n 'border-custom/30 text-custom ring-custom/20 checked:border-custom checked:bg-custom',\n },\n validationStyleEnabled: {\n disabled: '',\n enabled: 'valid:border-success invalid:border-error',\n },\n },\n defaultVariants: {\n variant: 'default',\n color: 'text',\n validationStyleEnabled: 'disabled',\n size: 'md',\n },\n }\n);\n\nexport type CheckboxSize = 'xs' | 'sm' | 'md' | 'lg';\n\nexport type CheckboxColor =\n | 'primary'\n | 'secondary'\n | 'neutral'\n | 'light'\n | 'text'\n | 'text-inverse'\n | 'dark'\n | 'error'\n | 'success'\n | 'custom';\n\nexport type CheckboxProps = Omit<\n DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,\n 'size'\n> & {\n name: string;\n validationStyleEnabled?: boolean;\n label?: ReactNode;\n} & Omit<\n VariantProps<typeof checkboxVariants>,\n 'validationStyleEnabled' | 'size' | 'color'\n > & {\n size?: CheckboxSize | `${CheckboxSize}`;\n color?: CheckboxColor | `${CheckboxColor}`;\n labelClassName?: string;\n };\n\nconst Input: FC<CheckboxProps> = ({\n validationStyleEnabled = false,\n label,\n size,\n color,\n name,\n variant,\n className,\n labelClassName,\n ...props\n}) => (\n <input\n type=\"checkbox\"\n className={cn(\n checkboxVariants({\n variant,\n size,\n color,\n validationStyleEnabled: validationStyleEnabled ? 'enabled' : 'disabled',\n }),\n className\n )}\n {...props}\n />\n);\n\nexport const Checkbox: FC<CheckboxProps> = (props) => {\n const { label, name, id } = props;\n\n return label ? (\n <label\n htmlFor={id ?? name}\n className={cn(\n 'flex w-full cursor-pointer items-center gap-x-4 font-medium text-sm',\n props.size === 'xs' && 'text-xs',\n props.labelClassName\n )}\n >\n <Input id={id ?? name} {...props} />\n {label}\n </label>\n ) : (\n <Input id={id ?? name} {...props} />\n );\n};\n"],"mappings":";;;;;AASA,MAAa,mBAAmB,IAC9B;CACE;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CAGA;CACA;CACA;CAGA;CAEA;AACF,CAAC,CAAC,KAAK,GAAG,GACV;CACE,UAAU;EACR,SAAS,EACP,SAAS,GACX;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EACA,OAAO;GACL,SACE;GACF,WACE;GACF,SACE;GACF,OACE;GACF,MAAM;GACN,gBACE;GACF,MAAM;GACN,OACE;GACF,SACE;GACF,QACE;EACJ;EACA,wBAAwB;GACtB,UAAU;GACV,SAAS;EACX;CACF;CACA,iBAAiB;EACf,SAAS;EACT,OAAO;EACP,wBAAwB;EACxB,MAAM;CACR;AACF,CACF;AAgCA,MAAM,SAA4B,EAChC,yBAAyB,OACzB,OACA,MACA,OACA,MACA,SACA,WACA,gBACA,GAAG,YAEH,oBAAC,SAAD;CACE,MAAK;CACL,WAAW,GACT,iBAAiB;EACf;EACA;EACA;EACA,wBAAwB,yBAAyB,YAAY;CAC/D,CAAC,GACD,SACF;CACA,GAAI;AACL;AAGH,MAAa,YAA+B,UAAU;CACpD,MAAM,EAAE,OAAO,MAAM,OAAO;CAE5B,OAAO,QACL,qBAAC,SAAD;EACE,SAAS,MAAM;EACf,WAAW,GACT,uEACA,MAAM,SAAS,QAAQ,WACvB,MAAM,cACR;YANF,CAQE,oBAAC,OAAD;GAAO,IAAI,MAAM;GAAM,GAAI;EAAQ,IAClC,KACI;MAEP,oBAAC,OAAD;EAAO,IAAI,MAAM;EAAM,GAAI;CAAQ;AAEvC"}
@@ -13,8 +13,8 @@ const inputVariants = cva([
13
13
  variants: {
14
14
  variant: {
15
15
  default: [
16
- "text-text",
17
- "bg-neutral-50 dark:bg-neutral-950",
16
+ "text-foreground",
17
+ "bg-accent",
18
18
  "ring-text/20",
19
19
  "disabled:ring-0",
20
20
  "hover:ring-3",
@@ -1 +1 @@
1
- {"version":3,"file":"Input.mjs","names":[],"sources":["../../../../src/components/Input/Input.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport type { DetailedHTMLProps, FC, InputHTMLAttributes } from 'react';\n\n// Optional: your own cn helper to merge class names\nconst cn = (...classes: (string | undefined | false | null)[]) =>\n classes.filter(Boolean).join(' ');\n\nexport const inputVariants = cva(\n [\n // base styles\n 'w-full select-text resize-none text-base shadow-none outline-none',\n 'transition-all duration-300 md:text-sm',\n 'ring-0',\n 'disabled:opacity-50',\n\n // Corner shape\n 'rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl',\n ].join(' '),\n {\n variants: {\n variant: {\n default: [\n 'text-text',\n 'bg-neutral-50 dark:bg-neutral-950',\n 'ring-text/20',\n\n // Focus ring\n 'disabled:ring-0',\n 'hover:ring-3',\n 'focus-within:ring-4',\n 'focus-visible:outline-none focus-visible:ring-4',\n\n // Remove any weird box-shadow\n '[box-shadow:none] focus:[box-shadow:none]',\n\n // aria-invalid border color\n 'aria-invalid:border-error',\n ].join(' '),\n invisible: 'border-none text-inherit outline-none ring-0',\n },\n size: {\n sm: 'px-2 py-2 text-sm md:py-1.5 md:text-xs',\n md: 'px-2 py-3 md:py-2',\n lg: 'p-4',\n },\n validationStyleEnabled: {\n disabled: '',\n enabled: 'valid:border-success invalid:border-error',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'md',\n validationStyleEnabled: 'disabled',\n },\n }\n);\n\nexport type InputVariant = 'default' | 'invisible';\n\nexport type InputSize = 'md' | 'lg';\n\nexport type InputProps = Omit<\n DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,\n 'size'\n> & {\n validationStyleEnabled?: boolean;\n} & Omit<VariantProps<typeof inputVariants>, 'validationStyleEnabled'>;\n\nexport const Input: FC<InputProps> = ({\n validationStyleEnabled = false,\n variant,\n size,\n className,\n ...props\n}) => (\n <input\n className={cn(\n inputVariants({\n variant,\n size,\n validationStyleEnabled: validationStyleEnabled ? 'enabled' : 'disabled',\n }),\n className\n )}\n suppressHydrationWarning\n {...props}\n />\n);\n"],"mappings":";;;;AAIA,MAAM,MAAM,GAAG,YACb,QAAQ,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;AAElC,MAAa,gBAAgB,IAC3B;CAEE;CACA;CACA;CACA;CAGA;AACF,CAAC,CAAC,KAAK,GAAG,GACV;CACE,UAAU;EACR,SAAS;GACP,SAAS;IACP;IACA;IACA;IAGA;IACA;IACA;IACA;IAGA;IAGA;GACF,CAAC,CAAC,KAAK,GAAG;GACV,WAAW;EACb;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EACA,wBAAwB;GACtB,UAAU;GACV,SAAS;EACX;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;EACN,wBAAwB;CAC1B;AACF,CACF;AAaA,MAAa,SAAyB,EACpC,yBAAyB,OACzB,SACA,MACA,WACA,GAAG,YAEH,oBAAC,SAAD;CACE,WAAW,GACT,cAAc;EACZ;EACA;EACA,wBAAwB,yBAAyB,YAAY;CAC/D,CAAC,GACD,SACF;CACA;CACA,GAAI;AACL"}
1
+ {"version":3,"file":"Input.mjs","names":[],"sources":["../../../../src/components/Input/Input.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport type { DetailedHTMLProps, FC, InputHTMLAttributes } from 'react';\n\n// Optional: your own cn helper to merge class names\nconst cn = (...classes: (string | undefined | false | null)[]) =>\n classes.filter(Boolean).join(' ');\n\nexport const inputVariants = cva(\n [\n // base styles\n 'w-full select-text resize-none text-base shadow-none outline-none',\n 'transition-all duration-300 md:text-sm',\n 'ring-0',\n 'disabled:opacity-50',\n\n // Corner shape\n 'rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl',\n ].join(' '),\n {\n variants: {\n variant: {\n default: [\n 'text-foreground',\n 'bg-accent',\n 'ring-text/20',\n\n // Focus ring\n 'disabled:ring-0',\n 'hover:ring-3',\n 'focus-within:ring-4',\n 'focus-visible:outline-none focus-visible:ring-4',\n\n // Remove any weird box-shadow\n '[box-shadow:none] focus:[box-shadow:none]',\n\n // aria-invalid border color\n 'aria-invalid:border-error',\n ].join(' '),\n invisible: 'border-none text-inherit outline-none ring-0',\n },\n size: {\n sm: 'px-2 py-2 text-sm md:py-1.5 md:text-xs',\n md: 'px-2 py-3 md:py-2',\n lg: 'p-4',\n },\n validationStyleEnabled: {\n disabled: '',\n enabled: 'valid:border-success invalid:border-error',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'md',\n validationStyleEnabled: 'disabled',\n },\n }\n);\n\nexport type InputVariant = 'default' | 'invisible';\n\nexport type InputSize = 'md' | 'lg';\n\nexport type InputProps = Omit<\n DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,\n 'size'\n> & {\n validationStyleEnabled?: boolean;\n} & Omit<VariantProps<typeof inputVariants>, 'validationStyleEnabled'>;\n\nexport const Input: FC<InputProps> = ({\n validationStyleEnabled = false,\n variant,\n size,\n className,\n ...props\n}) => (\n <input\n className={cn(\n inputVariants({\n variant,\n size,\n validationStyleEnabled: validationStyleEnabled ? 'enabled' : 'disabled',\n }),\n className\n )}\n suppressHydrationWarning\n {...props}\n />\n);\n"],"mappings":";;;;AAIA,MAAM,MAAM,GAAG,YACb,QAAQ,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;AAElC,MAAa,gBAAgB,IAC3B;CAEE;CACA;CACA;CACA;CAGA;AACF,CAAC,CAAC,KAAK,GAAG,GACV;CACE,UAAU;EACR,SAAS;GACP,SAAS;IACP;IACA;IACA;IAGA;IACA;IACA;IACA;IAGA;IAGA;GACF,CAAC,CAAC,KAAK,GAAG;GACV,WAAW;EACb;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EACA,wBAAwB;GACtB,UAAU;GACV,SAAS;EACX;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;EACN,wBAAwB;CAC1B;AACF,CACF;AAaA,MAAa,SAAyB,EACpC,yBAAyB,OACzB,SACA,MACA,WACA,GAAG,YAEH,oBAAC,SAAD;CACE,WAAW,GACT,cAAc;EACZ;EACA;EACA,wBAAwB,yBAAyB,YAAY;CAC/D,CAAC,GACD,SACF;CACA;CACA,GAAI;AACL"}
@@ -480,7 +480,7 @@ const InputOTPSlot = ({ index, className, onClick, onKeyDown, ...props }) => {
480
480
  };
481
481
  const InputOTPSeparator = (props) => /* @__PURE__ */ jsx("div", {
482
482
  "aria-hidden": true,
483
- className: "z-0 table h-0.5 w-3 rounded-full text-text/50",
483
+ className: "z-0 table h-0.5 w-3 rounded-full text-foreground/50",
484
484
  ...props,
485
485
  children: /* @__PURE__ */ jsx(MinusIcon, {})
486
486
  });
@@ -1 +1 @@
1
- {"version":3,"file":"OTPInput.mjs","names":[],"sources":["../../../../src/components/Input/OTPInput.tsx"],"sourcesContent":["'use client';\n\n/**\n * This component is a fork of https://github.com/guilhermerodz/input-otp\n */\n\nimport { cn } from '@utils/cn';\nimport { cva } from 'class-variance-authority';\nimport { MinusIcon } from 'lucide-react';\nimport {\n type ChangeEvent,\n type ClipboardEvent,\n type ComponentProps,\n type CSSProperties,\n createContext,\n type FC,\n type InputHTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n type RefObject,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { Button, type ButtonProps } from '../Button';\n\n// ---------------- Utilities ----------------\n\nconst syncTimeouts = (cb: (...args: any[]) => unknown): number[] => {\n const t1 = setTimeout(cb, 0); // For faster machines\n const t2 = setTimeout(cb, 1_0);\n const t3 = setTimeout(cb, 5_0);\n return [t1, t2, t3];\n};\n\nconst safeInsertRule = (sheet: CSSStyleSheet, rule: string) => {\n try {\n sheet.insertRule(rule);\n } catch {\n console.error('input-otp could not insert CSS rule:', rule);\n }\n};\n\n// Decided to go with <noscript>\n// instead of `scripting` CSS media query\n// because it's a fallback for initial page load\n// and the <script> tag won't be loaded\n// unless the user has JS disabled.\nconst NOSCRIPT_CSS_FALLBACK = `\n[data-input-otp] {\n --nojs-bg: white !important;\n --nojs-fg: black !important;\n\n background-color: var(--nojs-bg) !important;\n color: var(--nojs-fg) !important;\n caret-color: var(--nojs-fg) !important;\n letter-spacing: .25em !important;\n text-align: center !important;\n border: 1px solid var(--nojs-fg) !important;\n border-radius: 4px !important;\n width: 100% !important;\n}\n@media (prefers-color-scheme: dark) {\n [data-input-otp] {\n --nojs-bg: black !important;\n --nojs-fg: white !important;\n }\n}`;\n\n// ---------------- Constants ----------------\n\nconst PWM_BADGE_MARGIN_RIGHT = 18;\nconst PWM_BADGE_SPACE_WIDTH_PX = 40;\nconst PWM_BADGE_SPACE_WIDTH = `${PWM_BADGE_SPACE_WIDTH_PX}px` as const;\n\nconst PASSWORD_MANAGERS_SELECTORS = [\n '[data-lastpass-icon-root]', // LastPass\n 'com-1password-button', // 1Password\n '[data-dashlanecreated]', // Dashlane\n '[style$=\"2147483647 !important;\"]', // Bitwarden\n].join(',');\n\n// ---------------- Types ----------------\n\nexport type SlotProps = {\n isActive: boolean;\n char: string | null;\n placeholderChar: string | null;\n hasFakeCaret: boolean;\n};\n\nexport type RenderProps = {\n slots: SlotProps[];\n isFocused: boolean;\n isHovering: boolean;\n setSelection: (index: number) => void;\n};\n\ntype OverrideProps<T, R> = Omit<T, keyof R> & R;\n\ntype OTPInputBaseProps = OverrideProps<\n InputHTMLAttributes<HTMLInputElement>,\n {\n value?: string;\n onChange?: (newValue: string) => unknown;\n\n maxLength: number;\n\n onComplete?: (...args: any[]) => unknown;\n onActiveSlotChange?: (activeSlotIndex: number | null) => unknown;\n pushPasswordManagerStrategy?: 'increase-width' | 'none';\n pasteTransformer?: (pasted: string) => string;\n\n containerClassName?: string;\n\n noScriptCSSFallback?: string | null;\n }\n>;\n\ntype InputOTPRenderFn = (props: RenderProps) => ReactNode;\n\nexport type OTPInputProps = OTPInputBaseProps &\n (\n | {\n render: InputOTPRenderFn;\n children?: never;\n }\n | {\n render?: never;\n children: ReactNode;\n }\n );\n\n// ---------------- Hooks ----------------\n\nexport const usePasswordManagerBadge = ({\n containerRef,\n inputRef,\n pushPasswordManagerStrategy,\n isFocused,\n}: {\n containerRef: RefObject<HTMLDivElement | null>;\n inputRef: RefObject<HTMLInputElement | null>;\n pushPasswordManagerStrategy: OTPInputProps['pushPasswordManagerStrategy'];\n isFocused: boolean;\n}) => {\n /** Password managers have a badge\n * and I'll use this state to push them\n * outside the input */\n const [hasPWMBadge, setHasPWMBadge] = useState(false);\n const [hasPWMBadgeSpace, setHasPWMBadgeSpace] = useState(false);\n const [done, setDone] = useState(false);\n\n const willPushPWMBadge =\n pushPasswordManagerStrategy === 'none'\n ? false\n : (pushPasswordManagerStrategy === 'increase-width' ||\n // TODO: remove 'experimental-no-flickering' support in 2.0.0\n pushPasswordManagerStrategy === 'experimental-no-flickering') &&\n hasPWMBadge &&\n hasPWMBadgeSpace;\n\n const trackPWMBadge = () => {\n const container = containerRef.current;\n const input = inputRef.current;\n if (\n !container ||\n !input ||\n done ||\n pushPasswordManagerStrategy === 'none'\n ) {\n return;\n }\n\n const elementToCompare = container;\n\n // Get the top right-center point of the container.\n // That is usually where most password managers place their badge.\n const rightCornerX =\n elementToCompare.getBoundingClientRect().left +\n elementToCompare.offsetWidth;\n const centereredY =\n elementToCompare.getBoundingClientRect().top +\n elementToCompare.offsetHeight / 2;\n const x = rightCornerX - PWM_BADGE_MARGIN_RIGHT;\n const y = centereredY;\n\n // Do an extra search to check for famous password managers\n const pmws = document.querySelectorAll(PASSWORD_MANAGERS_SELECTORS);\n\n // If no password manager is automatically detect,\n // we'll try to dispatch document.elementFromPoint\n // to identify badges\n if (pmws.length === 0) {\n const maybeBadgeEl = document.elementFromPoint(x, y);\n\n // If the found element is the input itself,\n // then we assume it's not a password manager badge.\n // We are not sure. Most times that means there isn't a badge.\n if (maybeBadgeEl === container) {\n return;\n }\n }\n\n setHasPWMBadge(true);\n setDone(true);\n };\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container || pushPasswordManagerStrategy === 'none') {\n return;\n }\n\n // Check if the PWM area is 100% visible\n const checkHasSpace = () => {\n const viewportWidth = window.innerWidth;\n const distanceToRightEdge =\n viewportWidth - container.getBoundingClientRect().right;\n setHasPWMBadgeSpace(distanceToRightEdge >= PWM_BADGE_SPACE_WIDTH_PX);\n };\n\n checkHasSpace();\n const interval = setInterval(checkHasSpace, 1000);\n\n return () => {\n clearInterval(interval);\n };\n }, [containerRef, pushPasswordManagerStrategy]);\n\n useEffect(() => {\n const _isFocused = isFocused || document.activeElement === inputRef.current;\n\n if (pushPasswordManagerStrategy === 'none' || !_isFocused) {\n return;\n }\n const t1 = setTimeout(trackPWMBadge, 0);\n const t2 = setTimeout(trackPWMBadge, 2000);\n const t3 = setTimeout(trackPWMBadge, 5000);\n const t4 = setTimeout(() => {\n setDone(true);\n }, 6000);\n return () => {\n clearTimeout(t1);\n clearTimeout(t2);\n clearTimeout(t3);\n clearTimeout(t4);\n };\n }, [inputRef, isFocused, pushPasswordManagerStrategy]);\n\n return { hasPWMBadge, willPushPWMBadge, PWM_BADGE_SPACE_WIDTH };\n};\n\nexport const usePrevious = <T,>(value: T): T | undefined => {\n const ref = useRef<T | undefined>(undefined);\n useEffect(() => {\n ref.current = value;\n });\n return ref.current;\n};\n\n// ---------------- Context ----------------\n\nexport const OTPInputContext = createContext<RenderProps>({} as RenderProps);\n\n// ---------------- Core Component ----------------\n\nexport const OTPInput: FC<OTPInputProps> = ({\n value: uncheckedValue,\n onChange: uncheckedOnChange,\n maxLength,\n pattern,\n placeholder,\n inputMode = 'numeric',\n onComplete,\n onActiveSlotChange,\n pushPasswordManagerStrategy = 'increase-width',\n pasteTransformer,\n containerClassName,\n noScriptCSSFallback = NOSCRIPT_CSS_FALLBACK,\n render,\n children,\n ...props\n}) => {\n // Only used when `value` state is not provided\n const [internalValue, setInternalValue] = useState(\n typeof props.defaultValue === 'string' ? props.defaultValue : ''\n );\n\n // Definitions\n const value = uncheckedValue ?? internalValue;\n const previousValue = usePrevious(value);\n const onChange = (newValue: string) => {\n uncheckedOnChange?.(newValue);\n setInternalValue(newValue);\n };\n const regexp =\n pattern !== undefined\n ? typeof pattern === 'string'\n ? new RegExp(pattern)\n : pattern\n : null;\n\n /** useRef */\n const inputRef = useRef<HTMLInputElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const initialLoadRef = useRef({\n value,\n onChange,\n isIOS:\n typeof window !== 'undefined' &&\n window?.CSS?.supports?.('-webkit-touch-callout', 'none'),\n });\n const inputMetadataRef = useRef<{\n prev: [number | null, number | null, 'none' | 'forward' | 'backward'];\n }>({\n prev: [\n inputRef.current?.selectionStart ?? null,\n inputRef.current?.selectionEnd ?? null,\n inputRef.current?.selectionDirection ?? 'none',\n ],\n });\n useEffect(() => {\n const input = inputRef.current;\n const container = containerRef.current;\n\n if (!input || !container) {\n return;\n }\n\n // Sync input value\n if (initialLoadRef.current.value !== input.value) {\n initialLoadRef.current.onChange(input.value);\n }\n\n // Previous selection\n inputMetadataRef.current.prev = [\n input.selectionStart,\n input.selectionEnd,\n input.selectionDirection ?? 'none',\n ];\n const onDocumentSelectionChange = () => {\n if (document.activeElement !== input) {\n setMirrorSelectionStart(null);\n setMirrorSelectionEnd(null);\n setActualCaretPosition(null);\n return;\n }\n\n const selectionStart = input.selectionStart;\n const selectionEnd = input.selectionEnd;\n const selectionDirection = input.selectionDirection;\n const maxLength = input.maxLength;\n const value = input.value;\n const previousSelection = inputMetadataRef.current.prev;\n\n let calculatedStart = -1;\n let calculatedEnd = -1;\n let calculatedDirection: 'forward' | 'backward' | 'none' =\n selectionDirection ?? 'none';\n\n if (\n value.length !== 0 &&\n selectionStart !== null &&\n selectionEnd !== null\n ) {\n const isSingleCaret = selectionStart === selectionEnd;\n const isInsertMode =\n selectionStart === value.length && value.length < maxLength;\n\n if (isSingleCaret && !isInsertMode) {\n const caretPosition = selectionStart;\n if (caretPosition === 0) {\n calculatedStart = 0;\n calculatedEnd = 1;\n calculatedDirection = 'forward';\n } else if (caretPosition === maxLength) {\n calculatedStart = caretPosition - 1;\n calculatedEnd = caretPosition;\n calculatedDirection = 'backward';\n } else if (maxLength > 1 && value.length > 1) {\n let offset = 0;\n if (\n previousSelection[0] !== null &&\n previousSelection[1] !== null\n ) {\n calculatedDirection =\n caretPosition < previousSelection[1] ? 'backward' : 'forward';\n const wasPreviouslyInserting =\n previousSelection[0] === previousSelection[1] &&\n previousSelection[0] < maxLength;\n if (\n calculatedDirection === 'backward' &&\n !wasPreviouslyInserting\n ) {\n offset = -1;\n }\n }\n\n calculatedStart = offset + caretPosition;\n calculatedEnd = offset + caretPosition + 1;\n }\n }\n\n if (\n calculatedStart !== -1 &&\n calculatedEnd !== -1 &&\n calculatedStart !== calculatedEnd\n ) {\n inputRef.current?.setSelectionRange(\n calculatedStart,\n calculatedEnd,\n calculatedDirection\n );\n }\n }\n\n const finalSelectionStart =\n calculatedStart !== -1 ? calculatedStart : selectionStart;\n const finalSelectionEnd =\n calculatedEnd !== -1 ? calculatedEnd : selectionEnd;\n const finalDirection = calculatedDirection;\n\n // Track actual caret position (before expansion) for active slot detection\n if (selectionStart !== null && selectionEnd !== null) {\n const isSingleCaret = selectionStart === selectionEnd;\n if (isSingleCaret) {\n setActualCaretPosition(selectionStart);\n } else {\n // When selection is expanded, use the start position as the caret\n setActualCaretPosition(finalSelectionStart);\n }\n } else {\n setActualCaretPosition(null);\n }\n\n setMirrorSelectionStart(finalSelectionStart);\n setMirrorSelectionEnd(finalSelectionEnd);\n inputMetadataRef.current.prev = [\n finalSelectionStart,\n finalSelectionEnd,\n finalDirection,\n ];\n };\n document.addEventListener('selectionchange', onDocumentSelectionChange, {\n capture: true,\n });\n\n // Set initial mirror state\n onDocumentSelectionChange();\n if (document.activeElement === input) {\n setIsFocused(true);\n }\n\n // Apply needed styles\n if (!document.getElementById('input-otp-style')) {\n const styleEl = document.createElement('style');\n styleEl.id = 'input-otp-style';\n document.head.appendChild(styleEl);\n\n if (styleEl.sheet) {\n const autofillStyles =\n 'background: transparent !important; color: transparent !important; border-color: transparent !important; opacity: 0 !important; box-shadow: none !important; -webkit-box-shadow: none !important; -webkit-text-fill-color: transparent !important;';\n\n safeInsertRule(\n styleEl.sheet,\n '[data-input-otp]::selection { background: transparent !important; color: transparent !important; }'\n );\n safeInsertRule(\n styleEl.sheet,\n `[data-input-otp]:autofill { ${autofillStyles} }`\n );\n safeInsertRule(\n styleEl.sheet,\n `[data-input-otp]:-webkit-autofill { ${autofillStyles} }`\n );\n // iOS\n safeInsertRule(\n styleEl.sheet,\n `@supports (-webkit-touch-callout: none) { [data-input-otp] { letter-spacing: -.6em !important; font-weight: 100 !important; font-stretch: ultra-condensed; font-optical-sizing: none !important; left: -1px !important; right: 1px !important; } }`\n );\n // PWM badges\n safeInsertRule(\n styleEl.sheet,\n `[data-input-otp] + * { pointer-events: all !important; }`\n );\n }\n }\n // Track root height\n const updateRootHeight = () => {\n if (container) {\n container.style.setProperty('--root-height', `${input.clientHeight}px`);\n }\n };\n updateRootHeight();\n const resizeObserver = new ResizeObserver(updateRootHeight);\n resizeObserver.observe(input);\n\n return () => {\n document.removeEventListener(\n 'selectionchange',\n onDocumentSelectionChange,\n { capture: true }\n );\n resizeObserver.disconnect();\n };\n }, []);\n\n /** Mirrors for UI rendering purpose only */\n const [isHoveringInput, setIsHoveringInput] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n const [mirrorSelectionStart, setMirrorSelectionStart] = useState<\n number | null\n >(null);\n const [mirrorSelectionEnd, setMirrorSelectionEnd] = useState<number | null>(\n null\n );\n const [actualCaretPosition, setActualCaretPosition] = useState<number | null>(\n null\n );\n\n /** Effects */\n useEffect(() => {\n syncTimeouts(() => {\n // Forcefully remove :autofill state\n inputRef.current?.dispatchEvent(new Event('input'));\n\n // Update the selection state\n const s = inputRef.current?.selectionStart ?? null;\n const e = inputRef.current?.selectionEnd ?? null;\n const dir = inputRef.current?.selectionDirection ?? 'none';\n if (s !== null && e !== null) {\n setMirrorSelectionStart(s);\n setMirrorSelectionEnd(e);\n // Track actual caret position (use start position as caret)\n setActualCaretPosition(s);\n inputMetadataRef.current.prev = [s, e, dir];\n }\n });\n }, [value, isFocused]);\n\n useEffect(() => {\n if (previousValue === undefined) {\n return;\n }\n\n if (\n value !== previousValue &&\n previousValue.length < maxLength &&\n value.length === maxLength\n ) {\n onComplete?.(value);\n }\n }, [maxLength, onComplete, previousValue, value]);\n\n // Track active slot changes\n const previousActiveSlot = useRef<number | null>(null);\n useEffect(() => {\n const activeSlotIndex =\n isFocused && actualCaretPosition !== null ? actualCaretPosition : null;\n\n if (activeSlotIndex !== previousActiveSlot.current) {\n previousActiveSlot.current = activeSlotIndex;\n onActiveSlotChange?.(activeSlotIndex);\n }\n }, [isFocused, actualCaretPosition, onActiveSlotChange]);\n\n const pwmb = usePasswordManagerBadge({\n containerRef,\n inputRef,\n pushPasswordManagerStrategy,\n isFocused,\n });\n\n /** Event handlers */\n const _changeListener = (e: ChangeEvent<HTMLInputElement>) => {\n const newValue = e.currentTarget.value.slice(0, maxLength);\n if (newValue.length > 0 && regexp && !regexp.test(newValue)) {\n e.preventDefault();\n return;\n }\n const maybeHasDeleted =\n typeof previousValue === 'string' &&\n newValue.length < previousValue.length;\n if (maybeHasDeleted) {\n // Since cutting/deleting text doesn't trigger\n // selectionchange event, we'll have to dispatch it manually.\n // NOTE: The following line also triggers when cmd+A then pasting\n // a value with smaller length, which is not ideal for performance.\n document.dispatchEvent(new Event('selectionchange'));\n }\n onChange(newValue);\n };\n const _focusListener = () => {\n if (inputRef.current) {\n const start = Math.min(inputRef.current.value.length, maxLength - 1);\n const end = inputRef.current.value.length;\n inputRef.current?.setSelectionRange(start, end);\n setMirrorSelectionStart(start);\n setMirrorSelectionEnd(end);\n }\n setIsFocused(true);\n };\n // Fix iOS pasting\n const _pasteListener = (e: ClipboardEvent<HTMLInputElement>) => {\n const input = inputRef.current;\n if (\n !pasteTransformer &&\n (!initialLoadRef.current.isIOS || !e.clipboardData || !input)\n ) {\n return;\n }\n\n const _content = e.clipboardData.getData('text/plain');\n const content = pasteTransformer ? pasteTransformer(_content) : _content;\n e.preventDefault();\n\n const start = inputRef.current?.selectionStart;\n const end = inputRef.current?.selectionEnd;\n\n const isReplacing = start !== end;\n\n const newValueUncapped = isReplacing\n ? value.slice(0, start ?? 0) + content + value.slice(end ?? 0) // Replacing\n : value.slice(0, start ?? 0) + content + value.slice(start ?? 0); // Inserting\n const newValue = newValueUncapped.slice(0, maxLength);\n\n if (newValue.length > 0 && regexp && !regexp.test(newValue)) {\n return;\n }\n\n if (input) {\n input.value = newValue;\n onChange(newValue);\n\n const _start = Math.min(newValue.length, maxLength - 1);\n const _end = newValue.length;\n\n input.setSelectionRange(_start, _end);\n setMirrorSelectionStart(_start);\n setMirrorSelectionEnd(_end);\n }\n };\n\n /** Styles - dynamic styles that can't be converted to Tailwind */\n const dynamicInputStyle: CSSProperties = {\n width: pwmb.willPushPWMBadge\n ? `calc(100% + ${pwmb.PWM_BADGE_SPACE_WIDTH})`\n : '100%',\n clipPath: pwmb.willPushPWMBadge\n ? `inset(0 ${pwmb.PWM_BADGE_SPACE_WIDTH} 0 0)`\n : undefined,\n fontSize: 'var(--root-height)',\n };\n\n /** Rendering */\n const renderedInput = (\n <input\n autoComplete={props.autoComplete || 'one-time-code'}\n {...props}\n data-input-otp\n data-input-otp-placeholder-shown={value.length === 0 || undefined}\n data-input-otp-mss={mirrorSelectionStart}\n data-input-otp-mse={mirrorSelectionEnd}\n inputMode={inputMode}\n pattern={regexp?.source}\n aria-placeholder={placeholder}\n className=\"pointer-events-auto absolute inset-0 -z-10 flex h-full border-0 border-transparent bg-transparent text-center font-mono text-transparent tabular-nums leading-none tracking-[-.5em] caret-transparent opacity-100 shadow-none outline-none\"\n style={dynamicInputStyle}\n maxLength={maxLength}\n value={value}\n ref={inputRef}\n onPaste={(e) => {\n _pasteListener(e);\n props.onPaste?.(e);\n }}\n onChange={_changeListener}\n onMouseOver={(e) => {\n setIsHoveringInput(true);\n props.onMouseOver?.(e);\n }}\n onMouseLeave={(e) => {\n setIsHoveringInput(false);\n props.onMouseLeave?.(e);\n }}\n onKeyDown={(e) => {\n // Track arrow key navigation to ensure active slot updates correctly\n if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n // Use requestAnimationFrame to check selection after browser has processed the key\n requestAnimationFrame(() => {\n const input = inputRef.current;\n if (input && document.activeElement === input) {\n const s = input.selectionStart;\n const end = input.selectionEnd;\n if (s !== null && end !== null) {\n // Update actual caret position - use start position as caret\n setActualCaretPosition(s);\n }\n }\n });\n }\n props.onKeyDown?.(e);\n }}\n onFocus={(e) => {\n _focusListener();\n props.onFocus?.(e);\n }}\n onBlur={(e) => {\n setIsFocused(false);\n props.onBlur?.(e);\n }}\n />\n );\n\n const setSelection = (index: number) => {\n const input = inputRef.current;\n if (!input || props.disabled) {\n return;\n }\n\n // Clamp index to valid range\n const clampedIndex = Math.max(0, Math.min(index, maxLength - 1));\n\n // Focus the input if not already focused\n if (document.activeElement !== input) {\n input.focus();\n }\n\n // Set selection to the clicked slot\n // If there's a character at that position, select it; otherwise just position the caret\n const hasChar = value[clampedIndex] !== undefined;\n const start = clampedIndex;\n const end = hasChar ? clampedIndex + 1 : clampedIndex;\n\n input.setSelectionRange(start, end);\n setMirrorSelectionStart(start);\n setMirrorSelectionEnd(end);\n setIsFocused(true);\n };\n\n const contextValue: RenderProps = {\n slots: Array.from({ length: maxLength }).map((_, slotIdx) => {\n const isActive =\n isFocused &&\n mirrorSelectionStart !== null &&\n mirrorSelectionEnd !== null &&\n ((mirrorSelectionStart === mirrorSelectionEnd &&\n slotIdx === mirrorSelectionStart) ||\n (slotIdx >= mirrorSelectionStart && slotIdx < mirrorSelectionEnd));\n\n const char = value[slotIdx] !== undefined ? value[slotIdx] : null;\n const placeholderChar =\n value[0] !== undefined ? null : (placeholder?.[slotIdx] ?? null);\n\n return {\n char,\n placeholderChar,\n isActive,\n hasFakeCaret: isActive && char === null,\n };\n }),\n isFocused,\n isHovering: !props.disabled && isHoveringInput,\n setSelection,\n };\n\n const renderedChildren =\n render !== undefined ? (\n render(contextValue)\n ) : (\n <OTPInputContext.Provider value={contextValue}>\n {children}\n </OTPInputContext.Provider>\n );\n\n return (\n <>\n {noScriptCSSFallback !== null && (\n <noscript>\n <style>{noScriptCSSFallback}</style>\n </noscript>\n )}\n\n <div\n ref={containerRef}\n className={cn(\n 'relative',\n props.disabled ? 'cursor-default' : 'cursor-text',\n containerClassName\n )}\n >\n {renderedChildren}\n\n <div className=\"absolute inset-0\">{renderedInput}</div>\n </div>\n </>\n );\n};\n\n// ---------------- Root ----------------\n\ntype InputOTPProps = Omit<ComponentProps<typeof OTPInput>, 'children'>;\n\nexport const inputSlotVariants = cva('block text-center', {\n variants: {\n size: {\n sm: 'h-4 w-3 text-sm',\n md: 'h-5 w-4 text-base',\n lg: 'h-6 w-5 text-lg',\n xl: 'h-7 w-6 text-xl',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\nexport const InputOTP: FC<InputOTPProps> = ({\n className,\n render,\n ...props\n}) => (\n <OTPInput\n containerClassName=\"relative flex items-center gap-2 has-disabled:opacity-50\"\n className={cn('disabled:cursor-not-allowed', className)}\n render={render!}\n {...props}\n />\n);\n\n// ---------------- Group ----------------\n\nexport const InputOTPGroup = ({\n className,\n ...props\n}: ComponentProps<'div'>) => (\n <div className={cn('z-10 flex items-center gap-3', className)} {...props} />\n);\n\n// ---------------- Slot ----------------\n\ntype InputOTPSlotProps = Omit<ButtonProps, 'variant' | 'label'> & {\n index: number;\n};\n\nexport const InputOTPSlot: FC<InputOTPSlotProps> = ({\n index,\n className,\n onClick,\n onKeyDown,\n ...props\n}) => {\n const inputOTPContext = useContext(OTPInputContext);\n const { char, isActive } = inputOTPContext?.slots[index] ?? {};\n const { setSelection } = inputOTPContext ?? {};\n\n const handleClick = (e: MouseEvent<HTMLButtonElement>) => {\n setSelection?.(index);\n onClick?.(e);\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setSelection?.(index);\n }\n onKeyDown?.(e);\n };\n\n return (\n <Button\n isSelected={isActive}\n variant=\"input\"\n color=\"custom\"\n tabIndex={-1}\n className={cn('relative z-10 px-2!', isActive && 'ring-4!', className)}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n label={null}\n {...props}\n >\n {/* value */}\n <span className=\"relative z-10 flex h-6 w-4 items-center justify-center\">\n {char}\n </span>\n </Button>\n );\n};\n\n// ---------------- Separator ----------------\n\nexport const InputOTPSeparator: FC<ComponentProps<'div'>> = (props) => (\n <div\n aria-hidden\n className=\"z-0 table h-0.5 w-3 rounded-full text-text/50\"\n {...props}\n >\n <MinusIcon />\n </div>\n);\n\nexport const InputIndicator: FC<ComponentProps<'div'>> = (props) => (\n <div\n data-indicator\n className=\"absolute top-0 z-0 h-full w-auto rounded-xl bg-text/20 ring-4 ring-text/20 transition-[left,width] duration-300 ease-in-out [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl motion-reduce:transition-none\"\n {...props}\n />\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"OTPInput.mjs","names":[],"sources":["../../../../src/components/Input/OTPInput.tsx"],"sourcesContent":["'use client';\n\n/**\n * This component is a fork of https://github.com/guilhermerodz/input-otp\n */\n\nimport { cn } from '@utils/cn';\nimport { cva } from 'class-variance-authority';\nimport { MinusIcon } from 'lucide-react';\nimport {\n type ChangeEvent,\n type ClipboardEvent,\n type ComponentProps,\n type CSSProperties,\n createContext,\n type FC,\n type InputHTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n type RefObject,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { Button, type ButtonProps } from '../Button';\n\n// ---------------- Utilities ----------------\n\nconst syncTimeouts = (cb: (...args: any[]) => unknown): number[] => {\n const t1 = setTimeout(cb, 0); // For faster machines\n const t2 = setTimeout(cb, 1_0);\n const t3 = setTimeout(cb, 5_0);\n return [t1, t2, t3];\n};\n\nconst safeInsertRule = (sheet: CSSStyleSheet, rule: string) => {\n try {\n sheet.insertRule(rule);\n } catch {\n console.error('input-otp could not insert CSS rule:', rule);\n }\n};\n\n// Decided to go with <noscript>\n// instead of `scripting` CSS media query\n// because it's a fallback for initial page load\n// and the <script> tag won't be loaded\n// unless the user has JS disabled.\nconst NOSCRIPT_CSS_FALLBACK = `\n[data-input-otp] {\n --nojs-bg: white !important;\n --nojs-fg: black !important;\n\n background-color: var(--nojs-bg) !important;\n color: var(--nojs-fg) !important;\n caret-color: var(--nojs-fg) !important;\n letter-spacing: .25em !important;\n text-align: center !important;\n border: 1px solid var(--nojs-fg) !important;\n border-radius: 4px !important;\n width: 100% !important;\n}\n@media (prefers-color-scheme: dark) {\n [data-input-otp] {\n --nojs-bg: black !important;\n --nojs-fg: white !important;\n }\n}`;\n\n// ---------------- Constants ----------------\n\nconst PWM_BADGE_MARGIN_RIGHT = 18;\nconst PWM_BADGE_SPACE_WIDTH_PX = 40;\nconst PWM_BADGE_SPACE_WIDTH = `${PWM_BADGE_SPACE_WIDTH_PX}px` as const;\n\nconst PASSWORD_MANAGERS_SELECTORS = [\n '[data-lastpass-icon-root]', // LastPass\n 'com-1password-button', // 1Password\n '[data-dashlanecreated]', // Dashlane\n '[style$=\"2147483647 !important;\"]', // Bitwarden\n].join(',');\n\n// ---------------- Types ----------------\n\nexport type SlotProps = {\n isActive: boolean;\n char: string | null;\n placeholderChar: string | null;\n hasFakeCaret: boolean;\n};\n\nexport type RenderProps = {\n slots: SlotProps[];\n isFocused: boolean;\n isHovering: boolean;\n setSelection: (index: number) => void;\n};\n\ntype OverrideProps<T, R> = Omit<T, keyof R> & R;\n\ntype OTPInputBaseProps = OverrideProps<\n InputHTMLAttributes<HTMLInputElement>,\n {\n value?: string;\n onChange?: (newValue: string) => unknown;\n\n maxLength: number;\n\n onComplete?: (...args: any[]) => unknown;\n onActiveSlotChange?: (activeSlotIndex: number | null) => unknown;\n pushPasswordManagerStrategy?: 'increase-width' | 'none';\n pasteTransformer?: (pasted: string) => string;\n\n containerClassName?: string;\n\n noScriptCSSFallback?: string | null;\n }\n>;\n\ntype InputOTPRenderFn = (props: RenderProps) => ReactNode;\n\nexport type OTPInputProps = OTPInputBaseProps &\n (\n | {\n render: InputOTPRenderFn;\n children?: never;\n }\n | {\n render?: never;\n children: ReactNode;\n }\n );\n\n// ---------------- Hooks ----------------\n\nexport const usePasswordManagerBadge = ({\n containerRef,\n inputRef,\n pushPasswordManagerStrategy,\n isFocused,\n}: {\n containerRef: RefObject<HTMLDivElement | null>;\n inputRef: RefObject<HTMLInputElement | null>;\n pushPasswordManagerStrategy: OTPInputProps['pushPasswordManagerStrategy'];\n isFocused: boolean;\n}) => {\n /** Password managers have a badge\n * and I'll use this state to push them\n * outside the input */\n const [hasPWMBadge, setHasPWMBadge] = useState(false);\n const [hasPWMBadgeSpace, setHasPWMBadgeSpace] = useState(false);\n const [done, setDone] = useState(false);\n\n const willPushPWMBadge =\n pushPasswordManagerStrategy === 'none'\n ? false\n : (pushPasswordManagerStrategy === 'increase-width' ||\n // TODO: remove 'experimental-no-flickering' support in 2.0.0\n pushPasswordManagerStrategy === 'experimental-no-flickering') &&\n hasPWMBadge &&\n hasPWMBadgeSpace;\n\n const trackPWMBadge = () => {\n const container = containerRef.current;\n const input = inputRef.current;\n if (\n !container ||\n !input ||\n done ||\n pushPasswordManagerStrategy === 'none'\n ) {\n return;\n }\n\n const elementToCompare = container;\n\n // Get the top right-center point of the container.\n // That is usually where most password managers place their badge.\n const rightCornerX =\n elementToCompare.getBoundingClientRect().left +\n elementToCompare.offsetWidth;\n const centereredY =\n elementToCompare.getBoundingClientRect().top +\n elementToCompare.offsetHeight / 2;\n const x = rightCornerX - PWM_BADGE_MARGIN_RIGHT;\n const y = centereredY;\n\n // Do an extra search to check for famous password managers\n const pmws = document.querySelectorAll(PASSWORD_MANAGERS_SELECTORS);\n\n // If no password manager is automatically detect,\n // we'll try to dispatch document.elementFromPoint\n // to identify badges\n if (pmws.length === 0) {\n const maybeBadgeEl = document.elementFromPoint(x, y);\n\n // If the found element is the input itself,\n // then we assume it's not a password manager badge.\n // We are not sure. Most times that means there isn't a badge.\n if (maybeBadgeEl === container) {\n return;\n }\n }\n\n setHasPWMBadge(true);\n setDone(true);\n };\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container || pushPasswordManagerStrategy === 'none') {\n return;\n }\n\n // Check if the PWM area is 100% visible\n const checkHasSpace = () => {\n const viewportWidth = window.innerWidth;\n const distanceToRightEdge =\n viewportWidth - container.getBoundingClientRect().right;\n setHasPWMBadgeSpace(distanceToRightEdge >= PWM_BADGE_SPACE_WIDTH_PX);\n };\n\n checkHasSpace();\n const interval = setInterval(checkHasSpace, 1000);\n\n return () => {\n clearInterval(interval);\n };\n }, [containerRef, pushPasswordManagerStrategy]);\n\n useEffect(() => {\n const _isFocused = isFocused || document.activeElement === inputRef.current;\n\n if (pushPasswordManagerStrategy === 'none' || !_isFocused) {\n return;\n }\n const t1 = setTimeout(trackPWMBadge, 0);\n const t2 = setTimeout(trackPWMBadge, 2000);\n const t3 = setTimeout(trackPWMBadge, 5000);\n const t4 = setTimeout(() => {\n setDone(true);\n }, 6000);\n return () => {\n clearTimeout(t1);\n clearTimeout(t2);\n clearTimeout(t3);\n clearTimeout(t4);\n };\n }, [inputRef, isFocused, pushPasswordManagerStrategy]);\n\n return { hasPWMBadge, willPushPWMBadge, PWM_BADGE_SPACE_WIDTH };\n};\n\nexport const usePrevious = <T,>(value: T): T | undefined => {\n const ref = useRef<T | undefined>(undefined);\n useEffect(() => {\n ref.current = value;\n });\n return ref.current;\n};\n\n// ---------------- Context ----------------\n\nexport const OTPInputContext = createContext<RenderProps>({} as RenderProps);\n\n// ---------------- Core Component ----------------\n\nexport const OTPInput: FC<OTPInputProps> = ({\n value: uncheckedValue,\n onChange: uncheckedOnChange,\n maxLength,\n pattern,\n placeholder,\n inputMode = 'numeric',\n onComplete,\n onActiveSlotChange,\n pushPasswordManagerStrategy = 'increase-width',\n pasteTransformer,\n containerClassName,\n noScriptCSSFallback = NOSCRIPT_CSS_FALLBACK,\n render,\n children,\n ...props\n}) => {\n // Only used when `value` state is not provided\n const [internalValue, setInternalValue] = useState(\n typeof props.defaultValue === 'string' ? props.defaultValue : ''\n );\n\n // Definitions\n const value = uncheckedValue ?? internalValue;\n const previousValue = usePrevious(value);\n const onChange = (newValue: string) => {\n uncheckedOnChange?.(newValue);\n setInternalValue(newValue);\n };\n const regexp =\n pattern !== undefined\n ? typeof pattern === 'string'\n ? new RegExp(pattern)\n : pattern\n : null;\n\n /** useRef */\n const inputRef = useRef<HTMLInputElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const initialLoadRef = useRef({\n value,\n onChange,\n isIOS:\n typeof window !== 'undefined' &&\n window?.CSS?.supports?.('-webkit-touch-callout', 'none'),\n });\n const inputMetadataRef = useRef<{\n prev: [number | null, number | null, 'none' | 'forward' | 'backward'];\n }>({\n prev: [\n inputRef.current?.selectionStart ?? null,\n inputRef.current?.selectionEnd ?? null,\n inputRef.current?.selectionDirection ?? 'none',\n ],\n });\n useEffect(() => {\n const input = inputRef.current;\n const container = containerRef.current;\n\n if (!input || !container) {\n return;\n }\n\n // Sync input value\n if (initialLoadRef.current.value !== input.value) {\n initialLoadRef.current.onChange(input.value);\n }\n\n // Previous selection\n inputMetadataRef.current.prev = [\n input.selectionStart,\n input.selectionEnd,\n input.selectionDirection ?? 'none',\n ];\n const onDocumentSelectionChange = () => {\n if (document.activeElement !== input) {\n setMirrorSelectionStart(null);\n setMirrorSelectionEnd(null);\n setActualCaretPosition(null);\n return;\n }\n\n const selectionStart = input.selectionStart;\n const selectionEnd = input.selectionEnd;\n const selectionDirection = input.selectionDirection;\n const maxLength = input.maxLength;\n const value = input.value;\n const previousSelection = inputMetadataRef.current.prev;\n\n let calculatedStart = -1;\n let calculatedEnd = -1;\n let calculatedDirection: 'forward' | 'backward' | 'none' =\n selectionDirection ?? 'none';\n\n if (\n value.length !== 0 &&\n selectionStart !== null &&\n selectionEnd !== null\n ) {\n const isSingleCaret = selectionStart === selectionEnd;\n const isInsertMode =\n selectionStart === value.length && value.length < maxLength;\n\n if (isSingleCaret && !isInsertMode) {\n const caretPosition = selectionStart;\n if (caretPosition === 0) {\n calculatedStart = 0;\n calculatedEnd = 1;\n calculatedDirection = 'forward';\n } else if (caretPosition === maxLength) {\n calculatedStart = caretPosition - 1;\n calculatedEnd = caretPosition;\n calculatedDirection = 'backward';\n } else if (maxLength > 1 && value.length > 1) {\n let offset = 0;\n if (\n previousSelection[0] !== null &&\n previousSelection[1] !== null\n ) {\n calculatedDirection =\n caretPosition < previousSelection[1] ? 'backward' : 'forward';\n const wasPreviouslyInserting =\n previousSelection[0] === previousSelection[1] &&\n previousSelection[0] < maxLength;\n if (\n calculatedDirection === 'backward' &&\n !wasPreviouslyInserting\n ) {\n offset = -1;\n }\n }\n\n calculatedStart = offset + caretPosition;\n calculatedEnd = offset + caretPosition + 1;\n }\n }\n\n if (\n calculatedStart !== -1 &&\n calculatedEnd !== -1 &&\n calculatedStart !== calculatedEnd\n ) {\n inputRef.current?.setSelectionRange(\n calculatedStart,\n calculatedEnd,\n calculatedDirection\n );\n }\n }\n\n const finalSelectionStart =\n calculatedStart !== -1 ? calculatedStart : selectionStart;\n const finalSelectionEnd =\n calculatedEnd !== -1 ? calculatedEnd : selectionEnd;\n const finalDirection = calculatedDirection;\n\n // Track actual caret position (before expansion) for active slot detection\n if (selectionStart !== null && selectionEnd !== null) {\n const isSingleCaret = selectionStart === selectionEnd;\n if (isSingleCaret) {\n setActualCaretPosition(selectionStart);\n } else {\n // When selection is expanded, use the start position as the caret\n setActualCaretPosition(finalSelectionStart);\n }\n } else {\n setActualCaretPosition(null);\n }\n\n setMirrorSelectionStart(finalSelectionStart);\n setMirrorSelectionEnd(finalSelectionEnd);\n inputMetadataRef.current.prev = [\n finalSelectionStart,\n finalSelectionEnd,\n finalDirection,\n ];\n };\n document.addEventListener('selectionchange', onDocumentSelectionChange, {\n capture: true,\n });\n\n // Set initial mirror state\n onDocumentSelectionChange();\n if (document.activeElement === input) {\n setIsFocused(true);\n }\n\n // Apply needed styles\n if (!document.getElementById('input-otp-style')) {\n const styleEl = document.createElement('style');\n styleEl.id = 'input-otp-style';\n document.head.appendChild(styleEl);\n\n if (styleEl.sheet) {\n const autofillStyles =\n 'background: transparent !important; color: transparent !important; border-color: transparent !important; opacity: 0 !important; box-shadow: none !important; -webkit-box-shadow: none !important; -webkit-text-fill-color: transparent !important;';\n\n safeInsertRule(\n styleEl.sheet,\n '[data-input-otp]::selection { background: transparent !important; color: transparent !important; }'\n );\n safeInsertRule(\n styleEl.sheet,\n `[data-input-otp]:autofill { ${autofillStyles} }`\n );\n safeInsertRule(\n styleEl.sheet,\n `[data-input-otp]:-webkit-autofill { ${autofillStyles} }`\n );\n // iOS\n safeInsertRule(\n styleEl.sheet,\n `@supports (-webkit-touch-callout: none) { [data-input-otp] { letter-spacing: -.6em !important; font-weight: 100 !important; font-stretch: ultra-condensed; font-optical-sizing: none !important; left: -1px !important; right: 1px !important; } }`\n );\n // PWM badges\n safeInsertRule(\n styleEl.sheet,\n `[data-input-otp] + * { pointer-events: all !important; }`\n );\n }\n }\n // Track root height\n const updateRootHeight = () => {\n if (container) {\n container.style.setProperty('--root-height', `${input.clientHeight}px`);\n }\n };\n updateRootHeight();\n const resizeObserver = new ResizeObserver(updateRootHeight);\n resizeObserver.observe(input);\n\n return () => {\n document.removeEventListener(\n 'selectionchange',\n onDocumentSelectionChange,\n { capture: true }\n );\n resizeObserver.disconnect();\n };\n }, []);\n\n /** Mirrors for UI rendering purpose only */\n const [isHoveringInput, setIsHoveringInput] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n const [mirrorSelectionStart, setMirrorSelectionStart] = useState<\n number | null\n >(null);\n const [mirrorSelectionEnd, setMirrorSelectionEnd] = useState<number | null>(\n null\n );\n const [actualCaretPosition, setActualCaretPosition] = useState<number | null>(\n null\n );\n\n /** Effects */\n useEffect(() => {\n syncTimeouts(() => {\n // Forcefully remove :autofill state\n inputRef.current?.dispatchEvent(new Event('input'));\n\n // Update the selection state\n const s = inputRef.current?.selectionStart ?? null;\n const e = inputRef.current?.selectionEnd ?? null;\n const dir = inputRef.current?.selectionDirection ?? 'none';\n if (s !== null && e !== null) {\n setMirrorSelectionStart(s);\n setMirrorSelectionEnd(e);\n // Track actual caret position (use start position as caret)\n setActualCaretPosition(s);\n inputMetadataRef.current.prev = [s, e, dir];\n }\n });\n }, [value, isFocused]);\n\n useEffect(() => {\n if (previousValue === undefined) {\n return;\n }\n\n if (\n value !== previousValue &&\n previousValue.length < maxLength &&\n value.length === maxLength\n ) {\n onComplete?.(value);\n }\n }, [maxLength, onComplete, previousValue, value]);\n\n // Track active slot changes\n const previousActiveSlot = useRef<number | null>(null);\n useEffect(() => {\n const activeSlotIndex =\n isFocused && actualCaretPosition !== null ? actualCaretPosition : null;\n\n if (activeSlotIndex !== previousActiveSlot.current) {\n previousActiveSlot.current = activeSlotIndex;\n onActiveSlotChange?.(activeSlotIndex);\n }\n }, [isFocused, actualCaretPosition, onActiveSlotChange]);\n\n const pwmb = usePasswordManagerBadge({\n containerRef,\n inputRef,\n pushPasswordManagerStrategy,\n isFocused,\n });\n\n /** Event handlers */\n const _changeListener = (e: ChangeEvent<HTMLInputElement>) => {\n const newValue = e.currentTarget.value.slice(0, maxLength);\n if (newValue.length > 0 && regexp && !regexp.test(newValue)) {\n e.preventDefault();\n return;\n }\n const maybeHasDeleted =\n typeof previousValue === 'string' &&\n newValue.length < previousValue.length;\n if (maybeHasDeleted) {\n // Since cutting/deleting text doesn't trigger\n // selectionchange event, we'll have to dispatch it manually.\n // NOTE: The following line also triggers when cmd+A then pasting\n // a value with smaller length, which is not ideal for performance.\n document.dispatchEvent(new Event('selectionchange'));\n }\n onChange(newValue);\n };\n const _focusListener = () => {\n if (inputRef.current) {\n const start = Math.min(inputRef.current.value.length, maxLength - 1);\n const end = inputRef.current.value.length;\n inputRef.current?.setSelectionRange(start, end);\n setMirrorSelectionStart(start);\n setMirrorSelectionEnd(end);\n }\n setIsFocused(true);\n };\n // Fix iOS pasting\n const _pasteListener = (e: ClipboardEvent<HTMLInputElement>) => {\n const input = inputRef.current;\n if (\n !pasteTransformer &&\n (!initialLoadRef.current.isIOS || !e.clipboardData || !input)\n ) {\n return;\n }\n\n const _content = e.clipboardData.getData('text/plain');\n const content = pasteTransformer ? pasteTransformer(_content) : _content;\n e.preventDefault();\n\n const start = inputRef.current?.selectionStart;\n const end = inputRef.current?.selectionEnd;\n\n const isReplacing = start !== end;\n\n const newValueUncapped = isReplacing\n ? value.slice(0, start ?? 0) + content + value.slice(end ?? 0) // Replacing\n : value.slice(0, start ?? 0) + content + value.slice(start ?? 0); // Inserting\n const newValue = newValueUncapped.slice(0, maxLength);\n\n if (newValue.length > 0 && regexp && !regexp.test(newValue)) {\n return;\n }\n\n if (input) {\n input.value = newValue;\n onChange(newValue);\n\n const _start = Math.min(newValue.length, maxLength - 1);\n const _end = newValue.length;\n\n input.setSelectionRange(_start, _end);\n setMirrorSelectionStart(_start);\n setMirrorSelectionEnd(_end);\n }\n };\n\n /** Styles - dynamic styles that can't be converted to Tailwind */\n const dynamicInputStyle: CSSProperties = {\n width: pwmb.willPushPWMBadge\n ? `calc(100% + ${pwmb.PWM_BADGE_SPACE_WIDTH})`\n : '100%',\n clipPath: pwmb.willPushPWMBadge\n ? `inset(0 ${pwmb.PWM_BADGE_SPACE_WIDTH} 0 0)`\n : undefined,\n fontSize: 'var(--root-height)',\n };\n\n /** Rendering */\n const renderedInput = (\n <input\n autoComplete={props.autoComplete || 'one-time-code'}\n {...props}\n data-input-otp\n data-input-otp-placeholder-shown={value.length === 0 || undefined}\n data-input-otp-mss={mirrorSelectionStart}\n data-input-otp-mse={mirrorSelectionEnd}\n inputMode={inputMode}\n pattern={regexp?.source}\n aria-placeholder={placeholder}\n className=\"pointer-events-auto absolute inset-0 -z-10 flex h-full border-0 border-transparent bg-transparent text-center font-mono text-transparent tabular-nums leading-none tracking-[-.5em] caret-transparent opacity-100 shadow-none outline-none\"\n style={dynamicInputStyle}\n maxLength={maxLength}\n value={value}\n ref={inputRef}\n onPaste={(e) => {\n _pasteListener(e);\n props.onPaste?.(e);\n }}\n onChange={_changeListener}\n onMouseOver={(e) => {\n setIsHoveringInput(true);\n props.onMouseOver?.(e);\n }}\n onMouseLeave={(e) => {\n setIsHoveringInput(false);\n props.onMouseLeave?.(e);\n }}\n onKeyDown={(e) => {\n // Track arrow key navigation to ensure active slot updates correctly\n if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n // Use requestAnimationFrame to check selection after browser has processed the key\n requestAnimationFrame(() => {\n const input = inputRef.current;\n if (input && document.activeElement === input) {\n const s = input.selectionStart;\n const end = input.selectionEnd;\n if (s !== null && end !== null) {\n // Update actual caret position - use start position as caret\n setActualCaretPosition(s);\n }\n }\n });\n }\n props.onKeyDown?.(e);\n }}\n onFocus={(e) => {\n _focusListener();\n props.onFocus?.(e);\n }}\n onBlur={(e) => {\n setIsFocused(false);\n props.onBlur?.(e);\n }}\n />\n );\n\n const setSelection = (index: number) => {\n const input = inputRef.current;\n if (!input || props.disabled) {\n return;\n }\n\n // Clamp index to valid range\n const clampedIndex = Math.max(0, Math.min(index, maxLength - 1));\n\n // Focus the input if not already focused\n if (document.activeElement !== input) {\n input.focus();\n }\n\n // Set selection to the clicked slot\n // If there's a character at that position, select it; otherwise just position the caret\n const hasChar = value[clampedIndex] !== undefined;\n const start = clampedIndex;\n const end = hasChar ? clampedIndex + 1 : clampedIndex;\n\n input.setSelectionRange(start, end);\n setMirrorSelectionStart(start);\n setMirrorSelectionEnd(end);\n setIsFocused(true);\n };\n\n const contextValue: RenderProps = {\n slots: Array.from({ length: maxLength }).map((_, slotIdx) => {\n const isActive =\n isFocused &&\n mirrorSelectionStart !== null &&\n mirrorSelectionEnd !== null &&\n ((mirrorSelectionStart === mirrorSelectionEnd &&\n slotIdx === mirrorSelectionStart) ||\n (slotIdx >= mirrorSelectionStart && slotIdx < mirrorSelectionEnd));\n\n const char = value[slotIdx] !== undefined ? value[slotIdx] : null;\n const placeholderChar =\n value[0] !== undefined ? null : (placeholder?.[slotIdx] ?? null);\n\n return {\n char,\n placeholderChar,\n isActive,\n hasFakeCaret: isActive && char === null,\n };\n }),\n isFocused,\n isHovering: !props.disabled && isHoveringInput,\n setSelection,\n };\n\n const renderedChildren =\n render !== undefined ? (\n render(contextValue)\n ) : (\n <OTPInputContext.Provider value={contextValue}>\n {children}\n </OTPInputContext.Provider>\n );\n\n return (\n <>\n {noScriptCSSFallback !== null && (\n <noscript>\n <style>{noScriptCSSFallback}</style>\n </noscript>\n )}\n\n <div\n ref={containerRef}\n className={cn(\n 'relative',\n props.disabled ? 'cursor-default' : 'cursor-text',\n containerClassName\n )}\n >\n {renderedChildren}\n\n <div className=\"absolute inset-0\">{renderedInput}</div>\n </div>\n </>\n );\n};\n\n// ---------------- Root ----------------\n\ntype InputOTPProps = Omit<ComponentProps<typeof OTPInput>, 'children'>;\n\nexport const inputSlotVariants = cva('block text-center', {\n variants: {\n size: {\n sm: 'h-4 w-3 text-sm',\n md: 'h-5 w-4 text-base',\n lg: 'h-6 w-5 text-lg',\n xl: 'h-7 w-6 text-xl',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\nexport const InputOTP: FC<InputOTPProps> = ({\n className,\n render,\n ...props\n}) => (\n <OTPInput\n containerClassName=\"relative flex items-center gap-2 has-disabled:opacity-50\"\n className={cn('disabled:cursor-not-allowed', className)}\n render={render!}\n {...props}\n />\n);\n\n// ---------------- Group ----------------\n\nexport const InputOTPGroup = ({\n className,\n ...props\n}: ComponentProps<'div'>) => (\n <div className={cn('z-10 flex items-center gap-3', className)} {...props} />\n);\n\n// ---------------- Slot ----------------\n\ntype InputOTPSlotProps = Omit<ButtonProps, 'variant' | 'label'> & {\n index: number;\n};\n\nexport const InputOTPSlot: FC<InputOTPSlotProps> = ({\n index,\n className,\n onClick,\n onKeyDown,\n ...props\n}) => {\n const inputOTPContext = useContext(OTPInputContext);\n const { char, isActive } = inputOTPContext?.slots[index] ?? {};\n const { setSelection } = inputOTPContext ?? {};\n\n const handleClick = (e: MouseEvent<HTMLButtonElement>) => {\n setSelection?.(index);\n onClick?.(e);\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setSelection?.(index);\n }\n onKeyDown?.(e);\n };\n\n return (\n <Button\n isSelected={isActive}\n variant=\"input\"\n color=\"custom\"\n tabIndex={-1}\n className={cn('relative z-10 px-2!', isActive && 'ring-4!', className)}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n label={null}\n {...props}\n >\n {/* value */}\n <span className=\"relative z-10 flex h-6 w-4 items-center justify-center\">\n {char}\n </span>\n </Button>\n );\n};\n\n// ---------------- Separator ----------------\n\nexport const InputOTPSeparator: FC<ComponentProps<'div'>> = (props) => (\n <div\n aria-hidden\n className=\"z-0 table h-0.5 w-3 rounded-full text-foreground/50\"\n {...props}\n >\n <MinusIcon />\n </div>\n);\n\nexport const InputIndicator: FC<ComponentProps<'div'>> = (props) => (\n <div\n data-indicator\n className=\"absolute top-0 z-0 h-full w-auto rounded-xl bg-text/20 ring-4 ring-text/20 transition-[left,width] duration-300 ease-in-out [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl motion-reduce:transition-none\"\n {...props}\n />\n);\n"],"mappings":"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"}
@@ -157,7 +157,7 @@ const KeyboardShortcut = ({ shortcut, onTriggered, display = true, disabled = fa
157
157
  return pressedKeys.has(key) || pressedKeys.has(upperKey) || pressedKeys.has(normalizedKey) || key === "⌘" && pressedKeys.has("Meta") || key === "Ctrl" && pressedKeys.has("Control") || key === "⌥" && pressedKeys.has("Alt") || key === "Alt" && pressedKeys.has("Alt") || key === "←" && pressedKeys.has("ArrowLeft") || key === "→" && pressedKeys.has("ArrowRight") || key === "↑" && pressedKeys.has("ArrowUp") || key === "↓" && pressedKeys.has("ArrowDown");
158
158
  };
159
159
  return /* @__PURE__ */ jsx("kbd", {
160
- className: cn("inline-flex items-center justify-center gap-0.5 p-0.5", "rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl", "font-medium font-sans", "border-1 border-neutral/20 text-neutral", size === "sm" && "text-xs", size === "md" && "text-sm", size === "lg" && "text-base", className),
160
+ className: cn("inline-flex items-center justify-center gap-0.5 p-0.5", "rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl", "font-medium font-sans", "border-1 text-neutral", size === "sm" && "text-xs", size === "md" && "text-sm", size === "lg" && "text-base", className),
161
161
  children: keys.map((key, index) => {
162
162
  const keyId = `${key}-${index}-${shortcut}`;
163
163
  const displayKey = getDisplayKey(key);
@@ -167,7 +167,7 @@ const KeyboardShortcut = ({ shortcut, onTriggered, display = true, disabled = fa
167
167
  className: "text-neutral/50",
168
168
  children: "+"
169
169
  }), /* @__PURE__ */ jsx("span", {
170
- className: cn("min-w-4 px-0.5 text-center", isKeyPressed(key) && "scale-120 font-bold text-text"),
170
+ className: cn("min-w-4 px-0.5 text-center", isKeyPressed(key) && "scale-120 font-bold text-foreground"),
171
171
  suppressHydrationWarning: true,
172
172
  children: displayKey
173
173
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"KeyboardShortcut.mjs","names":[],"sources":["../../../../src/components/KeyboardShortcut/KeyboardShortcut.tsx"],"sourcesContent":["'use client';\n\nimport { useDevice } from '@hooks/useDevice';\nimport { cn } from '@utils/cn';\nimport { type FC, useEffect, useState } from 'react';\n\n/**\n * Enum for available keyboard keys\n */\nexport type KeyList =\n | 'Ctrl'\n | 'Alt'\n | 'Shift'\n | 'Meta'\n | 'F'\n | 'K'\n | 'L'\n | 'P'\n | 'S'\n | 'A'\n | 'B'\n | 'C'\n | 'D'\n | 'E'\n | 'G'\n | 'H'\n | 'I'\n | 'J'\n | 'M'\n | 'N'\n | 'O'\n | 'Q'\n | 'R'\n | 'T'\n | 'U'\n | 'V'\n | 'W'\n | 'X'\n | 'Y'\n | 'Z'\n | 'Enter'\n | 'Escape'\n | 'Backspace'\n | 'Tab'\n | 'Space'\n | 'ArrowUp'\n | 'ArrowDown'\n | 'ArrowLeft'\n | 'ArrowRight';\n\n/**\n * Type-safe keyboard shortcut combinations\n * Note: Using string type to avoid union type complexity issues\n * Expected format: \"Key + Key\" (e.g., \"⌘ + F\", \"Ctrl + Shift + K\")\n */\nexport type KeyboardShortcutType = string;\n\nexport type KeyboardShortcutProps = {\n /** The keyboard shortcut combination (e.g., \"⌘ + F\" or \"Ctrl + K\") */\n shortcut: KeyboardShortcutType;\n /** Callback function triggered when the shortcut is pressed */\n onTriggered?: () => void;\n /** Whether to display the shortcut visually (default: true) */\n display?: boolean;\n /** Whether to disable the shortcut trigger (default: false) */\n disabled?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Size of the keyboard shortcut display */\n size?: 'sm' | 'md' | 'lg';\n};\n\n/**\n * Parse keyboard shortcut string into individual keys\n */\nconst parseShortcut = (shortcut: string): string[] => {\n return shortcut.split(' + ').map((key) => key.trim());\n};\n\n/**\n * Normalize key name for event comparison\n */\nconst normalizeKey = (key: string): string => {\n const keyMap: Record<string, string> = {\n '⌘': 'Meta',\n Ctrl: 'Control',\n Control: 'Control',\n Alt: 'Alt',\n '⌥': 'Alt',\n Shift: 'Shift',\n Meta: 'Meta',\n '↑': 'ArrowUp',\n '↓': 'ArrowDown',\n '←': 'ArrowLeft',\n '→': 'ArrowRight',\n ArrowUp: 'ArrowUp',\n ArrowDown: 'ArrowDown',\n ArrowLeft: 'ArrowLeft',\n ArrowRight: 'ArrowRight',\n };\n\n return keyMap[key] || key;\n};\n\n/**\n * Check if the keyboard event matches the shortcut\n */\nconst matchesShortcut = (event: KeyboardEvent, keys: string[]): boolean => {\n const normalizedKeys = keys.map(normalizeKey);\n const hasModifiers = {\n Meta: normalizedKeys.includes('Meta'),\n Control: normalizedKeys.includes('Control'),\n Alt: normalizedKeys.includes('Alt'),\n Shift: normalizedKeys.includes('Shift'),\n };\n\n // Check if all required modifiers are pressed\n if (\n hasModifiers.Meta !== event.metaKey ||\n hasModifiers.Control !== event.ctrlKey ||\n hasModifiers.Alt !== event.altKey ||\n hasModifiers.Shift !== event.shiftKey\n ) {\n return false;\n }\n\n // Find the non-modifier key\n const nonModifierKey = keys.find(\n (key) =>\n !['⌘', 'Ctrl', 'Control', 'Alt', '⌥', 'Shift', 'Meta'].includes(\n normalizeKey(key)\n )\n );\n\n if (!nonModifierKey) return false;\n\n // Normalize the key for comparison\n const normalizedNonModifierKey = normalizeKey(nonModifierKey);\n\n // Compare the main key\n // For arrow keys, compare directly with event.key\n if (normalizedNonModifierKey.startsWith('Arrow')) {\n return event.key === normalizedNonModifierKey;\n }\n\n // For other keys, compare case-insensitive\n return event.key.toLowerCase() === normalizedNonModifierKey.toLowerCase();\n};\n\n/**\n * Get display key symbol for better visual representation\n */\nconst getDisplayKey = (key: string): string => {\n const displayMap: Record<string, string> = {\n ArrowUp: '↑',\n ArrowDown: '↓',\n ArrowLeft: '←',\n ArrowRight: '→',\n };\n\n return displayMap[key] || key;\n};\n\n/**\n * Get display shortcut based on OS (Mac uses ⌘ and ⌥, others use Ctrl and Alt)\n */\nconst getDisplayShortcut = (shortcut: string, isMac: boolean): string => {\n let result = shortcut;\n\n if (isMac) {\n result = result.replace(/Ctrl/g, '⌘');\n result = result.replace(/Alt/g, '⌥');\n } else {\n result = result.replace(/⌘/g, 'Ctrl');\n result = result.replace(/⌥/g, 'Alt');\n }\n\n // Replace arrow key names with symbols\n result = result.replace(/ArrowUp/g, '↑');\n result = result.replace(/ArrowDown/g, '↓');\n result = result.replace(/ArrowLeft/g, '←');\n result = result.replace(/ArrowRight/g, '→');\n\n return result;\n};\n\n/**\n * KeyboardShortcut Component\n *\n * A reusable component that displays keyboard shortcuts and listens for key combinations.\n * Automatically adapts to Mac (⌘, ⌥) and Windows/Linux (Ctrl, Alt) conventions.\n *\n * @example\n * ```tsx\n * <KeyboardShortcut\n * shortcut=\"⌘ + F\"\n * onTriggered={() => setShowSearch(true)}\n * />\n * ```\n */\nexport const KeyboardShortcut: FC<KeyboardShortcutProps> = ({\n shortcut,\n onTriggered,\n display = true,\n disabled = false,\n className,\n size = 'md',\n}) => {\n const { isMac } = useDevice();\n const displayShortcut = getDisplayShortcut(shortcut, isMac ?? false);\n const keys = parseShortcut(displayShortcut);\n const [pressedKeys, setPressedKeys] = useState<Set<string>>(new Set());\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n // 1. Identify input fields\n const target = event.target as HTMLElement;\n const isInputField =\n target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable;\n\n // ... (Your existing key visualization logic here) ...\n // Note: Copied your key tracking logic for context\n const currentKey = event.key;\n const normalizedEventKeys = new Set<string>();\n if (event.metaKey) normalizedEventKeys.add('⌘');\n if (event.ctrlKey) normalizedEventKeys.add('Ctrl');\n if (event.altKey) normalizedEventKeys.add(isMac ? '⌥' : 'Alt');\n if (event.shiftKey) normalizedEventKeys.add('Shift');\n\n if (currentKey.startsWith('Arrow')) {\n normalizedEventKeys.add(currentKey);\n normalizedEventKeys.add(getDisplayKey(currentKey));\n } else {\n normalizedEventKeys.add(currentKey.toUpperCase());\n }\n setPressedKeys(normalizedEventKeys);\n\n // 2. Trigger callback if shortcut matches\n if (!disabled && onTriggered && matchesShortcut(event, keys)) {\n // FIX: Check if the required shortcut is \"Escape\"\n const isEscapeShortcut = keys.includes('Escape');\n\n // Only block if it is an input field AND the shortcut is NOT Escape\n if (isInputField && !isEscapeShortcut) {\n return;\n }\n\n event.preventDefault();\n onTriggered();\n }\n };\n\n const handleKeyUp = () => {\n setPressedKeys(new Set());\n };\n\n window.addEventListener('keydown', handleKeyDown);\n window.addEventListener('keyup', handleKeyUp);\n window.addEventListener('blur', handleKeyUp);\n\n return () => {\n window.removeEventListener('keydown', handleKeyDown);\n window.removeEventListener('keyup', handleKeyUp);\n window.removeEventListener('blur', handleKeyUp);\n };\n }, [keys, onTriggered, isMac, disabled]);\n if (!display) return null;\n\n /**\n * Check if a key is currently pressed\n */\n const isKeyPressed = (key: string): boolean => {\n const upperKey = key.toUpperCase();\n const normalizedKey = normalizeKey(key);\n\n return (\n pressedKeys.has(key) ||\n pressedKeys.has(upperKey) ||\n pressedKeys.has(normalizedKey) ||\n // Check for modifier key matches\n (key === '⌘' && pressedKeys.has('Meta')) ||\n (key === 'Ctrl' && pressedKeys.has('Control')) ||\n (key === '⌥' && pressedKeys.has('Alt')) ||\n (key === 'Alt' && pressedKeys.has('Alt')) ||\n // Check for arrow key symbols\n (key === '←' && pressedKeys.has('ArrowLeft')) ||\n (key === '→' && pressedKeys.has('ArrowRight')) ||\n (key === '↑' && pressedKeys.has('ArrowUp')) ||\n (key === '↓' && pressedKeys.has('ArrowDown'))\n );\n };\n\n return (\n <kbd\n className={cn(\n 'inline-flex items-center justify-center gap-0.5 p-0.5',\n 'rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl',\n 'font-medium font-sans',\n 'border-1 border-neutral/20 text-neutral',\n size === 'sm' && 'text-xs',\n size === 'md' && 'text-sm',\n size === 'lg' && 'text-base',\n className\n )}\n >\n {keys.map((key, index) => {\n const keyId = `${key}-${index}-${shortcut}`;\n const displayKey = getDisplayKey(key);\n return (\n <span key={keyId} className=\"inline-flex items-center\">\n {index > 0 && <span className=\"text-neutral/50\">+</span>}\n <span\n className={cn(\n 'min-w-4 px-0.5 text-center',\n isKeyPressed(key) && 'scale-120 font-bold text-text'\n )}\n suppressHydrationWarning\n >\n {displayKey}\n </span>\n </span>\n );\n })}\n </kbd>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"KeyboardShortcut.mjs","names":[],"sources":["../../../../src/components/KeyboardShortcut/KeyboardShortcut.tsx"],"sourcesContent":["'use client';\n\nimport { useDevice } from '@hooks/useDevice';\nimport { cn } from '@utils/cn';\nimport { type FC, useEffect, useState } from 'react';\n\n/**\n * Enum for available keyboard keys\n */\nexport type KeyList =\n | 'Ctrl'\n | 'Alt'\n | 'Shift'\n | 'Meta'\n | 'F'\n | 'K'\n | 'L'\n | 'P'\n | 'S'\n | 'A'\n | 'B'\n | 'C'\n | 'D'\n | 'E'\n | 'G'\n | 'H'\n | 'I'\n | 'J'\n | 'M'\n | 'N'\n | 'O'\n | 'Q'\n | 'R'\n | 'T'\n | 'U'\n | 'V'\n | 'W'\n | 'X'\n | 'Y'\n | 'Z'\n | 'Enter'\n | 'Escape'\n | 'Backspace'\n | 'Tab'\n | 'Space'\n | 'ArrowUp'\n | 'ArrowDown'\n | 'ArrowLeft'\n | 'ArrowRight';\n\n/**\n * Type-safe keyboard shortcut combinations\n * Note: Using string type to avoid union type complexity issues\n * Expected format: \"Key + Key\" (e.g., \"⌘ + F\", \"Ctrl + Shift + K\")\n */\nexport type KeyboardShortcutType = string;\n\nexport type KeyboardShortcutProps = {\n /** The keyboard shortcut combination (e.g., \"⌘ + F\" or \"Ctrl + K\") */\n shortcut: KeyboardShortcutType;\n /** Callback function triggered when the shortcut is pressed */\n onTriggered?: () => void;\n /** Whether to display the shortcut visually (default: true) */\n display?: boolean;\n /** Whether to disable the shortcut trigger (default: false) */\n disabled?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Size of the keyboard shortcut display */\n size?: 'sm' | 'md' | 'lg';\n};\n\n/**\n * Parse keyboard shortcut string into individual keys\n */\nconst parseShortcut = (shortcut: string): string[] => {\n return shortcut.split(' + ').map((key) => key.trim());\n};\n\n/**\n * Normalize key name for event comparison\n */\nconst normalizeKey = (key: string): string => {\n const keyMap: Record<string, string> = {\n '⌘': 'Meta',\n Ctrl: 'Control',\n Control: 'Control',\n Alt: 'Alt',\n '⌥': 'Alt',\n Shift: 'Shift',\n Meta: 'Meta',\n '↑': 'ArrowUp',\n '↓': 'ArrowDown',\n '←': 'ArrowLeft',\n '→': 'ArrowRight',\n ArrowUp: 'ArrowUp',\n ArrowDown: 'ArrowDown',\n ArrowLeft: 'ArrowLeft',\n ArrowRight: 'ArrowRight',\n };\n\n return keyMap[key] || key;\n};\n\n/**\n * Check if the keyboard event matches the shortcut\n */\nconst matchesShortcut = (event: KeyboardEvent, keys: string[]): boolean => {\n const normalizedKeys = keys.map(normalizeKey);\n const hasModifiers = {\n Meta: normalizedKeys.includes('Meta'),\n Control: normalizedKeys.includes('Control'),\n Alt: normalizedKeys.includes('Alt'),\n Shift: normalizedKeys.includes('Shift'),\n };\n\n // Check if all required modifiers are pressed\n if (\n hasModifiers.Meta !== event.metaKey ||\n hasModifiers.Control !== event.ctrlKey ||\n hasModifiers.Alt !== event.altKey ||\n hasModifiers.Shift !== event.shiftKey\n ) {\n return false;\n }\n\n // Find the non-modifier key\n const nonModifierKey = keys.find(\n (key) =>\n !['⌘', 'Ctrl', 'Control', 'Alt', '⌥', 'Shift', 'Meta'].includes(\n normalizeKey(key)\n )\n );\n\n if (!nonModifierKey) return false;\n\n // Normalize the key for comparison\n const normalizedNonModifierKey = normalizeKey(nonModifierKey);\n\n // Compare the main key\n // For arrow keys, compare directly with event.key\n if (normalizedNonModifierKey.startsWith('Arrow')) {\n return event.key === normalizedNonModifierKey;\n }\n\n // For other keys, compare case-insensitive\n return event.key.toLowerCase() === normalizedNonModifierKey.toLowerCase();\n};\n\n/**\n * Get display key symbol for better visual representation\n */\nconst getDisplayKey = (key: string): string => {\n const displayMap: Record<string, string> = {\n ArrowUp: '↑',\n ArrowDown: '↓',\n ArrowLeft: '←',\n ArrowRight: '→',\n };\n\n return displayMap[key] || key;\n};\n\n/**\n * Get display shortcut based on OS (Mac uses ⌘ and ⌥, others use Ctrl and Alt)\n */\nconst getDisplayShortcut = (shortcut: string, isMac: boolean): string => {\n let result = shortcut;\n\n if (isMac) {\n result = result.replace(/Ctrl/g, '⌘');\n result = result.replace(/Alt/g, '⌥');\n } else {\n result = result.replace(/⌘/g, 'Ctrl');\n result = result.replace(/⌥/g, 'Alt');\n }\n\n // Replace arrow key names with symbols\n result = result.replace(/ArrowUp/g, '↑');\n result = result.replace(/ArrowDown/g, '↓');\n result = result.replace(/ArrowLeft/g, '←');\n result = result.replace(/ArrowRight/g, '→');\n\n return result;\n};\n\n/**\n * KeyboardShortcut Component\n *\n * A reusable component that displays keyboard shortcuts and listens for key combinations.\n * Automatically adapts to Mac (⌘, ⌥) and Windows/Linux (Ctrl, Alt) conventions.\n *\n * @example\n * ```tsx\n * <KeyboardShortcut\n * shortcut=\"⌘ + F\"\n * onTriggered={() => setShowSearch(true)}\n * />\n * ```\n */\nexport const KeyboardShortcut: FC<KeyboardShortcutProps> = ({\n shortcut,\n onTriggered,\n display = true,\n disabled = false,\n className,\n size = 'md',\n}) => {\n const { isMac } = useDevice();\n const displayShortcut = getDisplayShortcut(shortcut, isMac ?? false);\n const keys = parseShortcut(displayShortcut);\n const [pressedKeys, setPressedKeys] = useState<Set<string>>(new Set());\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n // 1. Identify input fields\n const target = event.target as HTMLElement;\n const isInputField =\n target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable;\n\n // ... (Your existing key visualization logic here) ...\n // Note: Copied your key tracking logic for context\n const currentKey = event.key;\n const normalizedEventKeys = new Set<string>();\n if (event.metaKey) normalizedEventKeys.add('⌘');\n if (event.ctrlKey) normalizedEventKeys.add('Ctrl');\n if (event.altKey) normalizedEventKeys.add(isMac ? '⌥' : 'Alt');\n if (event.shiftKey) normalizedEventKeys.add('Shift');\n\n if (currentKey.startsWith('Arrow')) {\n normalizedEventKeys.add(currentKey);\n normalizedEventKeys.add(getDisplayKey(currentKey));\n } else {\n normalizedEventKeys.add(currentKey.toUpperCase());\n }\n setPressedKeys(normalizedEventKeys);\n\n // 2. Trigger callback if shortcut matches\n if (!disabled && onTriggered && matchesShortcut(event, keys)) {\n // FIX: Check if the required shortcut is \"Escape\"\n const isEscapeShortcut = keys.includes('Escape');\n\n // Only block if it is an input field AND the shortcut is NOT Escape\n if (isInputField && !isEscapeShortcut) {\n return;\n }\n\n event.preventDefault();\n onTriggered();\n }\n };\n\n const handleKeyUp = () => {\n setPressedKeys(new Set());\n };\n\n window.addEventListener('keydown', handleKeyDown);\n window.addEventListener('keyup', handleKeyUp);\n window.addEventListener('blur', handleKeyUp);\n\n return () => {\n window.removeEventListener('keydown', handleKeyDown);\n window.removeEventListener('keyup', handleKeyUp);\n window.removeEventListener('blur', handleKeyUp);\n };\n }, [keys, onTriggered, isMac, disabled]);\n if (!display) return null;\n\n /**\n * Check if a key is currently pressed\n */\n const isKeyPressed = (key: string): boolean => {\n const upperKey = key.toUpperCase();\n const normalizedKey = normalizeKey(key);\n\n return (\n pressedKeys.has(key) ||\n pressedKeys.has(upperKey) ||\n pressedKeys.has(normalizedKey) ||\n // Check for modifier key matches\n (key === '⌘' && pressedKeys.has('Meta')) ||\n (key === 'Ctrl' && pressedKeys.has('Control')) ||\n (key === '⌥' && pressedKeys.has('Alt')) ||\n (key === 'Alt' && pressedKeys.has('Alt')) ||\n // Check for arrow key symbols\n (key === '←' && pressedKeys.has('ArrowLeft')) ||\n (key === '→' && pressedKeys.has('ArrowRight')) ||\n (key === '↑' && pressedKeys.has('ArrowUp')) ||\n (key === '↓' && pressedKeys.has('ArrowDown'))\n );\n };\n\n return (\n <kbd\n className={cn(\n 'inline-flex items-center justify-center gap-0.5 p-0.5',\n 'rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl',\n 'font-medium font-sans',\n 'border-1 text-neutral',\n size === 'sm' && 'text-xs',\n size === 'md' && 'text-sm',\n size === 'lg' && 'text-base',\n className\n )}\n >\n {keys.map((key, index) => {\n const keyId = `${key}-${index}-${shortcut}`;\n const displayKey = getDisplayKey(key);\n return (\n <span key={keyId} className=\"inline-flex items-center\">\n {index > 0 && <span className=\"text-neutral/50\">+</span>}\n <span\n className={cn(\n 'min-w-4 px-0.5 text-center',\n isKeyPressed(key) && 'scale-120 font-bold text-foreground'\n )}\n suppressHydrationWarning\n >\n {displayKey}\n </span>\n </span>\n );\n })}\n </kbd>\n );\n};\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../utils/cn.mjs";
4
- import { Container } from "../Container/index.mjs";
5
4
  import { Flag } from "../Flags/Flag.mjs";
6
5
  import { startTransition, useEffect, useState } from "react";
7
6
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -17,14 +16,13 @@ const shuffleArray = (array, limit) => {
17
16
  return limit ? shuffled.slice(0, limit) : shuffled;
18
17
  };
19
18
  const LocalCard = ({ locale, ...props }) => /* @__PURE__ */ jsx("div", {
20
- className: "group z-10 mx-8 inline-flex shrink-0 transition-transform duration-300 hover:scale-105",
19
+ className: "group z-10 mx-8 inline-flex shrink-0 scale-95 rounded-lg border transition-transform duration-300 hover:scale-100",
21
20
  ...props,
22
- children: /* @__PURE__ */ jsxs(Container, {
23
- roundedSize: "xl",
24
- className: "flex flex-row items-center gap-5 p-3",
21
+ children: /* @__PURE__ */ jsxs("div", {
22
+ className: "flex flex-row items-center gap-5 px-3 py-1",
25
23
  children: [/* @__PURE__ */ jsx(Flag, {
26
24
  locale,
27
- className: "max-h-5 max-w-5 rounded-sm grayscale-80 transition duration-300 group-hover:grayscale-0",
25
+ className: "size-5 rounded-sm grayscale-50 transition duration-300 group-hover:grayscale-0",
28
26
  width: 640,
29
27
  height: 480,
30
28
  loading: "lazy"
@@ -56,7 +54,7 @@ const LanguageSection = ({ className, ...props }) => {
56
54
  });
57
55
  }, []);
58
56
  return /* @__PURE__ */ jsx("section", {
59
- className: cn("mask-[linear-gradient(to_right,transparent_0,black_128px,black_calc(100%-128px),transparent_100%)] my-10 w-full overflow-hidden", className),
57
+ className: cn("w-full overflow-hidden py-3", className),
60
58
  ...props,
61
59
  children: /* @__PURE__ */ jsxs("div", {
62
60
  className: "relative flex w-full flex-col gap-5 py-3",
@@ -83,5 +81,5 @@ const LanguageSection = ({ className, ...props }) => {
83
81
  };
84
82
 
85
83
  //#endregion
86
- export { LanguageSection };
84
+ export { LanguageSection, LocalCardList };
87
85
  //# sourceMappingURL=LanguageSection.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"LanguageSection.mjs","names":[],"sources":["../../../../src/components/LanguageBackground/LanguageSection.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport {\n ALL_LOCALES,\n getHTMLTextDir,\n getLocaleName,\n type Locale,\n} from 'intlayer';\nimport {\n type FC,\n type HTMLAttributes,\n startTransition,\n useEffect,\n useState,\n} from 'react';\nimport { Container } from '../Container';\nimport { Flag } from '../Flags';\n\nconst shuffleArray = (array: string[], limit?: number) => {\n const shuffled = [...array];\n\n for (let i = shuffled.length - 1; i > 0; i--) {\n const randomIndex = Math.floor(Math.random() * (i + 1));\n\n [shuffled[i], shuffled[randomIndex]] = [shuffled[randomIndex], shuffled[i]];\n }\n\n return limit ? shuffled.slice(0, limit) : shuffled;\n};\n\nconst LocalCard: FC<{ locale: string }> = ({ locale, ...props }) => (\n <div\n className=\"group z-10 mx-8 inline-flex shrink-0 transition-transform duration-300 hover:scale-105\"\n {...props}\n >\n <Container\n roundedSize=\"xl\"\n className=\"flex flex-row items-center gap-5 p-3\"\n >\n <Flag\n locale={locale as Locale}\n className=\"max-h-5 max-w-5 rounded-sm grayscale-80 transition duration-300 group-hover:grayscale-0\"\n width={640}\n height={480}\n loading=\"lazy\"\n />\n <span\n dir={getHTMLTextDir(locale as Locale)}\n lang={locale as Locale}\n className=\"flex text-nowrap\"\n >\n {getLocaleName(locale as Locale)}\n </span>\n </Container>\n </div>\n);\n\nconst LocalCardList: FC<{ localeList: string[]; className?: string }> = ({\n localeList,\n className,\n ...props\n}) => (\n <div className=\"relative flex w-full overflow-hidden\" {...props}>\n <div\n className={cn('inline-flex shrink-0 will-change-transform', className)}\n >\n {/* First set of cards */}\n {localeList.map((locale) => (\n <LocalCard key={`${locale}-first`} locale={locale} />\n ))}\n {/* Duplicate set for seamless loop */}\n {localeList.map((locale) => (\n <LocalCard key={`${locale}-second`} locale={locale} />\n ))}\n </div>\n </div>\n);\n\nconst NUM_OF_LOCALES = 15;\n\nconst emptyArrayOfLocale: string[][] = new Array(4).fill(0).map(() => []);\nconst arrayOfLocale: string[][] = new Array(4)\n .fill(0)\n .map(() => shuffleArray(Object.values(ALL_LOCALES), NUM_OF_LOCALES));\n\nexport const LanguageSection: FC<HTMLAttributes<HTMLElement>> = ({\n className,\n ...props\n}) => {\n const [localeList, setLocaleList] = useState(emptyArrayOfLocale);\n const [firstPart, secondPart, thirdPart, fourthPart] = localeList;\n\n useEffect(() => {\n startTransition(() => {\n setLocaleList(arrayOfLocale);\n });\n }, []);\n\n return (\n <section\n className={cn(\n 'mask-[linear-gradient(to_right,transparent_0,black_128px,black_calc(100%-128px),transparent_100%)] my-10 w-full overflow-hidden',\n className\n )}\n {...props}\n >\n <div className=\"relative flex w-full flex-col gap-5 py-3\">\n <LocalCardList localeList={firstPart} className=\"horizontal-loop-1\" />\n <LocalCardList localeList={secondPart} className=\"horizontal-loop-2\" />\n <LocalCardList localeList={thirdPart} className=\"horizontal-loop-1\" />\n <LocalCardList localeList={fourthPart} className=\"horizontal-loop-2\" />\n </div>\n </section>\n );\n};\n"],"mappings":";;;;;;;;;;AAmBA,MAAM,gBAAgB,OAAiB,UAAmB;CACxD,MAAM,WAAW,CAAC,GAAG,KAAK;CAE1B,KAAK,IAAI,IAAI,SAAS,SAAS,GAAG,IAAI,GAAG,KAAK;EAC5C,MAAM,cAAc,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE;EAEtD,CAAC,SAAS,IAAI,SAAS,gBAAgB,CAAC,SAAS,cAAc,SAAS,EAAE;CAC5E;CAEA,OAAO,QAAQ,SAAS,MAAM,GAAG,KAAK,IAAI;AAC5C;AAEA,MAAM,aAAqC,EAAE,QAAQ,GAAG,YACtD,oBAAC,OAAD;CACE,WAAU;CACV,GAAI;WAEJ,qBAAC,WAAD;EACE,aAAY;EACZ,WAAU;YAFZ,CAIE,oBAAC,MAAD;GACU;GACR,WAAU;GACV,OAAO;GACP,QAAQ;GACR,SAAQ;EACT,IACD,oBAAC,QAAD;GACE,KAAK,eAAe,MAAgB;GACpC,MAAM;GACN,WAAU;aAET,cAAc,MAAgB;EAC3B,EACG;;AACR;AAGP,MAAM,iBAAmE,EACvE,YACA,WACA,GAAG,YAEH,oBAAC,OAAD;CAAK,WAAU;CAAuC,GAAI;WACxD,qBAAC,OAAD;EACE,WAAW,GAAG,8CAA8C,SAAS;YADvE,CAIG,WAAW,KAAK,WACf,oBAAC,WAAD,EAA2C,OAAS,GAApC,GAAG,OAAO,OAA0B,CACrD,GAEA,WAAW,KAAK,WACf,oBAAC,WAAD,EAA4C,OAAS,GAArC,GAAG,OAAO,QAA2B,CACtD,CACE;;AACF;AAGP,MAAM,iBAAiB;AAEvB,MAAM,qBAAiC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AACxE,MAAM,gBAA4B,IAAI,MAAM,CAAC,CAAC,CAC3C,KAAK,CAAC,CAAC,CACP,UAAU,aAAa,OAAO,OAAO,WAAW,GAAG,cAAc,CAAC;AAErE,MAAa,mBAAoD,EAC/D,WACA,GAAG,YACC;CACJ,MAAM,CAAC,YAAY,iBAAiB,SAAS,kBAAkB;CAC/D,MAAM,CAAC,WAAW,YAAY,WAAW,cAAc;CAEvD,gBAAgB;EACd,sBAAsB;GACpB,cAAc,aAAa;EAC7B,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,OACE,oBAAC,WAAD;EACE,WAAW,GACT,mIACA,SACF;EACA,GAAI;YAEJ,qBAAC,OAAD;GAAK,WAAU;aAAf;IACE,oBAAC,eAAD;KAAe,YAAY;KAAW,WAAU;IAAqB;IACrE,oBAAC,eAAD;KAAe,YAAY;KAAY,WAAU;IAAqB;IACtE,oBAAC,eAAD;KAAe,YAAY;KAAW,WAAU;IAAqB;IACrE,oBAAC,eAAD;KAAe,YAAY;KAAY,WAAU;IAAqB;GACnE;;CACE;AAEb"}
1
+ {"version":3,"file":"LanguageSection.mjs","names":[],"sources":["../../../../src/components/LanguageBackground/LanguageSection.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport {\n ALL_LOCALES,\n getHTMLTextDir,\n getLocaleName,\n type Locale,\n} from 'intlayer';\nimport {\n type FC,\n type HTMLAttributes,\n startTransition,\n useEffect,\n useState,\n} from 'react';\nimport { Flag } from '../Flags';\n\nconst shuffleArray = (array: string[], limit?: number) => {\n const shuffled = [...array];\n\n for (let i = shuffled.length - 1; i > 0; i--) {\n const randomIndex = Math.floor(Math.random() * (i + 1));\n\n [shuffled[i], shuffled[randomIndex]] = [shuffled[randomIndex], shuffled[i]];\n }\n\n return limit ? shuffled.slice(0, limit) : shuffled;\n};\n\nconst LocalCard: FC<{ locale: string }> = ({ locale, ...props }) => (\n <div\n className=\"group z-10 mx-8 inline-flex shrink-0 scale-95 rounded-lg border transition-transform duration-300 hover:scale-100\"\n {...props}\n >\n <div className=\"flex flex-row items-center gap-5 px-3 py-1\">\n <Flag\n locale={locale as Locale}\n className=\"size-5 rounded-sm grayscale-50 transition duration-300 group-hover:grayscale-0\"\n width={640}\n height={480}\n loading=\"lazy\"\n />\n <span\n dir={getHTMLTextDir(locale as Locale)}\n lang={locale as Locale}\n className=\"flex text-nowrap\"\n >\n {getLocaleName(locale as Locale)}\n </span>\n </div>\n </div>\n);\n\nexport const LocalCardList: FC<{\n localeList: string[];\n className?: string;\n}> = ({ localeList, className, ...props }) => (\n <div className=\"relative flex w-full overflow-hidden\" {...props}>\n <div\n className={cn('inline-flex shrink-0 will-change-transform', className)}\n >\n {/* First set of cards */}\n {localeList.map((locale) => (\n <LocalCard key={`${locale}-first`} locale={locale} />\n ))}\n {/* Duplicate set for seamless loop */}\n {localeList.map((locale) => (\n <LocalCard key={`${locale}-second`} locale={locale} />\n ))}\n </div>\n </div>\n);\n\nconst NUM_OF_LOCALES = 15;\n\nconst emptyArrayOfLocale: string[][] = new Array(4).fill(0).map(() => []);\nconst arrayOfLocale: string[][] = new Array(4)\n .fill(0)\n .map(() => shuffleArray(Object.values(ALL_LOCALES), NUM_OF_LOCALES));\n\nexport const LanguageSection: FC<HTMLAttributes<HTMLElement>> = ({\n className,\n ...props\n}) => {\n const [localeList, setLocaleList] = useState(emptyArrayOfLocale);\n const [firstPart, secondPart, thirdPart, fourthPart] = localeList;\n\n useEffect(() => {\n startTransition(() => {\n setLocaleList(arrayOfLocale);\n });\n }, []);\n\n return (\n <section\n className={cn('w-full overflow-hidden py-3', className)}\n {...props}\n >\n <div className=\"relative flex w-full flex-col gap-5 py-3\">\n <LocalCardList localeList={firstPart!} className=\"horizontal-loop-1\" />\n <LocalCardList localeList={secondPart!} className=\"horizontal-loop-2\" />\n <LocalCardList localeList={thirdPart!} className=\"horizontal-loop-1\" />\n <LocalCardList localeList={fourthPart!} className=\"horizontal-loop-2\" />\n </div>\n </section>\n );\n};\n"],"mappings":";;;;;;;;;AAkBA,MAAM,gBAAgB,OAAiB,UAAmB;CACxD,MAAM,WAAW,CAAC,GAAG,KAAK;CAE1B,KAAK,IAAI,IAAI,SAAS,SAAS,GAAG,IAAI,GAAG,KAAK;EAC5C,MAAM,cAAc,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE;EAEtD,CAAC,SAAS,IAAI,SAAS,gBAAgB,CAAC,SAAS,cAAc,SAAS,EAAE;CAC5E;CAEA,OAAO,QAAQ,SAAS,MAAM,GAAG,KAAK,IAAI;AAC5C;AAEA,MAAM,aAAqC,EAAE,QAAQ,GAAG,YACtD,oBAAC,OAAD;CACE,WAAU;CACV,GAAI;WAEJ,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,MAAD;GACU;GACR,WAAU;GACV,OAAO;GACP,QAAQ;GACR,SAAQ;EACT,IACD,oBAAC,QAAD;GACE,KAAK,eAAe,MAAgB;GACpC,MAAM;GACN,WAAU;aAET,cAAc,MAAgB;EAC3B,EACH;;AACF;AAGP,MAAa,iBAGP,EAAE,YAAY,WAAW,GAAG,YAChC,oBAAC,OAAD;CAAK,WAAU;CAAuC,GAAI;WACxD,qBAAC,OAAD;EACE,WAAW,GAAG,8CAA8C,SAAS;YADvE,CAIG,WAAW,KAAK,WACf,oBAAC,WAAD,EAA2C,OAAS,GAApC,GAAG,OAAO,OAA0B,CACrD,GAEA,WAAW,KAAK,WACf,oBAAC,WAAD,EAA4C,OAAS,GAArC,GAAG,OAAO,QAA2B,CACtD,CACE;;AACF;AAGP,MAAM,iBAAiB;AAEvB,MAAM,qBAAiC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AACxE,MAAM,gBAA4B,IAAI,MAAM,CAAC,CAAC,CAC3C,KAAK,CAAC,CAAC,CACP,UAAU,aAAa,OAAO,OAAO,WAAW,GAAG,cAAc,CAAC;AAErE,MAAa,mBAAoD,EAC/D,WACA,GAAG,YACC;CACJ,MAAM,CAAC,YAAY,iBAAiB,SAAS,kBAAkB;CAC/D,MAAM,CAAC,WAAW,YAAY,WAAW,cAAc;CAEvD,gBAAgB;EACd,sBAAsB;GACpB,cAAc,aAAa;EAC7B,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,OACE,oBAAC,WAAD;EACE,WAAW,GAAG,+BAA+B,SAAS;EACtD,GAAI;YAEJ,qBAAC,OAAD;GAAK,WAAU;aAAf;IACE,oBAAC,eAAD;KAAe,YAAY;KAAY,WAAU;IAAqB;IACtE,oBAAC,eAAD;KAAe,YAAY;KAAa,WAAU;IAAqB;IACvE,oBAAC,eAAD;KAAe,YAAY;KAAY,WAAU;IAAqB;IACtE,oBAAC,eAAD;KAAe,YAAY;KAAa,WAAU;IAAqB;GACpE;;CACE;AAEb"}
@@ -1,4 +1,4 @@
1
1
  import { LanguageBackground } from "./LanguageBackground.mjs";
2
- import { LanguageSection } from "./LanguageSection.mjs";
2
+ import { LanguageSection, LocalCardList } from "./LanguageSection.mjs";
3
3
 
4
- export { LanguageBackground, LanguageSection };
4
+ export { LanguageBackground, LanguageSection, LocalCardList };
@@ -76,7 +76,7 @@ const LocaleSwitcherContent = ({ panelProps, isMultilingual = true }) => {
76
76
  else setSelectedLocales([locale]);
77
77
  };
78
78
  return /* @__PURE__ */ jsx("div", {
79
- className: "rounded-xl border border-text text-text transition-colors",
79
+ className: "rounded-xl border border-text text-foreground transition-colors",
80
80
  children: /* @__PURE__ */ jsxs(DropDown, {
81
81
  identifier: DROPDOWN_IDENTIFIER,
82
82
  children: [/* @__PURE__ */ jsx(DropDown.Trigger, {
@@ -87,7 +87,7 @@ const LocaleSwitcherContent = ({ panelProps, isMultilingual = true }) => {
87
87
  color: "text",
88
88
  variant: "hoverable",
89
89
  children: /* @__PURE__ */ jsxs("div", {
90
- className: "flex w-full items-center justify-between text-text",
90
+ className: "flex w-full items-center justify-between text-foreground",
91
91
  children: [/* @__PURE__ */ jsx("div", {
92
92
  className: "px-2 py-1",
93
93
  children: /* @__PURE__ */ jsx(Globe, { size: 16 })
@@ -1 +1 @@
1
- {"version":3,"file":"LocaleSwitcherContent.mjs","names":[],"sources":["../../../../src/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.tsx"],"sourcesContent":["'use client';\n\nimport { usePersistedStore } from '@hooks/usePersistedStore';\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core/localization';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport Fuse, { type IFuseOptions } from 'fuse.js';\nimport { Check, Globe, MoveVertical } from 'lucide-react';\nimport { type FC, useMemo, useRef, useState } from 'react';\nimport { useIntlayer, useLocale } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { Container } from '../Container';\nimport { DropDown, type PanelProps } from '../DropDown';\nimport { Input } from '../Input';\nimport { SwitchSelector } from '../SwitchSelector';\nimport { useLocaleSwitcherContent } from './LocaleSwitcherContentContext';\n\nexport type LocaleSwitcherContentProps = {\n panelProps?: Omit<PanelProps, 'identifier'>;\n isMultilingual?: boolean;\n};\n\nconst DROPDOWN_IDENTIFIER = 'locale-switcher-content';\n\ntype MultilingualAvailableLocales = {\n locale: LocalesValues;\n englishName: string;\n currentLocaleName: string;\n ownLocaleName: string;\n};\n\nexport const LocaleSwitcherContent: FC<LocaleSwitcherContentProps> = ({\n panelProps,\n isMultilingual = true,\n}) => {\n const {\n switchTo,\n searchInput,\n localeSwitcherLabel,\n languageListLabel,\n seeAllLocalesSwitch,\n } = useIntlayer('locale-switcher-content');\n const inputRef = useRef<HTMLInputElement>(null);\n const { locale } = useLocale();\n const { availableLocales, selectedLocales, setSelectedLocales } =\n useLocaleSwitcherContent();\n\n // 1. Memoize the list construction so it doesn't rebuild every render\n const multilingualAvailableLocales: MultilingualAvailableLocales[] = useMemo(\n () =>\n availableLocales.map((localeEl) => {\n const englishName = getLocaleName(localeEl, ENGLISH);\n const currentLocaleName = getLocaleName(localeEl, locale);\n const ownLocaleName = getLocaleName(localeEl);\n return {\n locale: localeEl,\n englishName,\n currentLocaleName,\n ownLocaleName,\n };\n }),\n [availableLocales, locale]\n );\n\n // 2. State for Search Query only (Source of Truth)\n const [searchQuery, setSearchQuery] = useState('');\n\n const [seeAllLocales, setSeeAllLocales] = usePersistedStore(\n 'locale-content-selector-see-all-locales',\n false\n );\n\n // 3. Memoize Fuse instance\n const fuse = useMemo(() => {\n const fuseOptions: IFuseOptions<MultilingualAvailableLocales> = {\n keys: [\n { name: 'ownLocaleName', weight: 0.4 },\n { name: 'englishName', weight: 0.2 },\n { name: 'currentLocaleName', weight: 0.2 },\n { name: 'locale', weight: 0.2 },\n ],\n threshold: 0.02,\n };\n return new Fuse(multilingualAvailableLocales, fuseOptions);\n }, [multilingualAvailableLocales]);\n\n // 4. Derive results from Search Query\n const results = useMemo(() => {\n if (!searchQuery) {\n return multilingualAvailableLocales;\n }\n return fuse.search(searchQuery).map((result) => result.item);\n }, [searchQuery, multilingualAvailableLocales, fuse]);\n\n const handleClickLocale = (localeItem: LocalesValues) => {\n if (isMultilingual) {\n if (selectedLocales.includes(localeItem)) {\n if (selectedLocales.length > 1) {\n setSelectedLocales((prev) => prev.filter((el) => el !== localeItem));\n }\n } else {\n setSelectedLocales((prev) => [...prev, localeItem]);\n }\n } else {\n setSelectedLocales([localeItem]);\n }\n };\n\n const handleSeeAllLocales = (value: boolean) => {\n setSeeAllLocales(value);\n\n if (value) {\n setSelectedLocales(availableLocales);\n } else {\n setSelectedLocales([locale]);\n }\n };\n\n return (\n <div className=\"rounded-xl border border-text text-text transition-colors\">\n <DropDown identifier={DROPDOWN_IDENTIFIER}>\n <DropDown.Trigger\n identifier={DROPDOWN_IDENTIFIER}\n label={localeSwitcherLabel.value}\n className=\"p-0!\"\n roundedSize=\"3xl\"\n color=\"text\"\n variant=\"hoverable\"\n >\n <div className=\"flex w-full items-center justify-between text-text\">\n <div className=\"px-2 py-1\">\n <Globe size={16} />\n </div>\n <MoveVertical className=\"self-center\" size={16} />\n </div>\n </DropDown.Trigger>\n\n <DropDown.Panel\n identifier={DROPDOWN_IDENTIFIER}\n isOverable\n isFocusable\n align=\"end\"\n {...panelProps}\n >\n <Container\n className=\"max-h-[60vh] min-w-28\"\n separator=\"y\"\n role=\"listbox\"\n transparency=\"xs\"\n border\n roundedSize=\"3xl\"\n borderColor=\"text\"\n aria-label={languageListLabel.value}\n >\n {isMultilingual && (\n <div className=\"m-auto p-2\">\n <SwitchSelector\n defaultValue={seeAllLocales} // Ensure this uses the persisted state\n onChange={handleSeeAllLocales}\n color=\"text\"\n size=\"sm\"\n className=\"!w-60\"\n choices={[\n {\n content: seeAllLocalesSwitch.true.value,\n value: true,\n },\n {\n content: seeAllLocalesSwitch.false.value,\n value: false,\n },\n ]}\n />\n </div>\n )}\n\n {!(isMultilingual && seeAllLocales) && (\n <>\n <div className=\"p-3\">\n <Input\n type=\"search\"\n aria-label={searchInput.ariaLabel.value}\n placeholder={searchInput.placeholder.value}\n // Update search query state directly\n onChange={(e) => setSearchQuery(e.target.value)}\n ref={inputRef}\n />\n </div>\n <ol className=\"divide-y divide-dashed divide-text/20 overflow-y-auto p-1\">\n {results.map(\n ({\n locale: localeItem,\n currentLocaleName,\n ownLocaleName,\n }) => (\n <li className=\"px-1.5 py-1\" key={localeItem}>\n <Button\n onClick={() => handleClickLocale(localeItem)}\n label={`${switchTo} ${currentLocaleName}`}\n disabled={\n !(availableLocales ?? availableLocales).includes(\n localeItem\n )\n }\n isActive={selectedLocales.includes(localeItem)}\n variant=\"hoverable\"\n color=\"text\"\n isFullWidth\n textAlign=\"left\"\n size=\"sm\"\n >\n <div className=\"flex flex-row items-center justify-between gap-3 px-2 py-1\">\n {isMultilingual && (\n <div className=\"w-4\">\n {selectedLocales.includes(localeItem) && (\n <Check className=\"size-full\" />\n )}\n </div>\n )}\n <div className=\"flex flex-1 flex-row items-center justify-between gap-3 px-2 py-1\">\n <div className=\"flex flex-col text-nowrap\">\n <span\n dir={getHTMLTextDir(localeItem)}\n lang={localeItem}\n >\n {ownLocaleName}\n </span>\n <span className=\"text-neutral text-xs\">\n {currentLocaleName}\n </span>\n </div>\n <span className=\"text-neutral text-sm\">\n {localeItem.toUpperCase()}\n </span>\n </div>\n </div>\n </Button>\n </li>\n )\n )}\n </ol>\n </>\n )}\n </Container>\n </DropDown.Panel>\n </DropDown>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"LocaleSwitcherContent.mjs","names":[],"sources":["../../../../src/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.tsx"],"sourcesContent":["'use client';\n\nimport { usePersistedStore } from '@hooks/usePersistedStore';\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core/localization';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport Fuse, { type IFuseOptions } from 'fuse.js';\nimport { Check, Globe, MoveVertical } from 'lucide-react';\nimport { type FC, useMemo, useRef, useState } from 'react';\nimport { useIntlayer, useLocale } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { Container } from '../Container';\nimport { DropDown, type PanelProps } from '../DropDown';\nimport { Input } from '../Input';\nimport { SwitchSelector } from '../SwitchSelector';\nimport { useLocaleSwitcherContent } from './LocaleSwitcherContentContext';\n\nexport type LocaleSwitcherContentProps = {\n panelProps?: Omit<PanelProps, 'identifier'>;\n isMultilingual?: boolean;\n};\n\nconst DROPDOWN_IDENTIFIER = 'locale-switcher-content';\n\ntype MultilingualAvailableLocales = {\n locale: LocalesValues;\n englishName: string;\n currentLocaleName: string;\n ownLocaleName: string;\n};\n\nexport const LocaleSwitcherContent: FC<LocaleSwitcherContentProps> = ({\n panelProps,\n isMultilingual = true,\n}) => {\n const {\n switchTo,\n searchInput,\n localeSwitcherLabel,\n languageListLabel,\n seeAllLocalesSwitch,\n } = useIntlayer('locale-switcher-content');\n const inputRef = useRef<HTMLInputElement>(null);\n const { locale } = useLocale();\n const { availableLocales, selectedLocales, setSelectedLocales } =\n useLocaleSwitcherContent();\n\n // 1. Memoize the list construction so it doesn't rebuild every render\n const multilingualAvailableLocales: MultilingualAvailableLocales[] = useMemo(\n () =>\n availableLocales.map((localeEl) => {\n const englishName = getLocaleName(localeEl, ENGLISH);\n const currentLocaleName = getLocaleName(localeEl, locale);\n const ownLocaleName = getLocaleName(localeEl);\n return {\n locale: localeEl,\n englishName,\n currentLocaleName,\n ownLocaleName,\n };\n }),\n [availableLocales, locale]\n );\n\n // 2. State for Search Query only (Source of Truth)\n const [searchQuery, setSearchQuery] = useState('');\n\n const [seeAllLocales, setSeeAllLocales] = usePersistedStore(\n 'locale-content-selector-see-all-locales',\n false\n );\n\n // 3. Memoize Fuse instance\n const fuse = useMemo(() => {\n const fuseOptions: IFuseOptions<MultilingualAvailableLocales> = {\n keys: [\n { name: 'ownLocaleName', weight: 0.4 },\n { name: 'englishName', weight: 0.2 },\n { name: 'currentLocaleName', weight: 0.2 },\n { name: 'locale', weight: 0.2 },\n ],\n threshold: 0.02,\n };\n return new Fuse(multilingualAvailableLocales, fuseOptions);\n }, [multilingualAvailableLocales]);\n\n // 4. Derive results from Search Query\n const results = useMemo(() => {\n if (!searchQuery) {\n return multilingualAvailableLocales;\n }\n return fuse.search(searchQuery).map((result) => result.item);\n }, [searchQuery, multilingualAvailableLocales, fuse]);\n\n const handleClickLocale = (localeItem: LocalesValues) => {\n if (isMultilingual) {\n if (selectedLocales.includes(localeItem)) {\n if (selectedLocales.length > 1) {\n setSelectedLocales((prev) => prev.filter((el) => el !== localeItem));\n }\n } else {\n setSelectedLocales((prev) => [...prev, localeItem]);\n }\n } else {\n setSelectedLocales([localeItem]);\n }\n };\n\n const handleSeeAllLocales = (value: boolean) => {\n setSeeAllLocales(value);\n\n if (value) {\n setSelectedLocales(availableLocales);\n } else {\n setSelectedLocales([locale]);\n }\n };\n\n return (\n <div className=\"rounded-xl border border-text text-foreground transition-colors\">\n <DropDown identifier={DROPDOWN_IDENTIFIER}>\n <DropDown.Trigger\n identifier={DROPDOWN_IDENTIFIER}\n label={localeSwitcherLabel.value}\n className=\"p-0!\"\n roundedSize=\"3xl\"\n color=\"text\"\n variant=\"hoverable\"\n >\n <div className=\"flex w-full items-center justify-between text-foreground\">\n <div className=\"px-2 py-1\">\n <Globe size={16} />\n </div>\n <MoveVertical className=\"self-center\" size={16} />\n </div>\n </DropDown.Trigger>\n\n <DropDown.Panel\n identifier={DROPDOWN_IDENTIFIER}\n isOverable\n isFocusable\n align=\"end\"\n {...panelProps}\n >\n <Container\n className=\"max-h-[60vh] min-w-28\"\n separator=\"y\"\n role=\"listbox\"\n transparency=\"xs\"\n border\n roundedSize=\"3xl\"\n borderColor=\"text\"\n aria-label={languageListLabel.value}\n >\n {isMultilingual && (\n <div className=\"m-auto p-2\">\n <SwitchSelector\n defaultValue={seeAllLocales} // Ensure this uses the persisted state\n onChange={handleSeeAllLocales}\n color=\"text\"\n size=\"sm\"\n className=\"!w-60\"\n choices={[\n {\n content: seeAllLocalesSwitch.true.value,\n value: true,\n },\n {\n content: seeAllLocalesSwitch.false.value,\n value: false,\n },\n ]}\n />\n </div>\n )}\n\n {!(isMultilingual && seeAllLocales) && (\n <>\n <div className=\"p-3\">\n <Input\n type=\"search\"\n aria-label={searchInput.ariaLabel.value}\n placeholder={searchInput.placeholder.value}\n // Update search query state directly\n onChange={(e) => setSearchQuery(e.target.value)}\n ref={inputRef}\n />\n </div>\n <ol className=\"divide-y divide-dashed divide-text/20 overflow-y-auto p-1\">\n {results.map(\n ({\n locale: localeItem,\n currentLocaleName,\n ownLocaleName,\n }) => (\n <li className=\"px-1.5 py-1\" key={localeItem}>\n <Button\n onClick={() => handleClickLocale(localeItem)}\n label={`${switchTo} ${currentLocaleName}`}\n disabled={\n !(availableLocales ?? availableLocales).includes(\n localeItem\n )\n }\n isActive={selectedLocales.includes(localeItem)}\n variant=\"hoverable\"\n color=\"text\"\n isFullWidth\n textAlign=\"left\"\n size=\"sm\"\n >\n <div className=\"flex flex-row items-center justify-between gap-3 px-2 py-1\">\n {isMultilingual && (\n <div className=\"w-4\">\n {selectedLocales.includes(localeItem) && (\n <Check className=\"size-full\" />\n )}\n </div>\n )}\n <div className=\"flex flex-1 flex-row items-center justify-between gap-3 px-2 py-1\">\n <div className=\"flex flex-col text-nowrap\">\n <span\n dir={getHTMLTextDir(localeItem)}\n lang={localeItem}\n >\n {ownLocaleName}\n </span>\n <span className=\"text-neutral text-xs\">\n {currentLocaleName}\n </span>\n </div>\n <span className=\"text-neutral text-sm\">\n {localeItem.toUpperCase()}\n </span>\n </div>\n </div>\n </Button>\n </li>\n )\n )}\n </ol>\n </>\n )}\n </Container>\n </DropDown.Panel>\n </DropDown>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -100,13 +100,18 @@ const EmbeddedFrame = ({ src, title, className, frameProps }) => {
100
100
  "aria-label": title ?? "Play video",
101
101
  onClick: () => setIsPlayRequested(true),
102
102
  className: cn("group relative block cursor-pointer border-0 bg-card p-0", className),
103
- children: [/* @__PURE__ */ jsx("img", {
103
+ children: [/* @__PURE__ */ jsxs("picture", { children: [/* @__PURE__ */ jsx("source", {
104
+ srcSet: `https://i.ytimg.com/vi_webp/${youtubeVideoId}/hqdefault.webp`,
105
+ type: "image/webp"
106
+ }), /* @__PURE__ */ jsx("img", {
104
107
  src: `https://i.ytimg.com/vi/${youtubeVideoId}/hqdefault.jpg`,
105
108
  alt: "",
109
+ width: 480,
110
+ height: 360,
106
111
  fetchPriority: "high",
107
112
  decoding: "async",
108
113
  className: "size-full object-cover"
109
- }), /* @__PURE__ */ jsx("span", {
114
+ })] }), /* @__PURE__ */ jsx("span", {
110
115
  className: "absolute inset-0 flex items-center justify-center",
111
116
  children: /* @__PURE__ */ jsx("span", {
112
117
  className: "flex size-14 items-center justify-center rounded-full bg-text/70 text-text-opposite transition-transform group-hover:scale-110",
@@ -158,7 +163,7 @@ const MarkDownIframe = (props) => {
158
163
  rel: "noopener noreferrer",
159
164
  label: "",
160
165
  color: "neutral",
161
- className: "inline-flex min-w-0 max-w-[calc(100%-3rem)] items-center gap-2 text-neutral text-xs underline-offset-2 hover:text-text hover:underline",
166
+ className: "inline-flex min-w-0 max-w-[calc(100%-3rem)] items-center gap-2 text-muted-foreground text-xs underline-offset-2 hover:text-foreground hover:underline",
162
167
  children: label
163
168
  }) : /* @__PURE__ */ jsx("span", {
164
169
  className: "text-neutral text-sm",