@thunderid/react 1.3.3 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/dist/cjs/components/presentation/ChangeCredential/BaseChangeCredential.cjs +1 -1
  2. package/dist/cjs/components/presentation/auth/AcceptInvite/BaseAcceptInvite.cjs +1 -1
  3. package/dist/cjs/components/presentation/auth/AcceptInvite/BaseAcceptInvite.cjs.map +1 -1
  4. package/dist/cjs/components/presentation/auth/AuthOptionFactory.cjs +56 -17
  5. package/dist/cjs/components/presentation/auth/AuthOptionFactory.cjs.map +1 -1
  6. package/dist/cjs/components/presentation/auth/InviteUser/BaseInviteUser.cjs +21 -5
  7. package/dist/cjs/components/presentation/auth/InviteUser/BaseInviteUser.cjs.map +1 -1
  8. package/dist/cjs/components/presentation/auth/InviteUser/InviteUser.cjs +6 -0
  9. package/dist/cjs/components/presentation/auth/InviteUser/InviteUser.cjs.map +1 -1
  10. package/dist/cjs/components/presentation/auth/SignIn/BaseSignIn.cjs +1 -0
  11. package/dist/cjs/components/presentation/auth/SignIn/BaseSignIn.cjs.map +1 -1
  12. package/dist/cjs/components/presentation/auth/SignIn/SignIn.cjs +2 -3
  13. package/dist/cjs/components/presentation/auth/SignIn/SignIn.cjs.map +1 -1
  14. package/dist/cjs/components/presentation/auth/SignUp/BaseSignUp.cjs +1 -0
  15. package/dist/cjs/components/presentation/auth/SignUp/BaseSignUp.cjs.map +1 -1
  16. package/dist/cjs/components/primitives/AffixedField/AffixedField.cjs +11 -1
  17. package/dist/cjs/components/primitives/AffixedField/AffixedField.cjs.map +1 -1
  18. package/dist/cjs/components/primitives/AuthFlowSelect/AuthFlowSelect.cjs +21 -0
  19. package/dist/cjs/components/primitives/AuthFlowSelect/AuthFlowSelect.cjs.map +1 -0
  20. package/dist/cjs/components/primitives/AuthFlowSelect/BaseAuthFlowSelect.cjs +32 -0
  21. package/dist/cjs/components/primitives/AuthFlowSelect/BaseAuthFlowSelect.cjs.map +1 -0
  22. package/dist/cjs/components/primitives/Checkbox/Checkbox.cjs +11 -1
  23. package/dist/cjs/components/primitives/Checkbox/Checkbox.cjs.map +1 -1
  24. package/dist/cjs/components/primitives/CopyableText/CopyableText.cjs +41 -21
  25. package/dist/cjs/components/primitives/CopyableText/CopyableText.cjs.map +1 -1
  26. package/dist/cjs/components/primitives/CopyableText/CopyableText.styles.cjs +5 -2
  27. package/dist/cjs/components/primitives/CopyableText/CopyableText.styles.cjs.map +1 -1
  28. package/dist/cjs/components/primitives/DatePicker/DatePicker.cjs +11 -1
  29. package/dist/cjs/components/primitives/DatePicker/DatePicker.cjs.map +1 -1
  30. package/dist/cjs/components/primitives/FormControl/FormControl.cjs +2 -1
  31. package/dist/cjs/components/primitives/FormControl/FormControl.cjs.map +1 -1
  32. package/dist/cjs/components/primitives/Icons/Copy.cjs +33 -0
  33. package/dist/cjs/components/primitives/Icons/Copy.cjs.map +1 -0
  34. package/dist/cjs/components/primitives/MultiInput/MultiInput.cjs +11 -2
  35. package/dist/cjs/components/primitives/MultiInput/MultiInput.cjs.map +1 -1
  36. package/dist/cjs/components/primitives/OtpField/OtpField.cjs +9 -0
  37. package/dist/cjs/components/primitives/OtpField/OtpField.cjs.map +1 -1
  38. package/dist/cjs/components/primitives/PasswordField/PasswordField.cjs +2 -1
  39. package/dist/cjs/components/primitives/PasswordField/PasswordField.cjs.map +1 -1
  40. package/dist/cjs/components/primitives/Select/ResourceSelect.cjs +104 -0
  41. package/dist/cjs/components/primitives/Select/ResourceSelect.cjs.map +1 -0
  42. package/dist/cjs/components/primitives/Select/Select.cjs +80 -21
  43. package/dist/cjs/components/primitives/Select/Select.cjs.map +1 -1
  44. package/dist/cjs/components/primitives/Select/Select.styles.cjs +19 -3
  45. package/dist/cjs/components/primitives/Select/Select.styles.cjs.map +1 -1
  46. package/dist/cjs/components/primitives/Select/useSelectMessages.cjs +21 -0
  47. package/dist/cjs/components/primitives/Select/useSelectMessages.cjs.map +1 -0
  48. package/dist/cjs/components/primitives/TextField/TextField.cjs +30 -4
  49. package/dist/cjs/components/primitives/TextField/TextField.cjs.map +1 -1
  50. package/dist/cjs/components/primitives/TextField/TextField.styles.cjs +18 -5
  51. package/dist/cjs/components/primitives/TextField/TextField.styles.cjs.map +1 -1
  52. package/dist/cjs/components/primitives/Toggle/Toggle.cjs +10 -1
  53. package/dist/cjs/components/primitives/Toggle/Toggle.cjs.map +1 -1
  54. package/dist/cjs/components/primitives/UserSelect/BaseUserSelect.cjs +33 -0
  55. package/dist/cjs/components/primitives/UserSelect/BaseUserSelect.cjs.map +1 -0
  56. package/dist/cjs/components/primitives/UserSelect/UserSelect.cjs +21 -0
  57. package/dist/cjs/components/primitives/UserSelect/UserSelect.cjs.map +1 -0
  58. package/dist/cjs/components/primitives/UserTypeSelect/BaseUserTypeSelect.cjs +31 -0
  59. package/dist/cjs/components/primitives/UserTypeSelect/BaseUserTypeSelect.cjs.map +1 -0
  60. package/dist/cjs/components/primitives/UserTypeSelect/UserTypeSelect.cjs +21 -0
  61. package/dist/cjs/components/primitives/UserTypeSelect/UserTypeSelect.cjs.map +1 -0
  62. package/dist/cjs/contexts/Theme/ThemeProvider.cjs +1 -1
  63. package/dist/cjs/contexts/Theme/ThemeProvider.cjs.map +1 -1
  64. package/dist/cjs/contexts/ThunderID/ThunderIDContext.cjs.map +1 -1
  65. package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs +1 -1
  66. package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs.map +1 -1
  67. package/dist/cjs/hooks/useFetchAuthFlows.cjs +36 -0
  68. package/dist/cjs/hooks/useFetchAuthFlows.cjs.map +1 -0
  69. package/dist/cjs/hooks/useFetchUserTypes.cjs +34 -0
  70. package/dist/cjs/hooks/useFetchUserTypes.cjs.map +1 -0
  71. package/dist/cjs/hooks/useFetchUsers.cjs +35 -0
  72. package/dist/cjs/hooks/useFetchUsers.cjs.map +1 -0
  73. package/dist/cjs/hooks/useInfiniteOptions.cjs +129 -0
  74. package/dist/cjs/hooks/useInfiniteOptions.cjs.map +1 -0
  75. package/dist/cjs/hooks/useManagementEndpoint.cjs.map +1 -1
  76. package/dist/cjs/index.cjs +56 -0
  77. package/dist/cjs/utils/createAuthenticatedFetcher.cjs +1 -0
  78. package/dist/cjs/utils/createAuthenticatedFetcher.cjs.map +1 -1
  79. package/dist/components/presentation/ChangeCredential/BaseChangeCredential.js +1 -1
  80. package/dist/components/presentation/auth/AcceptInvite/BaseAcceptInvite.d.ts.map +1 -1
  81. package/dist/components/presentation/auth/AcceptInvite/BaseAcceptInvite.js +1 -1
  82. package/dist/components/presentation/auth/AcceptInvite/BaseAcceptInvite.js.map +1 -1
  83. package/dist/components/presentation/auth/AuthOptionFactory.d.ts +9 -1
  84. package/dist/components/presentation/auth/AuthOptionFactory.d.ts.map +1 -1
  85. package/dist/components/presentation/auth/AuthOptionFactory.js +56 -17
  86. package/dist/components/presentation/auth/AuthOptionFactory.js.map +1 -1
  87. package/dist/components/presentation/auth/InviteUser/BaseInviteUser.d.ts +18 -2
  88. package/dist/components/presentation/auth/InviteUser/BaseInviteUser.d.ts.map +1 -1
  89. package/dist/components/presentation/auth/InviteUser/BaseInviteUser.js +22 -6
  90. package/dist/components/presentation/auth/InviteUser/BaseInviteUser.js.map +1 -1
  91. package/dist/components/presentation/auth/InviteUser/InviteUser.d.ts +2 -1
  92. package/dist/components/presentation/auth/InviteUser/InviteUser.d.ts.map +1 -1
  93. package/dist/components/presentation/auth/InviteUser/InviteUser.js +6 -0
  94. package/dist/components/presentation/auth/InviteUser/InviteUser.js.map +1 -1
  95. package/dist/components/presentation/auth/SignIn/BaseSignIn.d.ts +4 -0
  96. package/dist/components/presentation/auth/SignIn/BaseSignIn.d.ts.map +1 -1
  97. package/dist/components/presentation/auth/SignIn/BaseSignIn.js +1 -0
  98. package/dist/components/presentation/auth/SignIn/BaseSignIn.js.map +1 -1
  99. package/dist/components/presentation/auth/SignIn/SignIn.d.ts.map +1 -1
  100. package/dist/components/presentation/auth/SignIn/SignIn.js +2 -3
  101. package/dist/components/presentation/auth/SignIn/SignIn.js.map +1 -1
  102. package/dist/components/presentation/auth/SignUp/BaseSignUp.d.ts +4 -0
  103. package/dist/components/presentation/auth/SignUp/BaseSignUp.d.ts.map +1 -1
  104. package/dist/components/presentation/auth/SignUp/BaseSignUp.js +1 -0
  105. package/dist/components/presentation/auth/SignUp/BaseSignUp.js.map +1 -1
  106. package/dist/components/primitives/AffixedField/AffixedField.d.ts.map +1 -1
  107. package/dist/components/primitives/AffixedField/AffixedField.js +11 -1
  108. package/dist/components/primitives/AffixedField/AffixedField.js.map +1 -1
  109. package/dist/components/primitives/AuthFlowSelect/AuthFlowSelect.d.ts +11 -0
  110. package/dist/components/primitives/AuthFlowSelect/AuthFlowSelect.d.ts.map +1 -0
  111. package/dist/components/primitives/AuthFlowSelect/AuthFlowSelect.js +19 -0
  112. package/dist/components/primitives/AuthFlowSelect/AuthFlowSelect.js.map +1 -0
  113. package/dist/components/primitives/AuthFlowSelect/BaseAuthFlowSelect.d.ts +14 -0
  114. package/dist/components/primitives/AuthFlowSelect/BaseAuthFlowSelect.d.ts.map +1 -0
  115. package/dist/components/primitives/AuthFlowSelect/BaseAuthFlowSelect.js +29 -0
  116. package/dist/components/primitives/AuthFlowSelect/BaseAuthFlowSelect.js.map +1 -0
  117. package/dist/components/primitives/Checkbox/Checkbox.d.ts.map +1 -1
  118. package/dist/components/primitives/Checkbox/Checkbox.js +10 -1
  119. package/dist/components/primitives/Checkbox/Checkbox.js.map +1 -1
  120. package/dist/components/primitives/CopyableText/CopyableText.d.ts +9 -0
  121. package/dist/components/primitives/CopyableText/CopyableText.d.ts.map +1 -1
  122. package/dist/components/primitives/CopyableText/CopyableText.js +40 -21
  123. package/dist/components/primitives/CopyableText/CopyableText.js.map +1 -1
  124. package/dist/components/primitives/CopyableText/CopyableText.styles.d.ts.map +1 -1
  125. package/dist/components/primitives/CopyableText/CopyableText.styles.js +5 -2
  126. package/dist/components/primitives/CopyableText/CopyableText.styles.js.map +1 -1
  127. package/dist/components/primitives/DatePicker/DatePicker.d.ts.map +1 -1
  128. package/dist/components/primitives/DatePicker/DatePicker.js +10 -1
  129. package/dist/components/primitives/DatePicker/DatePicker.js.map +1 -1
  130. package/dist/components/primitives/FormControl/FormControl.d.ts +4 -0
  131. package/dist/components/primitives/FormControl/FormControl.d.ts.map +1 -1
  132. package/dist/components/primitives/FormControl/FormControl.js +2 -1
  133. package/dist/components/primitives/FormControl/FormControl.js.map +1 -1
  134. package/dist/components/primitives/Icons/Copy.d.ts +7 -0
  135. package/dist/components/primitives/Icons/Copy.d.ts.map +1 -0
  136. package/dist/components/primitives/Icons/Copy.js +31 -0
  137. package/dist/components/primitives/Icons/Copy.js.map +1 -0
  138. package/dist/components/primitives/MultiInput/MultiInput.d.ts.map +1 -1
  139. package/dist/components/primitives/MultiInput/MultiInput.js +12 -3
  140. package/dist/components/primitives/MultiInput/MultiInput.js.map +1 -1
  141. package/dist/components/primitives/OtpField/OtpField.d.ts.map +1 -1
  142. package/dist/components/primitives/OtpField/OtpField.js +10 -1
  143. package/dist/components/primitives/OtpField/OtpField.js.map +1 -1
  144. package/dist/components/primitives/PasswordField/PasswordField.d.ts +9 -1
  145. package/dist/components/primitives/PasswordField/PasswordField.d.ts.map +1 -1
  146. package/dist/components/primitives/PasswordField/PasswordField.js +2 -1
  147. package/dist/components/primitives/PasswordField/PasswordField.js.map +1 -1
  148. package/dist/components/primitives/Select/ResourceSelect.d.ts +36 -0
  149. package/dist/components/primitives/Select/ResourceSelect.d.ts.map +1 -0
  150. package/dist/components/primitives/Select/ResourceSelect.js +100 -0
  151. package/dist/components/primitives/Select/ResourceSelect.js.map +1 -0
  152. package/dist/components/primitives/Select/Select.d.ts +22 -13
  153. package/dist/components/primitives/Select/Select.d.ts.map +1 -1
  154. package/dist/components/primitives/Select/Select.js +80 -22
  155. package/dist/components/primitives/Select/Select.js.map +1 -1
  156. package/dist/components/primitives/Select/Select.styles.d.ts.map +1 -1
  157. package/dist/components/primitives/Select/Select.styles.js +19 -3
  158. package/dist/components/primitives/Select/Select.styles.js.map +1 -1
  159. package/dist/components/primitives/Select/__tests__/selectTestUtils.d.ts +6 -0
  160. package/dist/components/primitives/Select/__tests__/selectTestUtils.d.ts.map +1 -0
  161. package/dist/components/primitives/Select/useSelectMessages.d.ts +9 -0
  162. package/dist/components/primitives/Select/useSelectMessages.d.ts.map +1 -0
  163. package/dist/components/primitives/Select/useSelectMessages.js +18 -0
  164. package/dist/components/primitives/Select/useSelectMessages.js.map +1 -0
  165. package/dist/components/primitives/TextField/TextField.d.ts +8 -0
  166. package/dist/components/primitives/TextField/TextField.d.ts.map +1 -1
  167. package/dist/components/primitives/TextField/TextField.js +29 -4
  168. package/dist/components/primitives/TextField/TextField.js.map +1 -1
  169. package/dist/components/primitives/TextField/TextField.styles.d.ts +2 -1
  170. package/dist/components/primitives/TextField/TextField.styles.d.ts.map +1 -1
  171. package/dist/components/primitives/TextField/TextField.styles.js +18 -5
  172. package/dist/components/primitives/TextField/TextField.styles.js.map +1 -1
  173. package/dist/components/primitives/Toggle/Toggle.d.ts.map +1 -1
  174. package/dist/components/primitives/Toggle/Toggle.js +9 -1
  175. package/dist/components/primitives/Toggle/Toggle.js.map +1 -1
  176. package/dist/components/primitives/UserSelect/BaseUserSelect.d.ts +15 -0
  177. package/dist/components/primitives/UserSelect/BaseUserSelect.d.ts.map +1 -0
  178. package/dist/components/primitives/UserSelect/BaseUserSelect.js +30 -0
  179. package/dist/components/primitives/UserSelect/BaseUserSelect.js.map +1 -0
  180. package/dist/components/primitives/UserSelect/UserSelect.d.ts +11 -0
  181. package/dist/components/primitives/UserSelect/UserSelect.d.ts.map +1 -0
  182. package/dist/components/primitives/UserSelect/UserSelect.js +19 -0
  183. package/dist/components/primitives/UserSelect/UserSelect.js.map +1 -0
  184. package/dist/components/primitives/UserTypeSelect/BaseUserTypeSelect.d.ts +14 -0
  185. package/dist/components/primitives/UserTypeSelect/BaseUserTypeSelect.d.ts.map +1 -0
  186. package/dist/components/primitives/UserTypeSelect/BaseUserTypeSelect.js +28 -0
  187. package/dist/components/primitives/UserTypeSelect/BaseUserTypeSelect.js.map +1 -0
  188. package/dist/components/primitives/UserTypeSelect/UserTypeSelect.d.ts +11 -0
  189. package/dist/components/primitives/UserTypeSelect/UserTypeSelect.d.ts.map +1 -0
  190. package/dist/components/primitives/UserTypeSelect/UserTypeSelect.js +19 -0
  191. package/dist/components/primitives/UserTypeSelect/UserTypeSelect.js.map +1 -0
  192. package/dist/contexts/Theme/ThemeProvider.d.ts.map +1 -1
  193. package/dist/contexts/Theme/ThemeProvider.js +1 -1
  194. package/dist/contexts/Theme/ThemeProvider.js.map +1 -1
  195. package/dist/contexts/ThunderID/ThunderIDContext.d.ts +4 -3
  196. package/dist/contexts/ThunderID/ThunderIDContext.d.ts.map +1 -1
  197. package/dist/contexts/ThunderID/ThunderIDContext.js.map +1 -1
  198. package/dist/contexts/ThunderID/ThunderIDProvider.d.ts.map +1 -1
  199. package/dist/contexts/ThunderID/ThunderIDProvider.js +1 -1
  200. package/dist/contexts/ThunderID/ThunderIDProvider.js.map +1 -1
  201. package/dist/hooks/useFetchAuthFlows.d.ts +9 -0
  202. package/dist/hooks/useFetchAuthFlows.d.ts.map +1 -0
  203. package/dist/hooks/useFetchAuthFlows.js +33 -0
  204. package/dist/hooks/useFetchAuthFlows.js.map +1 -0
  205. package/dist/hooks/useFetchUserTypes.d.ts +8 -0
  206. package/dist/hooks/useFetchUserTypes.d.ts.map +1 -0
  207. package/dist/hooks/useFetchUserTypes.js +31 -0
  208. package/dist/hooks/useFetchUserTypes.js.map +1 -0
  209. package/dist/hooks/useFetchUsers.d.ts +8 -0
  210. package/dist/hooks/useFetchUsers.d.ts.map +1 -0
  211. package/dist/hooks/useFetchUsers.js +32 -0
  212. package/dist/hooks/useFetchUsers.js.map +1 -0
  213. package/dist/hooks/useInfiniteOptions.d.ts +31 -0
  214. package/dist/hooks/useInfiniteOptions.d.ts.map +1 -0
  215. package/dist/hooks/useInfiniteOptions.js +126 -0
  216. package/dist/hooks/useInfiniteOptions.js.map +1 -0
  217. package/dist/hooks/useManagementEndpoint.d.ts +1 -1
  218. package/dist/hooks/useManagementEndpoint.d.ts.map +1 -1
  219. package/dist/hooks/useManagementEndpoint.js.map +1 -1
  220. package/dist/index.d.ts +18 -1
  221. package/dist/index.d.ts.map +1 -1
  222. package/dist/index.js +12 -2
  223. package/dist/utils/createAuthenticatedFetcher.d.ts.map +1 -1
  224. package/dist/utils/createAuthenticatedFetcher.js +1 -0
  225. package/dist/utils/createAuthenticatedFetcher.js.map +1 -1
  226. package/package.json +4 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Copy.js","names":["Copy: FC<SVGProps<SVGSVGElement>>"],"sources":["../../../../src/components/primitives/Icons/Copy.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {FC, SVGProps} from 'react';\n\n/**\n * Copy icon component.\n */\nconst Copy: FC<SVGProps<SVGSVGElement>> = (props: SVGProps<SVGSVGElement>) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n);\n\nexport default Copy;\n"],"mappings":";;;;;;AAQA,MAAMA,QAAqC,UACzC,qBAAC;CACC,OAAM;CACN,OAAM;CACN,QAAO;CACP,SAAQ;CACR,MAAK;CACL,QAAO;CACP,aAAY;CACZ,eAAc;CACd,gBAAe;CACf,GAAI;YAEJ,oBAAC;EAAK,OAAM;EAAK,QAAO;EAAK,GAAE;EAAI,GAAE;EAAI,IAAG;EAAI,IAAG;GAAM,EACzD,oBAAC,UAAK,GAAE,4DAA4D;EAChE;AAGR,mBAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"MultiInput.d.ts","sourceRoot":"","sources":["../../../../src/components/primitives/MultiInput/MultiInput.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAC,aAAa,EAAE,EAAE,EAA+B,SAAS,EAAwB,MAAM,OAAO,CAAC;AAUvG,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAChG,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;OAEG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAMD,QAAA,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CA8KnC,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"MultiInput.d.ts","sourceRoot":"","sources":["../../../../src/components/primitives/MultiInput/MultiInput.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAC,aAAa,EAAE,EAAE,EAA+B,SAAS,EAA+B,MAAM,OAAO,CAAC;AAU9G,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAChG,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;OAEG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAMD,QAAA,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CAoLnC,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -7,12 +7,14 @@ import DatePicker_default from "../DatePicker/DatePicker.js";
7
7
  import TextField_default from "../TextField/TextField.js";
8
8
  import MultiInput_styles_default from "./MultiInput.styles.js";
9
9
  import { bem, withVendorCSSClassPrefix } from "@thunderid/browser";
10
- import { useCallback, useState } from "react";
10
+ import { useCallback, useId, useState } from "react";
11
11
  import { jsx, jsxs } from "react/jsx-runtime";
12
12
 
13
13
  //#region src/components/primitives/MultiInput/MultiInput.tsx
14
14
  const MultiInput = ({ label, error, required, className, disabled, helperText, placeholder = "Enter value", values = [], onChange, type = "text", fieldType = "STRING", startIcon, endIcon, minFields = 1, maxFields, style = {} }) => {
15
15
  const { theme, colorScheme } = useTheme_default();
16
+ const inputId = useId();
17
+ const helperTextId = error || helperText ? `${inputId}-description` : void 0;
16
18
  const canAddMore = !maxFields || values.length < maxFields;
17
19
  const canRemove = values.length > minFields;
18
20
  const styles = MultiInput_styles_default(theme, colorScheme, !!disabled, !!error, canAddMore, canRemove);
@@ -54,10 +56,13 @@ const MultiInput = ({ label, error, required, className, disabled, helperText, p
54
56
  onEndIconClick();
55
57
  }
56
58
  };
59
+ const finalEndIcon = attachedEndIcon || endIcon;
57
60
  const commonProps = {
61
+ "aria-describedby": helperTextId,
58
62
  disabled,
59
- endIcon: attachedEndIcon || endIcon,
63
+ endIcon: finalEndIcon,
60
64
  error,
65
+ id: inputId,
61
66
  onChange: handleInputChange,
62
67
  onEndIconClick,
63
68
  onKeyDown: handleKeyDown,
@@ -84,7 +89,9 @@ const MultiInput = ({ label, error, required, className, disabled, helperText, p
84
89
  endIcon,
85
90
  error,
86
91
  fieldType,
87
- type
92
+ type,
93
+ inputId,
94
+ helperTextId
88
95
  ]);
89
96
  const [currentInputValue, setCurrentInputValue] = useState("");
90
97
  const handleInputSubmit = useCallback(() => {
@@ -96,9 +103,11 @@ const MultiInput = ({ label, error, required, className, disabled, helperText, p
96
103
  return /* @__PURE__ */ jsxs(FormControl_default, {
97
104
  error,
98
105
  helperText,
106
+ helperTextId,
99
107
  className: cx(withVendorCSSClassPrefix(bem("multi-input")), className),
100
108
  style,
101
109
  children: [label && /* @__PURE__ */ jsx(InputLabel_default, {
110
+ htmlFor: inputId,
102
111
  required,
103
112
  error: !!error,
104
113
  children: label
@@ -1 +1 @@
1
- {"version":3,"file":"MultiInput.js","names":["MultiInput: FC<MultiInputProps>","useTheme","canAddMore: boolean","canRemove: boolean","styles: Record<string, string>","useStyles","PlusIcon: FC<IconProps>","BinIcon: FC<IconProps>","handleAddValue: ReturnType<typeof useCallback>","handleRemoveValue: ReturnType<typeof useCallback>","renderInputField: ReturnType<typeof useCallback>","commonProps: Record<string, unknown>","DatePicker","Checkbox","TextField","handleInputSubmit: ReturnType<typeof useCallback>","FormControl","InputLabel"],"sources":["../../../../src/components/primitives/MultiInput/MultiInput.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {CSSProperties, FC, KeyboardEvent, ReactElement, ReactNode, useCallback, useState} from 'react';\nimport useStyles from './MultiInput.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport Checkbox from '../Checkbox/Checkbox';\nimport DatePicker from '../DatePicker/DatePicker';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\nimport TextField from '../TextField/TextField';\n\nexport type MultiInputType = 'text' | 'email' | 'tel' | 'url' | 'password' | 'date' | 'boolean';\nexport type MultiInputFieldType = 'STRING' | 'DATE_TIME' | 'BOOLEAN';\n\nexport interface MultiInputProps {\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Whether the field is disabled\n */\n disabled?: boolean;\n /**\n * Icon to display at the end (right) of each input (in addition to add/remove buttons)\n */\n endIcon?: ReactNode;\n /**\n * Error message to display below the inputs\n */\n error?: string;\n /**\n * Field type for different input components\n */\n fieldType?: MultiInputFieldType;\n /**\n * Helper text to display below the inputs\n */\n helperText?: string;\n /**\n * Label text to display above the inputs\n */\n label?: string;\n /**\n * Maximum number of fields to allow (default: unlimited)\n */\n maxFields?: number;\n /**\n * Minimum number of fields to show (default: 1)\n */\n minFields?: number;\n /**\n * Callback when values change\n */\n onChange: (values: string[]) => void;\n /**\n * Placeholder text for input fields\n */\n placeholder?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n /**\n * Icon to display at the start (left) of each input\n */\n startIcon?: ReactNode;\n /**\n * Custom style object\n */\n style?: CSSProperties;\n /**\n * Input type\n */\n type?: MultiInputType;\n /**\n * Array of values\n */\n values: string[];\n}\n\ninterface IconProps {\n iconClassName?: string;\n}\n\nconst MultiInput: FC<MultiInputProps> = ({\n label,\n error,\n required,\n className,\n disabled,\n helperText,\n placeholder = 'Enter value',\n values = [],\n onChange,\n type = 'text',\n fieldType = 'STRING',\n startIcon,\n endIcon,\n minFields = 1,\n maxFields,\n style = {},\n}: MultiInputProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const canAddMore: boolean = !maxFields || values.length < maxFields;\n const canRemove: boolean = values.length > minFields;\n const styles: Record<string, string> = useStyles(theme, colorScheme, !!disabled, !!error, canAddMore, canRemove);\n\n const PlusIcon: FC<IconProps> = ({iconClassName}: IconProps): ReactElement => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" className={cx(styles['icon'], iconClassName)}>\n <path d=\"M12 5v14M5 12h14\" />\n </svg>\n );\n\n const BinIcon: FC<IconProps> = ({iconClassName}: IconProps): ReactElement => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" className={cx(styles['icon'], iconClassName)}>\n <path d=\"M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6h14ZM10 11v6M14 11v6\" />\n </svg>\n );\n\n const handleAddValue: ReturnType<typeof useCallback> = useCallback(\n (newValue: string) => {\n if (newValue.trim() !== '' && (!maxFields || values.length < maxFields)) {\n onChange([...values, newValue.trim()]);\n }\n },\n [values, onChange, maxFields],\n );\n\n const handleRemoveValue: ReturnType<typeof useCallback> = useCallback(\n (index: number) => {\n if (values.length > minFields) {\n const updatedValues: string[] = values.filter((_: string, i: number) => i !== index);\n onChange(updatedValues);\n }\n },\n [values, onChange, minFields],\n );\n\n const renderInputField: ReturnType<typeof useCallback> = useCallback(\n (\n value: string,\n onValueChange: (value: string) => void,\n attachedEndIcon?: ReactNode,\n onEndIconClick?: () => void,\n ): ReactElement => {\n const handleInputChange = (e: any): void => {\n const newValue: string = e.target ? e.target.value : e;\n onValueChange(newValue);\n };\n\n const handleKeyDown = (e: KeyboardEvent): void => {\n if (e.key === 'Enter' && onEndIconClick) {\n e.preventDefault();\n onEndIconClick();\n }\n };\n\n const finalEndIcon: ReactNode = attachedEndIcon || endIcon;\n\n const commonProps: Record<string, unknown> = {\n disabled,\n endIcon: finalEndIcon,\n error,\n onChange: handleInputChange,\n onEndIconClick,\n onKeyDown: handleKeyDown,\n placeholder,\n startIcon,\n value,\n };\n\n switch (fieldType) {\n case 'DATE_TIME':\n return <DatePicker {...commonProps} />;\n case 'BOOLEAN':\n return (\n <Checkbox\n {...commonProps}\n checked={value === 'true' || Boolean(value)}\n onChange={(e: any): void => onValueChange(e.target.checked ? 'true' : 'false')}\n />\n );\n default:\n return <TextField {...commonProps} type={type} />;\n }\n },\n [placeholder, disabled, startIcon, endIcon, error, fieldType, type],\n );\n\n // State for the current input value\n const [currentInputValue, setCurrentInputValue] = useState('');\n\n const handleInputSubmit: ReturnType<typeof useCallback> = useCallback((): void => {\n if (currentInputValue.trim() !== '') {\n handleAddValue(currentInputValue);\n setCurrentInputValue('');\n }\n }, [currentInputValue, handleAddValue]);\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n className={cx(withVendorCSSClassPrefix(bem('multi-input')), className)}\n style={style}\n >\n {label && (\n <InputLabel required={required} error={!!error}>\n {label}\n </InputLabel>\n )}\n <div className={cx(withVendorCSSClassPrefix(bem('multi-input', 'container')), styles['container'])}>\n {/* Input field at the top */}\n <div className={cx(withVendorCSSClassPrefix(bem('multi-input', 'input-row')), styles['inputRow'])}>\n <div className={cx(withVendorCSSClassPrefix(bem('multi-input', 'input-wrapper')), styles['inputWrapper'])}>\n {renderInputField(\n currentInputValue,\n setCurrentInputValue,\n canAddMore ? <PlusIcon iconClassName={styles['plusIcon']} /> : undefined,\n canAddMore ? handleInputSubmit : undefined,\n )}\n </div>\n </div>\n\n {/* List of added items */}\n {values.length > 0 && (\n <div className={cx(withVendorCSSClassPrefix(bem('multi-input', 'list-container')), styles['listContainer'])}>\n {values.map((value: string, index: number) => (\n <div\n key={index}\n className={cx(withVendorCSSClassPrefix(bem('multi-input', 'list-item')), styles['listItem'])}\n >\n <span\n className={cx(withVendorCSSClassPrefix(bem('multi-input', 'list-item-text')), styles['listItemText'])}\n >\n {value}\n </span>\n {canRemove && (\n <button\n type=\"button\"\n onClick={(): void => handleRemoveValue(index)}\n disabled={disabled}\n className={cx(\n withVendorCSSClassPrefix(bem('multi-input', 'remove-button')),\n styles['removeButton'],\n )}\n title=\"Remove value\"\n >\n <BinIcon iconClassName={styles['icon']} />\n </button>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n </FormControl>\n );\n};\n\nexport default MultiInput;\n"],"mappings":"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"}
1
+ {"version":3,"file":"MultiInput.js","names":["MultiInput: FC<MultiInputProps>","useTheme","inputId: string","helperTextId: string | undefined","canAddMore: boolean","canRemove: boolean","styles: Record<string, string>","useStyles","PlusIcon: FC<IconProps>","BinIcon: FC<IconProps>","handleAddValue: ReturnType<typeof useCallback>","handleRemoveValue: ReturnType<typeof useCallback>","renderInputField: ReturnType<typeof useCallback>","finalEndIcon: ReactNode","commonProps: Record<string, unknown>","DatePicker","Checkbox","TextField","handleInputSubmit: ReturnType<typeof useCallback>","FormControl","InputLabel"],"sources":["../../../../src/components/primitives/MultiInput/MultiInput.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {CSSProperties, FC, KeyboardEvent, ReactElement, ReactNode, useCallback, useId, useState} from 'react';\nimport useStyles from './MultiInput.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport Checkbox from '../Checkbox/Checkbox';\nimport DatePicker from '../DatePicker/DatePicker';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\nimport TextField from '../TextField/TextField';\n\nexport type MultiInputType = 'text' | 'email' | 'tel' | 'url' | 'password' | 'date' | 'boolean';\nexport type MultiInputFieldType = 'STRING' | 'DATE_TIME' | 'BOOLEAN';\n\nexport interface MultiInputProps {\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Whether the field is disabled\n */\n disabled?: boolean;\n /**\n * Icon to display at the end (right) of each input (in addition to add/remove buttons)\n */\n endIcon?: ReactNode;\n /**\n * Error message to display below the inputs\n */\n error?: string;\n /**\n * Field type for different input components\n */\n fieldType?: MultiInputFieldType;\n /**\n * Helper text to display below the inputs\n */\n helperText?: string;\n /**\n * Label text to display above the inputs\n */\n label?: string;\n /**\n * Maximum number of fields to allow (default: unlimited)\n */\n maxFields?: number;\n /**\n * Minimum number of fields to show (default: 1)\n */\n minFields?: number;\n /**\n * Callback when values change\n */\n onChange: (values: string[]) => void;\n /**\n * Placeholder text for input fields\n */\n placeholder?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n /**\n * Icon to display at the start (left) of each input\n */\n startIcon?: ReactNode;\n /**\n * Custom style object\n */\n style?: CSSProperties;\n /**\n * Input type\n */\n type?: MultiInputType;\n /**\n * Array of values\n */\n values: string[];\n}\n\ninterface IconProps {\n iconClassName?: string;\n}\n\nconst MultiInput: FC<MultiInputProps> = ({\n label,\n error,\n required,\n className,\n disabled,\n helperText,\n placeholder = 'Enter value',\n values = [],\n onChange,\n type = 'text',\n fieldType = 'STRING',\n startIcon,\n endIcon,\n minFields = 1,\n maxFields,\n style = {},\n}: MultiInputProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const inputId: string = useId();\n // The inner field renders its own helper text with `${inputId}-helper-text`, so this one needs a distinct id.\n const helperTextId: string | undefined = error || helperText ? `${inputId}-description` : undefined;\n const canAddMore: boolean = !maxFields || values.length < maxFields;\n const canRemove: boolean = values.length > minFields;\n const styles: Record<string, string> = useStyles(theme, colorScheme, !!disabled, !!error, canAddMore, canRemove);\n\n const PlusIcon: FC<IconProps> = ({iconClassName}: IconProps): ReactElement => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" className={cx(styles['icon'], iconClassName)}>\n <path d=\"M12 5v14M5 12h14\" />\n </svg>\n );\n\n const BinIcon: FC<IconProps> = ({iconClassName}: IconProps): ReactElement => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" className={cx(styles['icon'], iconClassName)}>\n <path d=\"M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6h14ZM10 11v6M14 11v6\" />\n </svg>\n );\n\n const handleAddValue: ReturnType<typeof useCallback> = useCallback(\n (newValue: string) => {\n if (newValue.trim() !== '' && (!maxFields || values.length < maxFields)) {\n onChange([...values, newValue.trim()]);\n }\n },\n [values, onChange, maxFields],\n );\n\n const handleRemoveValue: ReturnType<typeof useCallback> = useCallback(\n (index: number) => {\n if (values.length > minFields) {\n const updatedValues: string[] = values.filter((_: string, i: number) => i !== index);\n onChange(updatedValues);\n }\n },\n [values, onChange, minFields],\n );\n\n const renderInputField: ReturnType<typeof useCallback> = useCallback(\n (\n value: string,\n onValueChange: (value: string) => void,\n attachedEndIcon?: ReactNode,\n onEndIconClick?: () => void,\n ): ReactElement => {\n const handleInputChange = (e: any): void => {\n const newValue: string = e.target ? e.target.value : e;\n onValueChange(newValue);\n };\n\n const handleKeyDown = (e: KeyboardEvent): void => {\n if (e.key === 'Enter' && onEndIconClick) {\n e.preventDefault();\n onEndIconClick();\n }\n };\n\n const finalEndIcon: ReactNode = attachedEndIcon || endIcon;\n\n const commonProps: Record<string, unknown> = {\n 'aria-describedby': helperTextId,\n disabled,\n endIcon: finalEndIcon,\n error,\n id: inputId,\n onChange: handleInputChange,\n onEndIconClick,\n onKeyDown: handleKeyDown,\n placeholder,\n startIcon,\n value,\n };\n\n switch (fieldType) {\n case 'DATE_TIME':\n return <DatePicker {...commonProps} />;\n case 'BOOLEAN':\n return (\n <Checkbox\n {...commonProps}\n checked={value === 'true' || Boolean(value)}\n onChange={(e: any): void => onValueChange(e.target.checked ? 'true' : 'false')}\n />\n );\n default:\n return <TextField {...commonProps} type={type} />;\n }\n },\n [placeholder, disabled, startIcon, endIcon, error, fieldType, type, inputId, helperTextId],\n );\n\n // State for the current input value\n const [currentInputValue, setCurrentInputValue] = useState('');\n\n const handleInputSubmit: ReturnType<typeof useCallback> = useCallback((): void => {\n if (currentInputValue.trim() !== '') {\n handleAddValue(currentInputValue);\n setCurrentInputValue('');\n }\n }, [currentInputValue, handleAddValue]);\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n helperTextId={helperTextId}\n className={cx(withVendorCSSClassPrefix(bem('multi-input')), className)}\n style={style}\n >\n {label && (\n <InputLabel htmlFor={inputId} required={required} error={!!error}>\n {label}\n </InputLabel>\n )}\n <div className={cx(withVendorCSSClassPrefix(bem('multi-input', 'container')), styles['container'])}>\n {/* Input field at the top */}\n <div className={cx(withVendorCSSClassPrefix(bem('multi-input', 'input-row')), styles['inputRow'])}>\n <div className={cx(withVendorCSSClassPrefix(bem('multi-input', 'input-wrapper')), styles['inputWrapper'])}>\n {renderInputField(\n currentInputValue,\n setCurrentInputValue,\n canAddMore ? <PlusIcon iconClassName={styles['plusIcon']} /> : undefined,\n canAddMore ? handleInputSubmit : undefined,\n )}\n </div>\n </div>\n\n {/* List of added items */}\n {values.length > 0 && (\n <div className={cx(withVendorCSSClassPrefix(bem('multi-input', 'list-container')), styles['listContainer'])}>\n {values.map((value: string, index: number) => (\n <div\n key={index}\n className={cx(withVendorCSSClassPrefix(bem('multi-input', 'list-item')), styles['listItem'])}\n >\n <span\n className={cx(withVendorCSSClassPrefix(bem('multi-input', 'list-item-text')), styles['listItemText'])}\n >\n {value}\n </span>\n {canRemove && (\n <button\n type=\"button\"\n onClick={(): void => handleRemoveValue(index)}\n disabled={disabled}\n className={cx(\n withVendorCSSClassPrefix(bem('multi-input', 'remove-button')),\n styles['removeButton'],\n )}\n title=\"Remove value\"\n >\n <BinIcon iconClassName={styles['icon']} />\n </button>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n </FormControl>\n );\n};\n\nexport default MultiInput;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"OtpField.d.ts","sourceRoot":"","sources":["../../../../src/components/primitives/OtpField/OtpField.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,EAAE,EAOF,aAAa,EACd,MAAM,OAAO,CAAC;AAOf,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE;QAAC,MAAM,EAAE;YAAC,KAAK,EAAE,MAAM,CAAA;SAAC,CAAA;KAAC,KAAK,IAAI,CAAC;IACtD;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;OAEG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,QAAA,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CAmL/B,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"OtpField.d.ts","sourceRoot":"","sources":["../../../../src/components/primitives/OtpField/OtpField.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,EAAE,EAOF,aAAa,EAEd,MAAM,OAAO,CAAC;AAOf,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE;QAAC,MAAM,EAAE;YAAC,KAAK,EAAE,MAAM,CAAA;SAAC,CAAA;KAAC,KAAK,IAAI,CAAC;IACtD;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;OAEG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,QAAA,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CA6L/B,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -4,7 +4,7 @@ import FormControl_default from "../FormControl/FormControl.js";
4
4
  import InputLabel_default from "../InputLabel/InputLabel.js";
5
5
  import OtpField_styles_default from "./OtpField.styles.js";
6
6
  import { bem, withVendorCSSClassPrefix } from "@thunderid/browser";
7
- import { useEffect, useRef, useState } from "react";
7
+ import { useEffect, useId, useRef, useState } from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
9
 
10
10
  //#region src/components/primitives/OtpField/OtpField.tsx
@@ -13,6 +13,9 @@ const OtpField = ({ label, error, className, required, disabled, helperText, len
13
13
  const styles = OtpField_styles_default(theme, colorScheme, !!disabled, !!error, length);
14
14
  const [otp, setOtp] = useState(Array(length).fill(""));
15
15
  const inputRefs = useRef([]);
16
+ const fieldId = useId();
17
+ const labelId = `${fieldId}-label`;
18
+ const helperTextId = error || helperText ? `${fieldId}-helper-text` : void 0;
16
19
  useEffect(() => {
17
20
  inputRefs.current = inputRefs.current.slice(0, length);
18
21
  }, [length]);
@@ -82,14 +85,19 @@ const OtpField = ({ label, error, className, required, disabled, helperText, len
82
85
  return /* @__PURE__ */ jsxs(FormControl_default, {
83
86
  error,
84
87
  helperText,
88
+ helperTextId,
85
89
  className: cx(withVendorCSSClassPrefix(bem("otp-field")), className),
86
90
  helperTextAlign: "center",
87
91
  style,
88
92
  children: [label && /* @__PURE__ */ jsx(InputLabel_default, {
93
+ id: labelId,
89
94
  required,
90
95
  error: !!error,
91
96
  children: label
92
97
  }), /* @__PURE__ */ jsx("div", {
98
+ role: "group",
99
+ "aria-labelledby": label ? labelId : void 0,
100
+ "aria-describedby": helperTextId,
93
101
  className: cx(withVendorCSSClassPrefix(bem("otp-field", "input-container")), styles["inputContainer"]),
94
102
  children: Array.from({ length }, (_, index) => /* @__PURE__ */ jsx("input", {
95
103
  ref: (el) => {
@@ -113,6 +121,7 @@ const OtpField = ({ label, error, className, required, disabled, helperText, len
113
121
  "aria-label": `${label || "OTP"} digit ${index + 1}`,
114
122
  "aria-invalid": !!error,
115
123
  "aria-required": required,
124
+ "aria-describedby": helperTextId,
116
125
  autoComplete: "one-time-code"
117
126
  }, index))
118
127
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"OtpField.js","names":["OtpField: FC<OtpInputProps>","useTheme","styles: Record<string, string>","useStyles","inputRefs: MutableRefObject<HTMLInputElement[]>","newOtp: string[]","newValue: string","otpValue: string","rawData: string","pastedData: string","nextEmptyIndex: number","focusIndex: number","FormControl","InputLabel"],"sources":["../../../../src/components/primitives/OtpField/OtpField.tsx"],"sourcesContent":["// Copyright 2024 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {\n ClipboardEvent,\n FC,\n KeyboardEvent,\n ChangeEvent,\n MutableRefObject,\n useRef,\n useEffect,\n useState,\n CSSProperties,\n} from 'react';\nimport useStyles from './OtpField.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\n\nexport type OtpFieldType = 'text' | 'number' | 'password';\n\nexport interface OtpInputProps {\n /**\n * Auto focus the first input on mount\n */\n autoFocus?: boolean;\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Whether the field is disabled\n */\n disabled?: boolean;\n /**\n * Error message to display below the OTP input\n */\n error?: string;\n /**\n * Helper text to display below the OTP input\n */\n helperText?: string;\n /**\n * Label text to display above the OTP input\n */\n label?: string;\n /**\n * Number of OTP input fields\n */\n length?: number;\n /**\n * Callback function called when OTP value changes\n */\n onChange?: (event: {target: {value: string}}) => void;\n /**\n * Callback function called when OTP input is complete\n */\n onComplete?: (value: string) => void;\n /**\n * Pattern for numeric input validation\n */\n pattern?: string;\n /**\n * Placeholder character for each input field\n */\n placeholder?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n /**\n * Custom container style\n */\n style?: CSSProperties;\n /**\n * Type of input (text, number, password)\n */\n type?: OtpFieldType;\n /**\n * Upper-case entered characters before emitting them\n */\n uppercase?: boolean;\n /**\n * Current OTP value\n */\n value?: string;\n}\n\nconst OtpField: FC<OtpInputProps> = ({\n label,\n error,\n className,\n required,\n disabled,\n helperText,\n length = 6,\n value = '',\n onChange,\n onComplete,\n type = 'text',\n placeholder = '',\n style = {},\n autoFocus = false,\n pattern,\n uppercase = false,\n}: OtpInputProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme, !!disabled, !!error, length);\n const [otp, setOtp] = useState<string[]>(Array(length).fill(''));\n const inputRefs: MutableRefObject<HTMLInputElement[]> = useRef<HTMLInputElement[]>([]);\n\n useEffect(() => {\n inputRefs.current = inputRefs.current.slice(0, length);\n }, [length]);\n\n useEffect(() => {\n if (value) {\n const newOtp: string[] = value.split('').slice(0, length);\n while (newOtp.length < length) {\n newOtp.push('');\n }\n setOtp(newOtp);\n } else {\n setOtp(Array(length).fill(''));\n }\n }, [value, length]);\n\n useEffect(() => {\n if (autoFocus && inputRefs.current[0]) {\n inputRefs.current[0].focus();\n }\n }, [autoFocus]);\n\n const handleChange = (index: number, event: ChangeEvent<HTMLInputElement>): void => {\n const newValue: string = uppercase ? event.target.value.toUpperCase() : event.target.value;\n\n if (newValue.length > 1) return;\n\n if (type === 'number' && newValue && !/^\\d$/.test(newValue)) return;\n\n if (pattern && newValue && !new RegExp(pattern).test(newValue)) return;\n\n const newOtp: string[] = [...otp];\n newOtp[index] = newValue;\n setOtp(newOtp);\n\n const otpValue: string = newOtp.join('');\n\n onChange?.({target: {value: otpValue}});\n\n if (newValue && index < length - 1) {\n inputRefs.current[index + 1]?.focus();\n }\n\n if (newOtp.every((digit: string) => digit !== '') && onComplete) {\n onComplete(otpValue);\n }\n };\n\n const handleKeyDown = (index: number, event: KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === 'Backspace') {\n if (!otp[index] && index > 0) {\n const newOtp: string[] = [...otp];\n\n newOtp[index - 1] = '';\n setOtp(newOtp);\n inputRefs.current[index - 1]?.focus();\n onChange?.({target: {value: newOtp.join('')}});\n } else if (otp[index]) {\n const newOtp: string[] = [...otp];\n\n newOtp[index] = '';\n setOtp(newOtp);\n onChange?.({target: {value: newOtp.join('')}});\n }\n } else if (event.key === 'ArrowLeft' && index > 0) {\n inputRefs.current[index - 1]?.focus();\n } else if (event.key === 'ArrowRight' && index < length - 1) {\n inputRefs.current[index + 1]?.focus();\n } else if (event.key === 'Enter') {\n event.preventDefault();\n\n if (otp.every((digit: string) => digit !== '') && onComplete) {\n onComplete(otp.join(''));\n }\n }\n };\n\n const handlePaste = (event: ClipboardEvent<HTMLInputElement>): void => {\n event.preventDefault();\n\n const rawData: string = event.clipboardData.getData('text');\n // Filter first and let the copy loop below bound the result, so surrounding text such as\n // \"Your code is 123456\" does not push the code itself past the cut-off.\n const pastedData: string = uppercase ? rawData.toUpperCase() : rawData;\n\n let validData = '';\n\n Array.from(pastedData).forEach((char: string) => {\n if (type === 'number' && !/^\\d$/.test(char)) return;\n if (pattern && !new RegExp(pattern).test(char)) return;\n validData += char;\n });\n\n const newOtp: string[] = Array(length).fill('');\n\n for (let i = 0; i < Math.min(validData.length, length); i += 1) {\n newOtp[i] = validData[i];\n }\n\n setOtp(newOtp);\n onChange?.({target: {value: newOtp.join('')}});\n\n const nextEmptyIndex: number = newOtp.findIndex((digit: string) => digit === '');\n const focusIndex: number = nextEmptyIndex !== -1 ? nextEmptyIndex : length - 1;\n\n inputRefs.current[focusIndex]?.focus();\n\n if (newOtp.every((digit: string) => digit !== '') && onComplete) {\n onComplete(newOtp.join(''));\n }\n };\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n className={cx(withVendorCSSClassPrefix(bem('otp-field')), className)}\n helperTextAlign=\"center\"\n style={style}\n >\n {label && (\n <InputLabel required={required} error={!!error}>\n {label}\n </InputLabel>\n )}\n <div className={cx(withVendorCSSClassPrefix(bem('otp-field', 'input-container')), styles['inputContainer'])}>\n {Array.from({length}, (_: unknown, index: number) => (\n <input\n key={index}\n ref={(el: HTMLInputElement | null): void => {\n if (el) inputRefs.current[index] = el;\n }}\n type={type === 'password' ? 'password' : 'text'}\n inputMode={type === 'number' ? 'numeric' : 'text'}\n value={otp[index] || ''}\n onChange={(event: ChangeEvent<HTMLInputElement>): void => handleChange(index, event)}\n onKeyDown={(event: KeyboardEvent<HTMLInputElement>): void => handleKeyDown(index, event)}\n onPaste={handlePaste}\n className={cx(withVendorCSSClassPrefix(bem('otp-field', 'input')), styles['input'], {\n [withVendorCSSClassPrefix(bem('otp-field', 'input', 'error'))]: !!error,\n [styles['inputError']]: !!error,\n [withVendorCSSClassPrefix(bem('otp-field', 'input', 'disabled'))]: !!disabled,\n [styles['inputDisabled']]: !!disabled,\n })}\n maxLength={1}\n placeholder={placeholder}\n disabled={disabled}\n aria-label={`${label || 'OTP'} digit ${index + 1}`}\n aria-invalid={!!error}\n aria-required={required}\n autoComplete=\"one-time-code\"\n />\n ))}\n </div>\n </FormControl>\n );\n};\n\nexport default OtpField;\n"],"mappings":"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"}
1
+ {"version":3,"file":"OtpField.js","names":["OtpField: FC<OtpInputProps>","useTheme","styles: Record<string, string>","useStyles","inputRefs: MutableRefObject<HTMLInputElement[]>","fieldId: string","helperTextId: string | undefined","newOtp: string[]","newValue: string","otpValue: string","rawData: string","pastedData: string","nextEmptyIndex: number","focusIndex: number","FormControl","InputLabel"],"sources":["../../../../src/components/primitives/OtpField/OtpField.tsx"],"sourcesContent":["// Copyright 2024 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {\n ClipboardEvent,\n FC,\n KeyboardEvent,\n ChangeEvent,\n MutableRefObject,\n useRef,\n useEffect,\n useState,\n CSSProperties,\n useId,\n} from 'react';\nimport useStyles from './OtpField.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\n\nexport type OtpFieldType = 'text' | 'number' | 'password';\n\nexport interface OtpInputProps {\n /**\n * Auto focus the first input on mount\n */\n autoFocus?: boolean;\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Whether the field is disabled\n */\n disabled?: boolean;\n /**\n * Error message to display below the OTP input\n */\n error?: string;\n /**\n * Helper text to display below the OTP input\n */\n helperText?: string;\n /**\n * Label text to display above the OTP input\n */\n label?: string;\n /**\n * Number of OTP input fields\n */\n length?: number;\n /**\n * Callback function called when OTP value changes\n */\n onChange?: (event: {target: {value: string}}) => void;\n /**\n * Callback function called when OTP input is complete\n */\n onComplete?: (value: string) => void;\n /**\n * Pattern for numeric input validation\n */\n pattern?: string;\n /**\n * Placeholder character for each input field\n */\n placeholder?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n /**\n * Custom container style\n */\n style?: CSSProperties;\n /**\n * Type of input (text, number, password)\n */\n type?: OtpFieldType;\n /**\n * Upper-case entered characters before emitting them\n */\n uppercase?: boolean;\n /**\n * Current OTP value\n */\n value?: string;\n}\n\nconst OtpField: FC<OtpInputProps> = ({\n label,\n error,\n className,\n required,\n disabled,\n helperText,\n length = 6,\n value = '',\n onChange,\n onComplete,\n type = 'text',\n placeholder = '',\n style = {},\n autoFocus = false,\n pattern,\n uppercase = false,\n}: OtpInputProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme, !!disabled, !!error, length);\n const [otp, setOtp] = useState<string[]>(Array(length).fill(''));\n const inputRefs: MutableRefObject<HTMLInputElement[]> = useRef<HTMLInputElement[]>([]);\n const fieldId: string = useId();\n const labelId = `${fieldId}-label`;\n const helperTextId: string | undefined = error || helperText ? `${fieldId}-helper-text` : undefined;\n\n useEffect(() => {\n inputRefs.current = inputRefs.current.slice(0, length);\n }, [length]);\n\n useEffect(() => {\n if (value) {\n const newOtp: string[] = value.split('').slice(0, length);\n while (newOtp.length < length) {\n newOtp.push('');\n }\n setOtp(newOtp);\n } else {\n setOtp(Array(length).fill(''));\n }\n }, [value, length]);\n\n useEffect(() => {\n if (autoFocus && inputRefs.current[0]) {\n inputRefs.current[0].focus();\n }\n }, [autoFocus]);\n\n const handleChange = (index: number, event: ChangeEvent<HTMLInputElement>): void => {\n const newValue: string = uppercase ? event.target.value.toUpperCase() : event.target.value;\n\n if (newValue.length > 1) return;\n\n if (type === 'number' && newValue && !/^\\d$/.test(newValue)) return;\n\n if (pattern && newValue && !new RegExp(pattern).test(newValue)) return;\n\n const newOtp: string[] = [...otp];\n newOtp[index] = newValue;\n setOtp(newOtp);\n\n const otpValue: string = newOtp.join('');\n\n onChange?.({target: {value: otpValue}});\n\n if (newValue && index < length - 1) {\n inputRefs.current[index + 1]?.focus();\n }\n\n if (newOtp.every((digit: string) => digit !== '') && onComplete) {\n onComplete(otpValue);\n }\n };\n\n const handleKeyDown = (index: number, event: KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === 'Backspace') {\n if (!otp[index] && index > 0) {\n const newOtp: string[] = [...otp];\n\n newOtp[index - 1] = '';\n setOtp(newOtp);\n inputRefs.current[index - 1]?.focus();\n onChange?.({target: {value: newOtp.join('')}});\n } else if (otp[index]) {\n const newOtp: string[] = [...otp];\n\n newOtp[index] = '';\n setOtp(newOtp);\n onChange?.({target: {value: newOtp.join('')}});\n }\n } else if (event.key === 'ArrowLeft' && index > 0) {\n inputRefs.current[index - 1]?.focus();\n } else if (event.key === 'ArrowRight' && index < length - 1) {\n inputRefs.current[index + 1]?.focus();\n } else if (event.key === 'Enter') {\n event.preventDefault();\n\n if (otp.every((digit: string) => digit !== '') && onComplete) {\n onComplete(otp.join(''));\n }\n }\n };\n\n const handlePaste = (event: ClipboardEvent<HTMLInputElement>): void => {\n event.preventDefault();\n\n const rawData: string = event.clipboardData.getData('text');\n // Filter first and let the copy loop below bound the result, so surrounding text such as\n // \"Your code is 123456\" does not push the code itself past the cut-off.\n const pastedData: string = uppercase ? rawData.toUpperCase() : rawData;\n\n let validData = '';\n\n Array.from(pastedData).forEach((char: string) => {\n if (type === 'number' && !/^\\d$/.test(char)) return;\n if (pattern && !new RegExp(pattern).test(char)) return;\n validData += char;\n });\n\n const newOtp: string[] = Array(length).fill('');\n\n for (let i = 0; i < Math.min(validData.length, length); i += 1) {\n newOtp[i] = validData[i];\n }\n\n setOtp(newOtp);\n onChange?.({target: {value: newOtp.join('')}});\n\n const nextEmptyIndex: number = newOtp.findIndex((digit: string) => digit === '');\n const focusIndex: number = nextEmptyIndex !== -1 ? nextEmptyIndex : length - 1;\n\n inputRefs.current[focusIndex]?.focus();\n\n if (newOtp.every((digit: string) => digit !== '') && onComplete) {\n onComplete(newOtp.join(''));\n }\n };\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n helperTextId={helperTextId}\n className={cx(withVendorCSSClassPrefix(bem('otp-field')), className)}\n helperTextAlign=\"center\"\n style={style}\n >\n {label && (\n <InputLabel id={labelId} required={required} error={!!error}>\n {label}\n </InputLabel>\n )}\n <div\n role=\"group\"\n aria-labelledby={label ? labelId : undefined}\n aria-describedby={helperTextId}\n className={cx(withVendorCSSClassPrefix(bem('otp-field', 'input-container')), styles['inputContainer'])}\n >\n {Array.from({length}, (_: unknown, index: number) => (\n <input\n key={index}\n ref={(el: HTMLInputElement | null): void => {\n if (el) inputRefs.current[index] = el;\n }}\n type={type === 'password' ? 'password' : 'text'}\n inputMode={type === 'number' ? 'numeric' : 'text'}\n value={otp[index] || ''}\n onChange={(event: ChangeEvent<HTMLInputElement>): void => handleChange(index, event)}\n onKeyDown={(event: KeyboardEvent<HTMLInputElement>): void => handleKeyDown(index, event)}\n onPaste={handlePaste}\n className={cx(withVendorCSSClassPrefix(bem('otp-field', 'input')), styles['input'], {\n [withVendorCSSClassPrefix(bem('otp-field', 'input', 'error'))]: !!error,\n [styles['inputError']]: !!error,\n [withVendorCSSClassPrefix(bem('otp-field', 'input', 'disabled'))]: !!disabled,\n [styles['inputDisabled']]: !!disabled,\n })}\n maxLength={1}\n placeholder={placeholder}\n disabled={disabled}\n aria-label={`${label || 'OTP'} digit ${index + 1}`}\n aria-invalid={!!error}\n aria-required={required}\n aria-describedby={helperTextId}\n autoComplete=\"one-time-code\"\n />\n ))}\n </div>\n </FormControl>\n );\n};\n\nexport default OtpField;\n"],"mappings":"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"}
@@ -1,16 +1,24 @@
1
1
  import { FC } from 'react';
2
2
  import { TextFieldProps } from '../TextField/TextField';
3
- export interface PasswordFieldProps extends Omit<TextFieldProps, 'type' | 'endIcon' | 'onEndIconClick' | 'onChange'> {
3
+ export interface PasswordFieldProps extends Omit<TextFieldProps, 'type' | 'endIcon' | 'endIconLabel' | 'onEndIconClick' | 'onChange'> {
4
4
  /**
5
5
  * The browser autofill hint. Defaults to `current-password`; set `new-password` on the
6
6
  * fields of a change-password or sign-up form so password managers offer to generate and
7
7
  * store a new credential instead of filling the existing one.
8
8
  */
9
9
  autoComplete?: string;
10
+ /**
11
+ * Accessible name of the toggle button while the password is visible
12
+ */
13
+ hideLabel?: string;
10
14
  /**
11
15
  * Callback function when the field value changes
12
16
  */
13
17
  onChange: (value: string) => void;
18
+ /**
19
+ * Accessible name of the toggle button while the password is hidden
20
+ */
21
+ showLabel?: string;
14
22
  }
15
23
  /**
16
24
  * Password field component with show/hide toggle functionality.
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordField.d.ts","sourceRoot":"","sources":["../../../../src/components/primitives/PasswordField/PasswordField.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAc,EAAE,EAAqB,MAAM,OAAO,CAAC;AAM1D,OAAkB,EAAC,cAAc,EAAC,MAAM,wBAAwB,CAAC;AAEjE,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,gBAAgB,GAAG,UAAU,CAAC;IAClH;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;GAGG;AACH,QAAA,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CA2CzC,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"PasswordField.d.ts","sourceRoot":"","sources":["../../../../src/components/primitives/PasswordField/PasswordField.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAc,EAAE,EAAqB,MAAM,OAAO,CAAC;AAM1D,OAAkB,EAAC,cAAc,EAAC,MAAM,wBAAwB,CAAC;AAEjE,MAAM,WAAW,kBACf,SAAQ,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,gBAAgB,GAAG,UAAU,CAAC;IACjG;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,QAAA,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CA8CzC,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -13,7 +13,7 @@ import { jsx } from "react/jsx-runtime";
13
13
  * Password field component with show/hide toggle functionality.
14
14
  * This component extends TextField and adds password visibility toggle functionality.
15
15
  */
16
- const PasswordField = ({ autoComplete = "current-password", onChange, className, disabled, error,...textFieldProps }) => {
16
+ const PasswordField = ({ autoComplete = "current-password", hideLabel = "Hide password", onChange, showLabel = "Show password", className, disabled, error,...textFieldProps }) => {
17
17
  const { theme, colorScheme } = useTheme_default();
18
18
  const [showPassword, setShowPassword] = useState(false);
19
19
  const styles = PasswordField_styles_default(theme, colorScheme, showPassword, !!disabled, !!error);
@@ -29,6 +29,7 @@ const PasswordField = ({ autoComplete = "current-password", onChange, className,
29
29
  autoComplete,
30
30
  disabled,
31
31
  error,
32
+ endIconLabel: showPassword ? hideLabel : showLabel,
32
33
  endIcon: /* @__PURE__ */ jsx(IconComponent, {
33
34
  width: 16,
34
35
  height: 16,
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordField.js","names":["PasswordField: FC<PasswordFieldProps>","useTheme","styles: Record<string, string>","useStyles","IconComponent: FC<SVGProps<SVGSVGElement>>","EyeOff","Eye","TextField"],"sources":["../../../../src/components/primitives/PasswordField/PasswordField.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {ChangeEvent, FC, SVGProps, useState} from 'react';\nimport useStyles from './PasswordField.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport Eye from '../Icons/Eye';\nimport EyeOff from '../Icons/EyeOff';\nimport TextField, {TextFieldProps} from '../TextField/TextField';\n\nexport interface PasswordFieldProps extends Omit<TextFieldProps, 'type' | 'endIcon' | 'onEndIconClick' | 'onChange'> {\n /**\n * The browser autofill hint. Defaults to `current-password`; set `new-password` on the\n * fields of a change-password or sign-up form so password managers offer to generate and\n * store a new credential instead of filling the existing one.\n */\n autoComplete?: string;\n /**\n * Callback function when the field value changes\n */\n onChange: (value: string) => void;\n}\n\n/**\n * Password field component with show/hide toggle functionality.\n * This component extends TextField and adds password visibility toggle functionality.\n */\nconst PasswordField: FC<PasswordFieldProps> = ({\n autoComplete = 'current-password',\n onChange,\n className,\n disabled,\n error,\n ...textFieldProps\n}: PasswordFieldProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const [showPassword, setShowPassword] = useState(false);\n const styles: Record<string, string> = useStyles(theme, colorScheme, showPassword, !!disabled, !!error);\n\n const togglePasswordVisibility = (): void => {\n if (!disabled) {\n setShowPassword(!showPassword);\n }\n };\n\n const IconComponent: FC<SVGProps<SVGSVGElement>> = showPassword ? EyeOff : Eye;\n\n return (\n <TextField\n {...textFieldProps}\n className={cx(withVendorCSSClassPrefix(bem('password-field')), className)}\n type={showPassword ? 'text' : 'password'}\n onChange={(e: ChangeEvent<HTMLInputElement>): void => onChange(e.target.value)}\n autoComplete={autoComplete}\n disabled={disabled}\n error={error}\n endIcon={\n <IconComponent\n width={16}\n height={16}\n className={cx(\n withVendorCSSClassPrefix(bem('password-field', 'toggle-icon')),\n styles['toggleIcon'],\n showPassword ? styles['visibleIcon'] : styles['hiddenIcon'],\n )}\n />\n }\n onEndIconClick={togglePasswordVisibility}\n />\n );\n};\n\nexport default PasswordField;\n"],"mappings":";;;;;;;;;;;;;;;AA6BA,MAAMA,iBAAyC,EAC7C,eAAe,oBACf,UACA,WACA,UACA,MACA,GAAG,qBACqB;CACxB,MAAM,EAAC,OAAO,gBAA4CC,kBAAU;CACpE,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CACvD,MAAMC,SAAiCC,6BAAU,OAAO,aAAa,cAAc,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM;CAEvG,MAAM,iCAAuC;AAC3C,MAAI,CAAC,SACH,iBAAgB,CAAC,aAAa;;CAIlC,MAAMC,gBAA6C,eAAeC,iBAASC;AAE3E,QACE,oBAACC;EACC,GAAI;EACJ,WAAW,GAAG,yBAAyB,IAAI,iBAAiB,CAAC,EAAE,UAAU;EACzE,MAAM,eAAe,SAAS;EAC9B,WAAW,MAA2C,SAAS,EAAE,OAAO,MAAM;EAChE;EACJ;EACH;EACP,SACE,oBAAC;GACC,OAAO;GACP,QAAQ;GACR,WAAW,GACT,yBAAyB,IAAI,kBAAkB,cAAc,CAAC,EAC9D,OAAO,eACP,eAAe,OAAO,iBAAiB,OAAO,cAC/C;IACD;EAEJ,gBAAgB;GAChB;;AAIN,4BAAe"}
1
+ {"version":3,"file":"PasswordField.js","names":["PasswordField: FC<PasswordFieldProps>","useTheme","styles: Record<string, string>","useStyles","IconComponent: FC<SVGProps<SVGSVGElement>>","EyeOff","Eye","TextField"],"sources":["../../../../src/components/primitives/PasswordField/PasswordField.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {ChangeEvent, FC, SVGProps, useState} from 'react';\nimport useStyles from './PasswordField.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport Eye from '../Icons/Eye';\nimport EyeOff from '../Icons/EyeOff';\nimport TextField, {TextFieldProps} from '../TextField/TextField';\n\nexport interface PasswordFieldProps\n extends Omit<TextFieldProps, 'type' | 'endIcon' | 'endIconLabel' | 'onEndIconClick' | 'onChange'> {\n /**\n * The browser autofill hint. Defaults to `current-password`; set `new-password` on the\n * fields of a change-password or sign-up form so password managers offer to generate and\n * store a new credential instead of filling the existing one.\n */\n autoComplete?: string;\n /**\n * Accessible name of the toggle button while the password is visible\n */\n hideLabel?: string;\n /**\n * Callback function when the field value changes\n */\n onChange: (value: string) => void;\n /**\n * Accessible name of the toggle button while the password is hidden\n */\n showLabel?: string;\n}\n\n/**\n * Password field component with show/hide toggle functionality.\n * This component extends TextField and adds password visibility toggle functionality.\n */\nconst PasswordField: FC<PasswordFieldProps> = ({\n autoComplete = 'current-password',\n hideLabel = 'Hide password',\n onChange,\n showLabel = 'Show password',\n className,\n disabled,\n error,\n ...textFieldProps\n}: PasswordFieldProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const [showPassword, setShowPassword] = useState(false);\n const styles: Record<string, string> = useStyles(theme, colorScheme, showPassword, !!disabled, !!error);\n\n const togglePasswordVisibility = (): void => {\n if (!disabled) {\n setShowPassword(!showPassword);\n }\n };\n\n const IconComponent: FC<SVGProps<SVGSVGElement>> = showPassword ? EyeOff : Eye;\n\n return (\n <TextField\n {...textFieldProps}\n className={cx(withVendorCSSClassPrefix(bem('password-field')), className)}\n type={showPassword ? 'text' : 'password'}\n onChange={(e: ChangeEvent<HTMLInputElement>): void => onChange(e.target.value)}\n autoComplete={autoComplete}\n disabled={disabled}\n error={error}\n endIconLabel={showPassword ? hideLabel : showLabel}\n endIcon={\n <IconComponent\n width={16}\n height={16}\n className={cx(\n withVendorCSSClassPrefix(bem('password-field', 'toggle-icon')),\n styles['toggleIcon'],\n showPassword ? styles['visibleIcon'] : styles['hiddenIcon'],\n )}\n />\n }\n onEndIconClick={togglePasswordVisibility}\n />\n );\n};\n\nexport default PasswordField;\n"],"mappings":";;;;;;;;;;;;;;;AAsCA,MAAMA,iBAAyC,EAC7C,eAAe,oBACf,YAAY,iBACZ,UACA,YAAY,iBACZ,WACA,UACA,MACA,GAAG,qBACqB;CACxB,MAAM,EAAC,OAAO,gBAA4CC,kBAAU;CACpE,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CACvD,MAAMC,SAAiCC,6BAAU,OAAO,aAAa,cAAc,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM;CAEvG,MAAM,iCAAuC;AAC3C,MAAI,CAAC,SACH,iBAAgB,CAAC,aAAa;;CAIlC,MAAMC,gBAA6C,eAAeC,iBAASC;AAE3E,QACE,oBAACC;EACC,GAAI;EACJ,WAAW,GAAG,yBAAyB,IAAI,iBAAiB,CAAC,EAAE,UAAU;EACzE,MAAM,eAAe,SAAS;EAC9B,WAAW,MAA2C,SAAS,EAAE,OAAO,MAAM;EAChE;EACJ;EACH;EACP,cAAc,eAAe,YAAY;EACzC,SACE,oBAAC;GACC,OAAO;GACP,QAAQ;GACR,WAAW,GACT,yBAAyB,IAAI,kBAAkB,cAAc,CAAC,EAC9D,OAAO,eACP,eAAe,OAAO,iBAAiB,OAAO,cAC/C;IACD;EAEJ,gBAAgB;GAChB;;AAIN,4BAAe"}
@@ -0,0 +1,36 @@
1
+ import type { EmbeddedFlowComponent, EmbeddedFlowComponentType, FetchSelectPage, SelectOptionDefaults, SelectOptionMapping } from '@thunderid/browser';
2
+ import { FC } from 'react';
3
+ import { SelectProps } from './Select';
4
+ export interface ResourceSelectProps extends Omit<SelectProps, 'loading' | 'onError' | 'onLoadMore' | 'options'> {
5
+ /** Block name for the picker's CSS class, e.g. `user-select`. */
6
+ bemBlock: string;
7
+ /** The flow component the page function is called for. Defaults to one built from `type`. */
8
+ component?: EmbeddedFlowComponent;
9
+ defaults?: SelectOptionDefaults;
10
+ /** Wording used when the translations for the keys under `messageKey` are empty. */
11
+ fallbackMessages: {
12
+ ariaLabel: string;
13
+ empty: string;
14
+ };
15
+ /** Loads one page of the resource. Nothing is requested while this is unset. */
16
+ fetchPage?: FetchSelectPage;
17
+ filter?: string;
18
+ mapping?: SelectOptionMapping;
19
+ /** Translation key group under `elements.fields`, e.g. `user_select`. */
20
+ messageKey: string;
21
+ /** Called with the error of every failed load. The list itself shows no error. */
22
+ onError?: (error: Error) => void;
23
+ /** Options per request. Defaults to 30 and is capped at 100. */
24
+ pageSize?: number;
25
+ /** What is loaded, in the words of the failure log, e.g. `users`. */
26
+ resource: string;
27
+ /** The flow component type this picker stands for. */
28
+ type: EmbeddedFlowComponentType;
29
+ }
30
+ /**
31
+ * The part the `USER_SELECT`, `AUTH_FLOW_SELECT` and `USER_TYPE_SELECT` pickers share: a {@link Select} that loads
32
+ * one resource page by page. The list restarts when the page function, filter or page size changes.
33
+ */
34
+ declare const ResourceSelect: FC<ResourceSelectProps>;
35
+ export default ResourceSelect;
36
+ //# sourceMappingURL=ResourceSelect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResourceSelect.d.ts","sourceRoot":"","sources":["../../../../src/components/primitives/Select/ResourceSelect.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,qBAAqB,EACrB,yBAAyB,EACzB,eAAe,EAEf,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,EAAE,EAA6B,MAAM,OAAO,CAAC;AACrD,OAAe,EAAC,WAAW,EAAC,MAAM,UAAU,CAAC;AAK7C,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAAC;IAC9G,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,oFAAoF;IACpF,gBAAgB,EAAE;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC;IACrD,gFAAgF;IAChF,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,IAAI,EAAE,yBAAyB,CAAC;CACjC;AAID;;;GAGG;AACH,QAAA,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CA6F3C,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -0,0 +1,100 @@
1
+ import { cx } from "../../../styles/emotion.js";
2
+ import useTranslation_default from "../../../hooks/useTranslation.js";
3
+ import useInfiniteOptions_default from "../../../hooks/useInfiniteOptions.js";
4
+ import Select_default from "./Select.js";
5
+ import { SelectConstants, bem, createResourceOptionsLoader, resolvePageSize, withVendorCSSClassPrefix } from "@thunderid/browser";
6
+ import { useEffect, useMemo, useRef } from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+
9
+ //#region src/components/primitives/Select/ResourceSelect.tsx
10
+ const NO_PAGES = () => Promise.resolve({
11
+ nextOffset: null,
12
+ options: []
13
+ });
14
+ /**
15
+ * The part the `USER_SELECT`, `AUTH_FLOW_SELECT` and `USER_TYPE_SELECT` pickers share: a {@link Select} that loads
16
+ * one resource page by page. The list restarts when the page function, filter or page size changes.
17
+ */
18
+ const ResourceSelect = ({ "aria-label": ariaLabel, bemBlock, className, component, defaults, emptyText, fallbackMessages, fetchPage, filter, id, label, mapping, messageKey, name, onError, pageSize = SelectConstants.DEFAULT_PAGE_SIZE, placeholder, resource, type,...rest }) => {
19
+ const { t } = useTranslation_default();
20
+ const effectivePageSize = resolvePageSize(pageSize);
21
+ const live = useRef({
22
+ component,
23
+ defaults,
24
+ mapping
25
+ });
26
+ useEffect(() => {
27
+ live.current = {
28
+ component,
29
+ defaults,
30
+ mapping
31
+ };
32
+ });
33
+ const load = useMemo(() => createResourceOptionsLoader({
34
+ get component() {
35
+ return live.current.component ?? {
36
+ id: id ?? name ?? bemBlock,
37
+ type
38
+ };
39
+ },
40
+ get defaults() {
41
+ return live.current.defaults;
42
+ },
43
+ fetchPage: fetchPage ?? NO_PAGES,
44
+ filter,
45
+ get mapping() {
46
+ return live.current.mapping;
47
+ },
48
+ pageSize: effectivePageSize,
49
+ resource
50
+ }), [
51
+ bemBlock,
52
+ effectivePageSize,
53
+ fetchPage,
54
+ filter,
55
+ id,
56
+ name,
57
+ resource,
58
+ type
59
+ ]);
60
+ const { hasMore, loading, onLoadMore, options, reset } = useInfiniteOptions_default({
61
+ load,
62
+ onError
63
+ });
64
+ const previousLoadRef = useRef(null);
65
+ useEffect(() => {
66
+ const previousLoad = previousLoadRef.current;
67
+ previousLoadRef.current = load;
68
+ if (previousLoad !== null && previousLoad !== load) reset();
69
+ if (fetchPage) onLoadMore();
70
+ }, [
71
+ fetchPage,
72
+ load,
73
+ onLoadMore,
74
+ reset
75
+ ]);
76
+ const accessibleName = [
77
+ ariaLabel,
78
+ label,
79
+ placeholder,
80
+ t(`elements.fields.${messageKey}.aria_label`)
81
+ ].find((text) => Boolean(text)) ?? fallbackMessages.ariaLabel;
82
+ return /* @__PURE__ */ jsx(Select_default, {
83
+ ...rest,
84
+ "aria-label": accessibleName,
85
+ className: cx(withVendorCSSClassPrefix(bem(bemBlock)), className),
86
+ emptyText: emptyText ?? (t(`elements.fields.${messageKey}.empty`) || fallbackMessages.empty),
87
+ id,
88
+ label,
89
+ loading,
90
+ name,
91
+ onLoadMore: fetchPage && hasMore ? onLoadMore : void 0,
92
+ options,
93
+ placeholder
94
+ });
95
+ };
96
+ var ResourceSelect_default = ResourceSelect;
97
+
98
+ //#endregion
99
+ export { ResourceSelect_default as default };
100
+ //# sourceMappingURL=ResourceSelect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResourceSelect.js","names":["NO_PAGES: FetchSelectPage","ResourceSelect: FC<ResourceSelectProps>","useTranslation","effectivePageSize: number","load: ResourceOptionsLoader","useInfiniteOptions","previousLoad: ResourceOptionsLoader | null","accessibleName: string","Select"],"sources":["../../../../src/components/primitives/Select/ResourceSelect.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n bem,\n createResourceOptionsLoader,\n SelectConstants,\n resolvePageSize,\n withVendorCSSClassPrefix,\n} from '@thunderid/browser';\nimport type {\n EmbeddedFlowComponent,\n EmbeddedFlowComponentType,\n FetchSelectPage,\n ResourceOptionsLoader,\n SelectOptionDefaults,\n SelectOptionMapping,\n} from '@thunderid/browser';\nimport {FC, useEffect, useMemo, useRef} from 'react';\nimport Select, {SelectProps} from './Select';\nimport useInfiniteOptions from '../../../hooks/useInfiniteOptions';\nimport useTranslation from '../../../hooks/useTranslation';\nimport {cx} from '../../../styles/emotion';\n\nexport interface ResourceSelectProps extends Omit<SelectProps, 'loading' | 'onError' | 'onLoadMore' | 'options'> {\n /** Block name for the picker's CSS class, e.g. `user-select`. */\n bemBlock: string;\n /** The flow component the page function is called for. Defaults to one built from `type`. */\n component?: EmbeddedFlowComponent;\n defaults?: SelectOptionDefaults;\n /** Wording used when the translations for the keys under `messageKey` are empty. */\n fallbackMessages: {ariaLabel: string; empty: string};\n /** Loads one page of the resource. Nothing is requested while this is unset. */\n fetchPage?: FetchSelectPage;\n filter?: string;\n mapping?: SelectOptionMapping;\n /** Translation key group under `elements.fields`, e.g. `user_select`. */\n messageKey: string;\n /** Called with the error of every failed load. The list itself shows no error. */\n onError?: (error: Error) => void;\n /** Options per request. Defaults to 30 and is capped at 100. */\n pageSize?: number;\n /** What is loaded, in the words of the failure log, e.g. `users`. */\n resource: string;\n /** The flow component type this picker stands for. */\n type: EmbeddedFlowComponentType;\n}\n\nconst NO_PAGES: FetchSelectPage = () => Promise.resolve({nextOffset: null, options: []});\n\n/**\n * The part the `USER_SELECT`, `AUTH_FLOW_SELECT` and `USER_TYPE_SELECT` pickers share: a {@link Select} that loads\n * one resource page by page. The list restarts when the page function, filter or page size changes.\n */\nconst ResourceSelect: FC<ResourceSelectProps> = ({\n 'aria-label': ariaLabel,\n bemBlock,\n className,\n component,\n defaults,\n emptyText,\n fallbackMessages,\n fetchPage,\n filter,\n id,\n label,\n mapping,\n messageKey,\n name,\n onError,\n pageSize = SelectConstants.DEFAULT_PAGE_SIZE,\n placeholder,\n resource,\n type,\n ...rest\n}: ResourceSelectProps) => {\n const {t} = useTranslation();\n const effectivePageSize: number = resolvePageSize(pageSize);\n\n const live = useRef({component, defaults, mapping});\n\n useEffect(() => {\n live.current = {component, defaults, mapping};\n });\n\n // Only the page function, filter and page size restart the list. Mapping, defaults and component are read when\n // a page loads, so a parent that passes a new object on every render does not reload it.\n const load: ResourceOptionsLoader = useMemo(\n () =>\n createResourceOptionsLoader({\n get component(): EmbeddedFlowComponent {\n return live.current.component ?? ({id: id ?? name ?? bemBlock, type} as EmbeddedFlowComponent);\n },\n get defaults(): SelectOptionDefaults | undefined {\n return live.current.defaults;\n },\n fetchPage: fetchPage ?? NO_PAGES,\n filter,\n get mapping(): SelectOptionMapping | undefined {\n return live.current.mapping;\n },\n pageSize: effectivePageSize,\n resource,\n }),\n [bemBlock, effectivePageSize, fetchPage, filter, id, name, resource, type],\n );\n const {hasMore, loading, onLoadMore, options, reset} = useInfiniteOptions({load, onError});\n\n const previousLoadRef = useRef<ResourceOptionsLoader | null>(null);\n\n // The first batch is requested when the picker renders. A different page function, filter or page size starts\n // the list again from the beginning.\n useEffect(() => {\n const previousLoad: ResourceOptionsLoader | null = previousLoadRef.current;\n\n previousLoadRef.current = load;\n\n if (previousLoad !== null && previousLoad !== load) {\n reset();\n }\n\n if (fetchPage) {\n onLoadMore();\n }\n }, [fetchPage, load, onLoadMore, reset]);\n\n // The first of these that is not empty names the select. An empty string is not a name, which is why this is not a\n // chain of `??`.\n const accessibleName: string =\n [ariaLabel, label, placeholder, t(`elements.fields.${messageKey}.aria_label`)].find((text) => Boolean(text)) ??\n fallbackMessages.ariaLabel;\n\n return (\n <Select\n {...rest}\n aria-label={accessibleName}\n className={cx(withVendorCSSClassPrefix(bem(bemBlock)), className)}\n emptyText={emptyText ?? (t(`elements.fields.${messageKey}.empty`) || fallbackMessages.empty)}\n id={id}\n label={label}\n loading={loading}\n name={name}\n onLoadMore={fetchPage && hasMore ? onLoadMore : undefined}\n options={options}\n placeholder={placeholder}\n />\n );\n};\n\nexport default ResourceSelect;\n"],"mappings":";;;;;;;;;AAgDA,MAAMA,iBAAkC,QAAQ,QAAQ;CAAC,YAAY;CAAM,SAAS,EAAE;CAAC,CAAC;;;;;AAMxF,MAAMC,kBAA2C,EAC/C,cAAc,WACd,UACA,WACA,WACA,UACA,WACA,kBACA,WACA,QACA,IACA,OACA,SACA,YACA,MACA,SACA,WAAW,gBAAgB,mBAC3B,aACA,UACA,KACA,GAAG,WACsB;CACzB,MAAM,EAAC,MAAKC,wBAAgB;CAC5B,MAAMC,oBAA4B,gBAAgB,SAAS;CAE3D,MAAM,OAAO,OAAO;EAAC;EAAW;EAAU;EAAQ,CAAC;AAEnD,iBAAgB;AACd,OAAK,UAAU;GAAC;GAAW;GAAU;GAAQ;GAC7C;CAIF,MAAMC,OAA8B,cAEhC,4BAA4B;EAC1B,IAAI,YAAmC;AACrC,UAAO,KAAK,QAAQ,aAAc;IAAC,IAAI,MAAM,QAAQ;IAAU;IAAK;;EAEtE,IAAI,WAA6C;AAC/C,UAAO,KAAK,QAAQ;;EAEtB,WAAW,aAAa;EACxB;EACA,IAAI,UAA2C;AAC7C,UAAO,KAAK,QAAQ;;EAEtB,UAAU;EACV;EACD,CAAC,EACJ;EAAC;EAAU;EAAmB;EAAW;EAAQ;EAAI;EAAM;EAAU;EAAK,CAC3E;CACD,MAAM,EAAC,SAAS,SAAS,YAAY,SAAS,UAASC,2BAAmB;EAAC;EAAM;EAAQ,CAAC;CAE1F,MAAM,kBAAkB,OAAqC,KAAK;AAIlE,iBAAgB;EACd,MAAMC,eAA6C,gBAAgB;AAEnE,kBAAgB,UAAU;AAE1B,MAAI,iBAAiB,QAAQ,iBAAiB,KAC5C,QAAO;AAGT,MAAI,UACF,aAAY;IAEb;EAAC;EAAW;EAAM;EAAY;EAAM,CAAC;CAIxC,MAAMC,iBACJ;EAAC;EAAW;EAAO;EAAa,EAAE,mBAAmB,WAAW,aAAa;EAAC,CAAC,MAAM,SAAS,QAAQ,KAAK,CAAC,IAC5G,iBAAiB;AAEnB,QACE,oBAACC;EACC,GAAI;EACJ,cAAY;EACZ,WAAW,GAAG,yBAAyB,IAAI,SAAS,CAAC,EAAE,UAAU;EACjE,WAAW,cAAc,EAAE,mBAAmB,WAAW,QAAQ,IAAI,iBAAiB;EAClF;EACG;EACE;EACH;EACN,YAAY,aAAa,UAAU,aAAa;EACvC;EACI;GACb;;AAIN,6BAAe"}
@@ -1,14 +1,6 @@
1
+ import type { SelectOption, SelectOptionInput } from '@thunderid/browser';
1
2
  import { FC, SelectHTMLAttributes } from 'react';
2
- export interface SelectOption {
3
- /**
4
- * The text that will be displayed in the select
5
- */
6
- label: string;
7
- /**
8
- * The value that will be submitted with the form
9
- */
10
- value: string;
11
- }
3
+ export type { SelectOption, SelectOptionInput };
12
4
  export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, 'className'> {
13
5
  /**
14
6
  * Additional CSS class names
@@ -18,6 +10,10 @@ export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement
18
10
  * Whether the field is disabled
19
11
  */
20
12
  disabled?: boolean;
13
+ /**
14
+ * Text shown below the select when it has no options, nothing is loading and there is nothing more to load
15
+ */
16
+ emptyText?: string;
21
17
  /**
22
18
  * Error message to display below the select
23
19
  */
@@ -31,17 +27,30 @@ export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement
31
27
  */
32
28
  label?: string;
33
29
  /**
34
- * The options to display in the select
30
+ * Whether options are being fetched. The load more option waits, and a select with no options shows a loading message
35
31
  */
36
- options: SelectOption[];
32
+ loading?: boolean;
37
33
  /**
38
- * Placeholder text for the default/empty option
34
+ * Called when the load more option, listed after the last one, is chosen. Choosing it does not change the selection.
35
+ * The option is listed only when this is set, so pass it only while more options may be available
36
+ */
37
+ onLoadMore?: () => void;
38
+ /**
39
+ * The options to display: strings, numbers, or `{label, value, disabled?}` objects
40
+ */
41
+ options?: readonly (SelectOptionInput | null | undefined)[] | null;
42
+ /**
43
+ * Placeholder text for the default/empty option. While the field is not required, choosing it clears the selection
39
44
  */
40
45
  placeholder?: string;
41
46
  /**
42
47
  * Whether the field is required
43
48
  */
44
49
  required?: boolean;
50
+ /**
51
+ * Label of the selected option while `value` is not among `options`, such as a value loaded from saved data
52
+ */
53
+ selectedOption?: SelectOption;
45
54
  }
46
55
  declare const Select: FC<SelectProps>;
47
56
  export default Select;
@@ -1 +1 @@
1
- {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../../src/components/primitives/Select/Select.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAC,EAAE,EAAE,oBAAoB,EAAC,MAAM,OAAO,CAAC;AAO/C,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAC7F;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAuD3B,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../../src/components/primitives/Select/Select.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,YAAY,EAAE,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAc,EAAE,EAAa,oBAAoB,EAAoC,MAAM,OAAO,CAAC;AAQ1G,YAAY,EAAC,YAAY,EAAE,iBAAiB,EAAC,CAAC;AAE9C,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAC7F;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC;IACnE;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,cAAc,CAAC,EAAE,YAAY,CAAC;CAC/B;AAED,QAAA,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAgI3B,CAAC;AAEF,eAAe,MAAM,CAAC"}