smarthr-ui 97.0.0 → 98.1.0

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 (293) hide show
  1. package/lib/components/AppHeader/components/common/AppLauncherFeatures.cjs +1 -1
  2. package/lib/components/AppHeader/components/common/AppLauncherFeatures.js +1 -1
  3. package/lib/components/AppHeader/components/common/AppLauncherSortDropdown.cjs +1 -1
  4. package/lib/components/AppHeader/components/common/AppLauncherSortDropdown.js +1 -1
  5. package/lib/components/AppHeader/components/desktop/AppLauncher.cjs +5 -5
  6. package/lib/components/AppHeader/components/desktop/AppLauncher.cjs.map +1 -1
  7. package/lib/components/AppHeader/components/desktop/AppLauncher.js +5 -5
  8. package/lib/components/AppHeader/components/desktop/AppLauncher.js.map +1 -1
  9. package/lib/components/AppHeader/components/desktop/DesktopHeader.cjs +1 -1
  10. package/lib/components/AppHeader/components/desktop/DesktopHeader.js +1 -1
  11. package/lib/components/AppHeader/components/desktop/ReleaseNotesDropdown.cjs +1 -1
  12. package/lib/components/AppHeader/components/desktop/ReleaseNotesDropdown.js +1 -1
  13. package/lib/components/AppHeader/components/desktop/UserInfo.cjs +1 -1
  14. package/lib/components/AppHeader/components/desktop/UserInfo.js +1 -1
  15. package/lib/components/AppHeader/components/mobile/AppLauncher.cjs +1 -1
  16. package/lib/components/AppHeader/components/mobile/AppLauncher.js +1 -1
  17. package/lib/components/AppHeader/components/mobile/AppLauncherFilterDropdown.cjs +1 -1
  18. package/lib/components/AppHeader/components/mobile/AppLauncherFilterDropdown.js +1 -1
  19. package/lib/components/AppHeader/components/mobile/Help.cjs +1 -1
  20. package/lib/components/AppHeader/components/mobile/Help.js +1 -1
  21. package/lib/components/AppHeader/components/mobile/LanguageSelector.cjs +1 -1
  22. package/lib/components/AppHeader/components/mobile/LanguageSelector.js +1 -1
  23. package/lib/components/AppHeader/components/mobile/Menu.cjs +1 -1
  24. package/lib/components/AppHeader/components/mobile/Menu.js +1 -1
  25. package/lib/components/AppHeader/components/mobile/MenuAccordion.cjs +1 -1
  26. package/lib/components/AppHeader/components/mobile/MenuAccordion.js +1 -1
  27. package/lib/components/AppHeader/components/mobile/MenuDialog.cjs +2 -2
  28. package/lib/components/AppHeader/components/mobile/MenuDialog.js +2 -2
  29. package/lib/components/AppHeader/components/mobile/MenuSubHeading.cjs +1 -1
  30. package/lib/components/AppHeader/components/mobile/MenuSubHeading.js +1 -1
  31. package/lib/components/AppHeader/components/mobile/ReleaseNote.cjs +1 -1
  32. package/lib/components/AppHeader/components/mobile/ReleaseNote.js +1 -1
  33. package/lib/components/AppHeader/components/mobile/UserInfo.cjs +2 -2
  34. package/lib/components/AppHeader/components/mobile/UserInfo.js +2 -2
  35. package/lib/components/Browser/Browser.cjs +11 -7
  36. package/lib/components/Browser/Browser.cjs.map +1 -1
  37. package/lib/components/Browser/Browser.js +12 -8
  38. package/lib/components/Browser/Browser.js.map +1 -1
  39. package/lib/components/Calendar/Calendar.cjs +1 -1
  40. package/lib/components/Calendar/Calendar.js +1 -1
  41. package/lib/components/Calendar/CalendarTable.cjs +1 -1
  42. package/lib/components/Calendar/CalendarTable.js +1 -1
  43. package/lib/components/Calendar/YearPicker.cjs +1 -1
  44. package/lib/components/Calendar/YearPicker.js +1 -1
  45. package/lib/components/Combobox/ItemButton.cjs +27 -26
  46. package/lib/components/Combobox/ItemButton.cjs.map +1 -1
  47. package/lib/components/Combobox/ItemButton.js +28 -27
  48. package/lib/components/Combobox/ItemButton.js.map +1 -1
  49. package/lib/components/Combobox/MultiCombobox/MultiCombobox.cjs +122 -134
  50. package/lib/components/Combobox/MultiCombobox/MultiCombobox.cjs.map +1 -1
  51. package/lib/components/Combobox/MultiCombobox/MultiCombobox.js +123 -135
  52. package/lib/components/Combobox/MultiCombobox/MultiCombobox.js.map +1 -1
  53. package/lib/components/Combobox/MultiCombobox/MultiSelectedItem.cjs +1 -1
  54. package/lib/components/Combobox/MultiCombobox/MultiSelectedItem.js +1 -1
  55. package/lib/components/Combobox/SingleCombobox/SingleCombobox.cjs +79 -46
  56. package/lib/components/Combobox/SingleCombobox/SingleCombobox.cjs.map +1 -1
  57. package/lib/components/Combobox/SingleCombobox/SingleCombobox.js +81 -48
  58. package/lib/components/Combobox/SingleCombobox/SingleCombobox.js.map +1 -1
  59. package/lib/components/Combobox/useListbox.cjs +1 -1
  60. package/lib/components/Combobox/useListbox.js +1 -1
  61. package/lib/components/Combobox/useOptions.cjs +3 -1
  62. package/lib/components/Combobox/useOptions.cjs.map +1 -1
  63. package/lib/components/Combobox/useOptions.js +4 -2
  64. package/lib/components/Combobox/useOptions.js.map +1 -1
  65. package/lib/components/Dialog/ControlledActionDialog/ActionDialogContentInner.cjs +3 -3
  66. package/lib/components/Dialog/ControlledActionDialog/ActionDialogContentInner.cjs.map +1 -1
  67. package/lib/components/Dialog/ControlledActionDialog/ActionDialogContentInner.js +3 -3
  68. package/lib/components/Dialog/ControlledActionDialog/ActionDialogContentInner.js.map +1 -1
  69. package/lib/components/Dialog/ControlledFormDialog/FormDialogContentInner.cjs +3 -3
  70. package/lib/components/Dialog/ControlledFormDialog/FormDialogContentInner.cjs.map +1 -1
  71. package/lib/components/Dialog/ControlledFormDialog/FormDialogContentInner.js +3 -3
  72. package/lib/components/Dialog/ControlledFormDialog/FormDialogContentInner.js.map +1 -1
  73. package/lib/components/Dialog/ControlledMessageDialog/MessageDialogContentInner.cjs +1 -1
  74. package/lib/components/Dialog/ControlledMessageDialog/MessageDialogContentInner.js +1 -1
  75. package/lib/components/Dialog/ControlledStepFormDialog/ControlledStepFormDialog.cjs +1 -1
  76. package/lib/components/Dialog/ControlledStepFormDialog/ControlledStepFormDialog.js +1 -1
  77. package/lib/components/Dialog/ControlledStepFormDialog/StepFormDialogContentInner.cjs +2 -2
  78. package/lib/components/Dialog/ControlledStepFormDialog/StepFormDialogContentInner.cjs.map +1 -1
  79. package/lib/components/Dialog/ControlledStepFormDialog/StepFormDialogContentInner.js +2 -2
  80. package/lib/components/Dialog/ControlledStepFormDialog/StepFormDialogContentInner.js.map +1 -1
  81. package/lib/components/Dialog/DialogContentResponseStatusMessage.cjs +3 -8
  82. package/lib/components/Dialog/DialogContentResponseStatusMessage.cjs.map +1 -1
  83. package/lib/components/Dialog/DialogContentResponseStatusMessage.d.ts +1 -1
  84. package/lib/components/Dialog/DialogContentResponseStatusMessage.js +3 -8
  85. package/lib/components/Dialog/DialogContentResponseStatusMessage.js.map +1 -1
  86. package/lib/components/Dialog/FocusTrap.cjs +4 -1
  87. package/lib/components/Dialog/FocusTrap.cjs.map +1 -1
  88. package/lib/components/Dialog/FocusTrap.js +4 -1
  89. package/lib/components/Dialog/FocusTrap.js.map +1 -1
  90. package/lib/components/Dialog/ModelessDialog/ModelessDialog.cjs +1 -1
  91. package/lib/components/Dialog/ModelessDialog/ModelessDialog.js +1 -1
  92. package/lib/components/Dialog/RemoteDialogTrigger/RemoteDialogTrigger.cjs +9 -3
  93. package/lib/components/Dialog/RemoteDialogTrigger/RemoteDialogTrigger.cjs.map +1 -1
  94. package/lib/components/Dialog/RemoteDialogTrigger/RemoteDialogTrigger.js +9 -3
  95. package/lib/components/Dialog/RemoteDialogTrigger/RemoteDialogTrigger.js.map +1 -1
  96. package/lib/components/Disclosure/DisclosureTrigger.cjs +8 -4
  97. package/lib/components/Disclosure/DisclosureTrigger.cjs.map +1 -1
  98. package/lib/components/Disclosure/DisclosureTrigger.js +8 -4
  99. package/lib/components/Disclosure/DisclosureTrigger.js.map +1 -1
  100. package/lib/components/DropZone/DropZone.cjs +1 -1
  101. package/lib/components/DropZone/DropZone.js +1 -1
  102. package/lib/components/Dropdown/Dropdown.cjs +36 -34
  103. package/lib/components/Dropdown/Dropdown.cjs.map +1 -1
  104. package/lib/components/Dropdown/Dropdown.js +37 -35
  105. package/lib/components/Dropdown/Dropdown.js.map +1 -1
  106. package/lib/components/Dropdown/DropdownMenuButton/DropdownMenuButton.cjs +1 -1
  107. package/lib/components/Dropdown/DropdownMenuButton/DropdownMenuButton.js +1 -1
  108. package/lib/components/Dropdown/FilterDropdown/FilterDropdown.cjs +3 -5
  109. package/lib/components/Dropdown/FilterDropdown/FilterDropdown.cjs.map +1 -1
  110. package/lib/components/Dropdown/FilterDropdown/FilterDropdown.d.ts +1 -1
  111. package/lib/components/Dropdown/FilterDropdown/FilterDropdown.js +3 -5
  112. package/lib/components/Dropdown/FilterDropdown/FilterDropdown.js.map +1 -1
  113. package/lib/components/Dropdown/SortDropdown/useSortDropdown.cjs +1 -1
  114. package/lib/components/Dropdown/SortDropdown/useSortDropdown.js +1 -1
  115. package/lib/components/ErrorScreen/AuthErrorScreen.cjs +1 -1
  116. package/lib/components/ErrorScreen/AuthErrorScreen.js +1 -1
  117. package/lib/components/ErrorScreen/ForbiddenErrorScreen.cjs +1 -1
  118. package/lib/components/ErrorScreen/ForbiddenErrorScreen.js +1 -1
  119. package/lib/components/ErrorScreen/NotFoundErrorScreen.cjs +1 -1
  120. package/lib/components/ErrorScreen/NotFoundErrorScreen.js +1 -1
  121. package/lib/components/ErrorScreen/UnauthorizedErrorScreen.cjs +1 -1
  122. package/lib/components/ErrorScreen/UnauthorizedErrorScreen.js +1 -1
  123. package/lib/components/FileViewer/FileViewer.cjs +35 -2
  124. package/lib/components/FileViewer/FileViewer.cjs.map +1 -1
  125. package/lib/components/FileViewer/FileViewer.js +37 -4
  126. package/lib/components/FileViewer/FileViewer.js.map +1 -1
  127. package/lib/components/FileViewer/PDFViewer.cjs +59 -2
  128. package/lib/components/FileViewer/PDFViewer.cjs.map +1 -1
  129. package/lib/components/FileViewer/PDFViewer.d.ts +6 -1
  130. package/lib/components/FileViewer/PDFViewer.js +60 -3
  131. package/lib/components/FileViewer/PDFViewer.js.map +1 -1
  132. package/lib/components/FileViewer/SearchController.cjs +105 -0
  133. package/lib/components/FileViewer/SearchController.cjs.map +1 -0
  134. package/lib/components/FileViewer/SearchController.d.ts +7 -0
  135. package/lib/components/FileViewer/SearchController.js +103 -0
  136. package/lib/components/FileViewer/SearchController.js.map +1 -0
  137. package/lib/components/FileViewer/buildCustomTextRenderer.cjs +55 -0
  138. package/lib/components/FileViewer/buildCustomTextRenderer.cjs.map +1 -0
  139. package/lib/components/FileViewer/buildCustomTextRenderer.d.ts +9 -0
  140. package/lib/components/FileViewer/buildCustomTextRenderer.js +50 -0
  141. package/lib/components/FileViewer/buildCustomTextRenderer.js.map +1 -0
  142. package/lib/components/FileViewer/types.d.ts +7 -0
  143. package/lib/components/FileViewer/usePDFSearch.cjs +148 -0
  144. package/lib/components/FileViewer/usePDFSearch.cjs.map +1 -0
  145. package/lib/components/FileViewer/usePDFSearch.d.ts +19 -0
  146. package/lib/components/FileViewer/usePDFSearch.js +143 -0
  147. package/lib/components/FileViewer/usePDFSearch.js.map +1 -0
  148. package/lib/components/FormControl/FormControl.cjs +2 -22
  149. package/lib/components/FormControl/FormControl.cjs.map +1 -1
  150. package/lib/components/FormControl/FormControl.js +2 -22
  151. package/lib/components/FormControl/FormControl.js.map +1 -1
  152. package/lib/components/Header/AppLauncher/AppLauncher.cjs +1 -1
  153. package/lib/components/Header/AppLauncher/AppLauncher.js +1 -1
  154. package/lib/components/Header/LanguageSwitcher/LanguageSwitcher.cjs +1 -1
  155. package/lib/components/Header/LanguageSwitcher/LanguageSwitcher.js +1 -1
  156. package/lib/components/Icon/FaIcon.js +1 -1
  157. package/lib/components/Icon/OpenInNewTabIcon.cjs +1 -1
  158. package/lib/components/Icon/OpenInNewTabIcon.js +1 -1
  159. package/lib/components/InformationPanel/InformationPanel.cjs +1 -1
  160. package/lib/components/InformationPanel/InformationPanel.js +1 -1
  161. package/lib/components/Input/SearchInput/SearchInputIcon.cjs +1 -1
  162. package/lib/components/Input/SearchInput/SearchInputIcon.js +1 -1
  163. package/lib/components/InputFile/InputFileMultiplyAppendable.cjs +1 -1
  164. package/lib/components/InputFile/InputFileMultiplyAppendable.js +1 -1
  165. package/lib/components/InputFile/InputFileNative.cjs +1 -1
  166. package/lib/components/InputFile/InputFileNative.js +1 -1
  167. package/lib/components/Layout/Cluster/Cluster.cjs +0 -1
  168. package/lib/components/Layout/Cluster/Cluster.cjs.map +1 -1
  169. package/lib/components/Layout/Cluster/Cluster.js +0 -1
  170. package/lib/components/Layout/Cluster/Cluster.js.map +1 -1
  171. package/lib/components/Layout/Container/Container.cjs +1 -5
  172. package/lib/components/Layout/Container/Container.cjs.map +1 -1
  173. package/lib/components/Layout/Container/Container.js +1 -5
  174. package/lib/components/Layout/Container/Container.js.map +1 -1
  175. package/lib/components/Layout/Stack/Stack.cjs +22 -22
  176. package/lib/components/Layout/Stack/Stack.cjs.map +1 -1
  177. package/lib/components/Layout/Stack/Stack.js +22 -22
  178. package/lib/components/Layout/Stack/Stack.js.map +1 -1
  179. package/lib/components/Loader/LoaderSpinner.cjs +1 -1
  180. package/lib/components/Loader/LoaderSpinner.js +1 -1
  181. package/lib/components/Pagination/Pagination.cjs +1 -1
  182. package/lib/components/Pagination/Pagination.js +1 -1
  183. package/lib/components/Pagination/PaginationItemButton.cjs +1 -1
  184. package/lib/components/Pagination/PaginationItemButton.js +1 -1
  185. package/lib/components/SideNav/SideNav.cjs +3 -22
  186. package/lib/components/SideNav/SideNav.cjs.map +1 -1
  187. package/lib/components/SideNav/SideNav.d.ts +2 -9
  188. package/lib/components/SideNav/SideNav.js +4 -23
  189. package/lib/components/SideNav/SideNav.js.map +1 -1
  190. package/lib/components/SideNav/SideNavContext.cjs +11 -0
  191. package/lib/components/SideNav/SideNavContext.cjs.map +1 -0
  192. package/lib/components/SideNav/SideNavContext.d.ts +7 -0
  193. package/lib/components/SideNav/SideNavContext.js +8 -0
  194. package/lib/components/SideNav/SideNavContext.js.map +1 -0
  195. package/lib/components/SideNav/SideNavItemButton.cjs +12 -7
  196. package/lib/components/SideNav/SideNavItemButton.cjs.map +1 -1
  197. package/lib/components/SideNav/SideNavItemButton.d.ts +5 -11
  198. package/lib/components/SideNav/SideNavItemButton.js +12 -7
  199. package/lib/components/SideNav/SideNavItemButton.js.map +1 -1
  200. package/lib/components/Table/Th.cjs +2 -2
  201. package/lib/components/Table/Th.cjs.map +1 -1
  202. package/lib/components/Table/Th.d.ts +0 -2
  203. package/lib/components/Table/Th.js +2 -2
  204. package/lib/components/Table/Th.js.map +1 -1
  205. package/lib/components/Table/ThCheckbox.cjs +1 -1
  206. package/lib/components/Table/ThCheckbox.js +1 -1
  207. package/lib/components/Table/ThSortButton.cjs +5 -6
  208. package/lib/components/Table/ThSortButton.cjs.map +1 -1
  209. package/lib/components/Table/ThSortButton.d.ts +1 -6
  210. package/lib/components/Table/ThSortButton.js +5 -6
  211. package/lib/components/Table/ThSortButton.js.map +1 -1
  212. package/lib/components/WarekiPicker/WarekiPicker.cjs +1 -1
  213. package/lib/components/WarekiPicker/WarekiPicker.js +1 -1
  214. package/lib/hooks/useLatest.cjs +33 -0
  215. package/lib/hooks/useLatest.cjs.map +1 -0
  216. package/lib/hooks/useLatest.d.ts +19 -0
  217. package/lib/hooks/useLatest.js +31 -0
  218. package/lib/hooks/useLatest.js.map +1 -0
  219. package/lib/index.cjs +1 -6
  220. package/lib/index.cjs.map +1 -1
  221. package/lib/index.d.ts +0 -1
  222. package/lib/index.js +1 -4
  223. package/lib/index.js.map +1 -1
  224. package/lib/intl/Localizer.cjs +5 -1
  225. package/lib/intl/Localizer.cjs.map +1 -1
  226. package/lib/intl/Localizer.d.ts +1 -1
  227. package/lib/intl/Localizer.js +5 -1
  228. package/lib/intl/Localizer.js.map +1 -1
  229. package/lib/intl/locales/en_us.json.cjs +3 -0
  230. package/lib/intl/locales/en_us.json.cjs.map +1 -1
  231. package/lib/intl/locales/en_us.json.js +3 -0
  232. package/lib/intl/locales/en_us.json.js.map +1 -1
  233. package/lib/intl/locales/id_id.json.cjs +3 -0
  234. package/lib/intl/locales/id_id.json.cjs.map +1 -1
  235. package/lib/intl/locales/id_id.json.js +3 -0
  236. package/lib/intl/locales/id_id.json.js.map +1 -1
  237. package/lib/intl/locales/index.d.ts +27 -0
  238. package/lib/intl/locales/ja.cjs +3 -0
  239. package/lib/intl/locales/ja.cjs.map +1 -1
  240. package/lib/intl/locales/ja.d.ts +3 -0
  241. package/lib/intl/locales/ja.js +3 -0
  242. package/lib/intl/locales/ja.js.map +1 -1
  243. package/lib/intl/locales/ja.json.cjs +3 -0
  244. package/lib/intl/locales/ja.json.cjs.map +1 -1
  245. package/lib/intl/locales/ja.json.js +3 -0
  246. package/lib/intl/locales/ja.json.js.map +1 -1
  247. package/lib/intl/locales/ja_easy.json.cjs +3 -0
  248. package/lib/intl/locales/ja_easy.json.cjs.map +1 -1
  249. package/lib/intl/locales/ja_easy.json.js +3 -0
  250. package/lib/intl/locales/ja_easy.json.js.map +1 -1
  251. package/lib/intl/locales/ko_kr.json.cjs +3 -0
  252. package/lib/intl/locales/ko_kr.json.cjs.map +1 -1
  253. package/lib/intl/locales/ko_kr.json.js +3 -0
  254. package/lib/intl/locales/ko_kr.json.js.map +1 -1
  255. package/lib/intl/locales/pt_br.json.cjs +3 -0
  256. package/lib/intl/locales/pt_br.json.cjs.map +1 -1
  257. package/lib/intl/locales/pt_br.json.js +3 -0
  258. package/lib/intl/locales/pt_br.json.js.map +1 -1
  259. package/lib/intl/locales/vi_vn.json.cjs +3 -0
  260. package/lib/intl/locales/vi_vn.json.cjs.map +1 -1
  261. package/lib/intl/locales/vi_vn.json.js +3 -0
  262. package/lib/intl/locales/vi_vn.json.js.map +1 -1
  263. package/lib/intl/locales/zh_hans_cn.json.cjs +3 -0
  264. package/lib/intl/locales/zh_hans_cn.json.cjs.map +1 -1
  265. package/lib/intl/locales/zh_hans_cn.json.js +3 -0
  266. package/lib/intl/locales/zh_hans_cn.json.js.map +1 -1
  267. package/lib/intl/locales/zh_hant_tw.json.cjs +3 -0
  268. package/lib/intl/locales/zh_hant_tw.json.cjs.map +1 -1
  269. package/lib/intl/locales/zh_hant_tw.json.js +3 -0
  270. package/lib/intl/locales/zh_hant_tw.json.js.map +1 -1
  271. package/metadata.json +1 -1
  272. package/package.json +1 -1
  273. package/smarthr-ui.css +35 -98
  274. package/lib/hooks/useDecorators.cjs +0 -18
  275. package/lib/hooks/useDecorators.cjs.map +0 -1
  276. package/lib/hooks/useDecorators.d.ts +0 -6
  277. package/lib/hooks/useDecorators.js +0 -16
  278. package/lib/hooks/useDecorators.js.map +0 -1
  279. package/lib/hooks/useDevice/DeviceProvider.cjs +0 -37
  280. package/lib/hooks/useDevice/DeviceProvider.cjs.map +0 -1
  281. package/lib/hooks/useDevice/DeviceProvider.d.ts +0 -4
  282. package/lib/hooks/useDevice/DeviceProvider.js +0 -35
  283. package/lib/hooks/useDevice/DeviceProvider.js.map +0 -1
  284. package/lib/hooks/useDevice/index.cjs +0 -10
  285. package/lib/hooks/useDevice/index.cjs.map +0 -1
  286. package/lib/hooks/useDevice/index.d.ts +0 -2
  287. package/lib/hooks/useDevice/index.js +0 -3
  288. package/lib/hooks/useDevice/index.js.map +0 -1
  289. package/lib/hooks/useDevice/useDevice.cjs +0 -11
  290. package/lib/hooks/useDevice/useDevice.cjs.map +0 -1
  291. package/lib/hooks/useDevice/useDevice.d.ts +0 -4
  292. package/lib/hooks/useDevice/useDevice.js +0 -8
  293. package/lib/hooks/useDevice/useDevice.js.map +0 -1
@@ -6,10 +6,11 @@ var React = require('react');
6
6
  var index$1 = require('../../../_virtual/index3.cjs');
7
7
  var index = require('./../../../vendor/.pnpm/tailwind-variants@0.3.1_tailwindcss@3.4.19_ts-node@10.9.2_@swc_core@1.15.17_@types_node@20.19.35_typescript@5.9.3__/vendor/tailwind-variants/dist/index.cjs');
8
8
  var hooks_useClick = require('../../../hooks/useClick.cjs');
9
+ var hooks_useLatest = require('../../../hooks/useLatest.cjs');
9
10
  var hooks_useTheme = require('../../../hooks/useTheme.cjs');
10
11
  require('../../../intl/IntlProvider.cjs');
11
12
  var intl_useIntl = require('../../../intl/useIntl.cjs');
12
- require('react-intl');
13
+ require('../../../intl/Localizer.cjs');
13
14
  require('../../../_virtual/dayjs.min.cjs');
14
15
  require('../../../intl/TimeFormatter.cjs');
15
16
  var libs_util = require('../../../libs/util.cjs');
@@ -66,6 +67,7 @@ const classNameGenerator = index.tv({
66
67
  },
67
68
  },
68
69
  });
70
+ const SuffixButtons = React.memo(({ onClickClear, clearButtonRef, onClickIcon: onDelegateClickIcon, caretIconColor, destroyButtonIconAlt, classNames, }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(components_Button_UnstyledButton.UnstyledButton, { onClick: onClickClear, ref: clearButtonRef, className: classNames.clearButton, children: jsxRuntime.jsx(components_Icon_FaIcon.FaCircleXmarkIcon, { color: "TEXT_BLACK", alt: destroyButtonIconAlt, className: classNames.clearButtonIcon }) }), jsxRuntime.jsx("span", { role: "presentation", onClick: onDelegateClickIcon, className: classNames.caretDownLayout, children: jsxRuntime.jsx(components_Icon_FaIcon.FaCaretDownIcon, { color: caretIconColor, className: classNames.caretDownIcon }) })] })));
69
71
  const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled, readOnly, required, prefix, error, creatable, placeholder, autoComplete, dropdownHelpMessage, isLoading, width, dropdownWidth = 'auto', className, onChange, onChangeInput, onAdd, onSelect, onClear, onClearClick, onChangeSelected, onFocus, onBlur, onKeyPress, noResultText, style, ...rest }, ref) => {
70
72
  const theme = hooks_useTheme.useTheme();
71
73
  const { localize } = intl_useIntl.useIntl();
@@ -77,6 +79,24 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
77
79
  const [inputValue, setInputValue] = React.useState('');
78
80
  const [isComposing, setIsComposing] = React.useState(false);
79
81
  const [isEditing, setIsEditing] = React.useState(false);
82
+ const latest = hooks_useLatest.useLatest({
83
+ onChange,
84
+ onChangeInput,
85
+ onAdd,
86
+ onSelect,
87
+ onClear,
88
+ onClearClick,
89
+ onChangeSelected,
90
+ onFocus,
91
+ onBlur,
92
+ onKeyPress,
93
+ defaultItem,
94
+ selectedItem,
95
+ isFocused,
96
+ isExpanded,
97
+ isComposing,
98
+ isEditing,
99
+ });
80
100
  React.useImperativeHandle(ref, () => inputRef.current);
81
101
  const { options } = components_Combobox_useOptions.useSingleOptions({
82
102
  items,
@@ -91,49 +111,58 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
91
111
  dropdownWidth,
92
112
  onAdd,
93
113
  onSelect: React.useCallback((selected) => {
94
- onSelect?.(selected);
95
- onChangeSelected?.(selected);
96
- // 制御コンポーネントの場合に親側でinputValueを更新できるように、選択時にonChangeInputを空文字で発火する
97
- onChangeInput?.(EMPTY_INPUT_CHANGE_EVENT);
114
+ latest.onSelect?.(selected);
115
+ latest.onChangeSelected?.(selected);
98
116
  // HINT: Dropdown系コンポーネント内でComboboxを使うと、選択肢がportalで表現されている関係上Dropdownが閉じてしまう
99
117
  // requestAnimationFrameを追加、処理を遅延させることで正常に閉じる/閉じないの判定を行えるようにする
100
118
  requestAnimationFrame(() => {
101
119
  setIsExpanded(false);
120
+ // HINT:
121
+ // - 制御コンポーネントの場合に親側でinputValueを更新できるように、選択時にonChangeInputを空文字で発火する
122
+ // - 対応するdropdownを閉じて以降にonChangeInputを発火する必要がある
123
+ // - 先にclearしてしまうと意図せずこの要素のドロップダウンを閉じる前に他要素の再レンダリングを引き起こす可能性がある
124
+ // - 例えばFilterDropdownなどで当comboboxを使っている場合、レイアウト上comboboxのdropdown以下の要素がクリックされた扱いになってしまい
125
+ // FilterDropdownを意図せず閉じてしまうなどの挙動のバグを引き起こす可能性がある
126
+ latest.onChangeInput?.(EMPTY_INPUT_CHANGE_EVENT);
102
127
  });
103
128
  setIsEditing(false);
104
- }, [onChangeSelected, onSelect, onChangeInput]),
129
+ }, [latest]),
105
130
  isExpanded,
106
131
  isLoading,
107
132
  triggerRef: outerRef,
108
133
  noResultText,
109
134
  });
110
- const selectDefaultItem = React.useMemo(() => (onSelect && defaultItem ? () => onSelect(defaultItem) : NOOP), [onSelect, defaultItem]);
135
+ const selectDefaultItem = React.useCallback(() => {
136
+ if (latest.onSelect && latest.defaultItem) {
137
+ latest.onSelect(latest.defaultItem);
138
+ }
139
+ }, [latest]);
111
140
  const focus = React.useCallback(() => {
112
- onFocus?.();
141
+ latest.onFocus?.();
113
142
  inputRef.current?.focus();
114
143
  setIsFocused(true);
115
- if (!isFocused) {
144
+ if (!latest.isFocused) {
116
145
  setIsExpanded(true);
117
146
  }
118
- }, [onFocus, isFocused]);
147
+ }, [latest]);
119
148
  const unfocus = React.useCallback(() => {
120
- if (!isFocused)
149
+ if (!latest.isFocused)
121
150
  return;
122
- onBlur?.();
151
+ latest.onBlur?.();
123
152
  setIsFocused(false);
124
153
  setIsExpanded(false);
125
154
  setIsEditing(false);
126
- if (selectedItem) {
127
- setInputValue(index$1(selectedItem.label));
155
+ if (latest.selectedItem) {
156
+ setInputValue(index$1(latest.selectedItem.label));
128
157
  }
129
158
  else {
130
159
  selectDefaultItem();
131
160
  }
132
- }, [isFocused, onBlur, selectedItem, selectDefaultItem]);
161
+ }, [selectDefaultItem, latest]);
133
162
  const onClickClear = React.useCallback((e) => {
134
163
  e.stopPropagation();
135
164
  let isExecutedPreventDefault = false;
136
- onClearClick?.({
165
+ latest.onClearClick?.({
137
166
  ...e,
138
167
  preventDefault: () => {
139
168
  e.preventDefault();
@@ -141,44 +170,43 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
141
170
  },
142
171
  });
143
172
  if (!isExecutedPreventDefault) {
144
- onClear?.();
145
- onChangeSelected?.(null);
173
+ latest.onClear?.();
174
+ latest.onChangeSelected?.(null);
146
175
  inputRef.current?.focus();
147
176
  setIsFocused(true);
148
177
  setIsExpanded(true);
149
178
  }
150
- }, [onClearClick, onClear, onChangeSelected]);
179
+ }, [latest]);
151
180
  const onClickInput = React.useCallback((e) => {
152
181
  if (disabled || readOnly) {
153
182
  e.stopPropagation();
154
183
  return;
155
184
  }
156
185
  inputRef.current?.focus();
157
- if (!isExpanded) {
186
+ if (!latest.isExpanded) {
158
187
  setIsExpanded(true);
159
188
  }
160
- }, [disabled, readOnly, inputRef, isExpanded]);
161
- const onDelegateClickIcon = onClickInput;
189
+ }, [disabled, readOnly, latest]);
162
190
  const actualOnChangeInput = React.useCallback((e) => {
163
- onChange?.(e);
164
- onChangeInput?.(e);
165
- if (!isEditing)
191
+ latest.onChange?.(e);
192
+ latest.onChangeInput?.(e);
193
+ if (!latest.isEditing)
166
194
  setIsEditing(true);
167
195
  const { value } = e.currentTarget;
168
196
  setInputValue(value);
169
197
  if (value === '') {
170
- onClear?.();
171
- onChangeSelected?.(null);
198
+ latest.onClear?.();
199
+ latest.onChangeSelected?.(null);
172
200
  }
173
- }, [isEditing, onChange, onChangeInput, onClear, onChangeSelected]);
201
+ }, [latest]);
174
202
  const onCompositionStart = React.useCallback(() => setIsComposing(true), []);
175
203
  const onCompositionEnd = React.useCallback(() => setIsComposing(false), []);
176
204
  const onKeyDownInput = React.useCallback((e) => {
177
- if (isComposing) {
205
+ if (latest.isComposing) {
178
206
  return;
179
207
  }
180
208
  if (ESCAPE_KEY_REGEX.test(e.key)) {
181
- if (isExpanded) {
209
+ if (latest.isExpanded) {
182
210
  e.stopPropagation();
183
211
  setIsExpanded(false);
184
212
  }
@@ -191,28 +219,26 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
191
219
  e.preventDefault();
192
220
  }
193
221
  inputRef.current?.focus();
194
- if (!isExpanded) {
222
+ if (!latest.isExpanded) {
195
223
  setIsExpanded(true);
196
224
  }
197
225
  }
198
226
  onKeyDownListBox(e);
199
- }, [isComposing, isExpanded, unfocus, onKeyDownListBox]);
227
+ }, [unfocus, onKeyDownListBox, latest]);
200
228
  // HINT: form内にcomboboxを設置 & 検索inputにfocusした状態で
201
229
  // アイテムをキーボードで選択し、Enterを押すとinput上でEnterを押したことになるため、
202
230
  // submitイベントが発生し、formが送信される場合がある
203
231
  const handleKeyPress = React.useCallback((e) => {
204
232
  if (e.key === 'Enter')
205
233
  e.preventDefault();
206
- onKeyPress?.(e);
207
- }, [onKeyPress]);
208
- const caretIconColor = React.useMemo(() => {
209
- if (isFocused)
210
- return theme.textColor.black;
211
- if (disabled || readOnly)
212
- return theme.textColor.disabled;
213
- return theme.textColor.grey;
214
- }, [disabled, readOnly, isFocused, theme.textColor]);
215
- hooks_useClick.useClick(React.useMemo(() => [outerRef, listBoxRef, clearButtonRef], [outerRef, listBoxRef, clearButtonRef]), isFocused || selectedItem ? NOOP : selectDefaultItem, unfocus);
234
+ latest.onKeyPress?.(e);
235
+ }, [latest]);
236
+ const caretIconColor = isFocused
237
+ ? theme.textColor.black
238
+ : disabled || readOnly
239
+ ? theme.textColor.disabled
240
+ : theme.textColor.grey;
241
+ hooks_useClick.useClick(React.useMemo(() => [outerRef, listBoxRef, clearButtonRef], [listBoxRef]), isFocused || selectedItem ? NOOP : selectDefaultItem, unfocus);
216
242
  // selectedItem.label はプリミティブ値でないデータ型の可能性があり、そのまま useEffect の依存配列に入れると意図せぬエフェクトの実行を引き起こしてしまう可能性があるので、プリミティブ値である string 型に変換したものを依存配列に入れています。
217
243
  const selectedItemLabelText = index$1(selectedItem?.label);
218
244
  React.useEffect(() => {
@@ -222,7 +248,7 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
222
248
  ...style,
223
249
  width: typeof width === 'number' ? `${width}px` : width,
224
250
  }), [style, width]);
225
- const notSelected = selectedItem === null;
251
+ const hasSelectedItem = selectedItem !== null;
226
252
  const classNames = React.useMemo(() => {
227
253
  const { wrapper, input, caretDownLayout, caretDownIcon, clearButton, clearButtonIcon } = classNameGenerator();
228
254
  return {
@@ -230,17 +256,24 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
230
256
  input: input(),
231
257
  caretDownLayout: caretDownLayout(),
232
258
  caretDownIcon: caretDownIcon(),
233
- clearButton: clearButton({ hidden: notSelected || disabled || readOnly }),
259
+ clearButton: clearButton({
260
+ hidden: !hasSelectedItem || disabled || readOnly,
261
+ }),
234
262
  clearButtonIcon: clearButtonIcon(),
235
263
  };
236
- }, [notSelected, disabled, readOnly, className]);
264
+ }, [hasSelectedItem, disabled, readOnly, className]);
237
265
  const destroyButtonIconAlt = React.useMemo(() => localize({
238
266
  id: 'smarthr-ui/SingleCombobox/destroyButtonIconAlt',
239
267
  defaultText: 'クリア',
240
268
  }), [localize]);
241
269
  return (jsxRuntime.jsxs("div", { role: "group", className: classNames.wrapper, style: wrapperStyle, ref: outerRef, children: [jsxRuntime.jsx(components_Input_Input.Input, { ...rest, ref: inputRef, type: "text", role: "combobox", name: name, value: inputValue, disabled: disabled, readOnly: readOnly, required: required, autoComplete: autoComplete ?? 'off', "aria-haspopup": "listbox", "aria-controls": listBoxId, "aria-expanded": isFocused, "aria-activedescendant": activeOption?.id, "aria-autocomplete": "list",
242
270
  /* eslint-disable-next-line smarthr/a11y-prohibit-input-placeholder */
243
- placeholder: placeholder, onClick: onClickInput, onChange: actualOnChangeInput, onFocus: isFocused ? undefined : focus, onCompositionStart: onCompositionStart, onCompositionEnd: onCompositionEnd, onKeyDown: onKeyDownInput, onKeyPress: handleKeyPress, error: error, prefix: prefix, suffix: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(components_Button_UnstyledButton.UnstyledButton, { onClick: onClickClear, ref: clearButtonRef, className: classNames.clearButton, children: jsxRuntime.jsx(components_Icon_FaIcon.FaCircleXmarkIcon, { color: "TEXT_BLACK", alt: destroyButtonIconAlt, className: classNames.clearButtonIcon }) }), jsxRuntime.jsx("span", { role: "presentation", onClick: onDelegateClickIcon, className: classNames.caretDownLayout, children: jsxRuntime.jsx(components_Icon_FaIcon.FaCaretDownIcon, { color: caretIconColor, className: classNames.caretDownIcon }) })] }), className: classNames.input, "data-smarthr-ui-input": "true" }), !readOnly && renderListBox()] }));
271
+ placeholder: placeholder, onClick: onClickInput, onChange: actualOnChangeInput, onFocus: isFocused ? undefined : focus, onCompositionStart: onCompositionStart, onCompositionEnd: onCompositionEnd, onKeyDown: onKeyDownInput, onKeyPress: handleKeyPress, error: error, prefix: prefix, suffix: jsxRuntime.jsx(SuffixButtons, { onClickClear: onClickClear, clearButtonRef: clearButtonRef, onClickIcon: onClickInput, caretIconColor: caretIconColor, destroyButtonIconAlt: destroyButtonIconAlt, classNames: {
272
+ clearButton: classNames.clearButton,
273
+ clearButtonIcon: classNames.clearButtonIcon,
274
+ caretDownLayout: classNames.caretDownLayout,
275
+ caretDownIcon: classNames.caretDownIcon,
276
+ } }), className: classNames.input, "data-smarthr-ui-input": "true" }), !readOnly && renderListBox()] }));
244
277
  };
245
278
  const SingleCombobox = libs_util.genericsForwardRef(ActualSingleCombobox);
246
279
 
@@ -1 +1 @@
1
- {"version":3,"file":"SingleCombobox.cjs","sources":["../../../../src/components/Combobox/SingleCombobox/SingleCombobox.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n type Ref,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport innerText from 'react-innertext'\nimport { tv } from 'tailwind-variants'\n\nimport { useClick } from '../../../hooks/useClick'\nimport { useTheme } from '../../../hooks/useTheme'\nimport { useIntl } from '../../../intl'\nimport { genericsForwardRef } from '../../../libs/util'\nimport { UnstyledButton } from '../../Button'\nimport { FaCaretDownIcon, FaCircleXmarkIcon } from '../../Icon'\nimport { Input } from '../../Input'\nimport { useListbox } from '../useListbox'\nimport { useSingleOptions } from '../useOptions'\n\nimport type { ComboboxItem, AbstractProps as ComboboxProps } from '../types'\n\ntype AbstractProps<T> = ComboboxProps<T> & {\n /**\n * 選択されているアイテム\n */\n selectedItem: ComboboxItem<T> | null\n /**\n * デフォルトで選択されるアイテム\n */\n defaultItem?: ComboboxItem<T>\n /**\n * コンポーネント内の先頭に表示する内容\n */\n prefix?: ReactNode\n /**\n * 選択されているアイテムがクリアされた時に発火するコールバック関数\n */\n onClear?: () => void\n /**\n * 選択されているアイテムがクリアされた時に発火するコールバック関数\n * 指定している場合、クリア時にonClickを実行せずにonClearClickのみ実行する\n */\n onClearClick?: (e: MouseEvent) => void\n /**\n * 選択されているアイテムのリストが変わった時に発火するコールバック関数\n */\n onChangeSelected?: (selectedItem: ComboboxItem<T> | null) => void\n /**\n * コンポーネントがフォーカスされたときに発火するコールバック関数\n */\n onFocus?: () => void\n /**\n * コンポーネントからフォーカスが外れた時に発火するコールバック関数\n */\n onBlur?: () => void\n /**\n * 検索結果が0件の時に表示するコンテンツ\n */\n noResultText?: ReactNode\n}\ntype Props<T> = AbstractProps<T> &\n Omit<ComponentPropsWithoutRef<'input'>, keyof AbstractProps<unknown>>\n\nconst NOOP = () => undefined\n\nconst ESCAPE_KEY_REGEX = /^Esc(ape)?$/\nconst ARROW_UP_DOWN_REGEX = /^(Arrow)?(Up|Down)$/\n\nconst EMPTY_INPUT_CHANGE_EVENT = {\n currentTarget: { value: '' },\n target: { value: '' },\n} as ChangeEvent<HTMLInputElement>\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-SingleCombobox shr-inline-block',\n input: 'smarthr-ui-SingleCombobox-input shr-w-full',\n caretDownLayout: [\n 'shr-relative -shr-me-0.5 shr-p-0.5',\n 'before:shr-border-0',\n 'before:shr-absolute before:shr-inset-x-0 before:shr-inset-y-0.25 before:shr-w-0 before:shr-border-l before:shr-border-solid before:shr-border-default before:shr-content-[\"\"]',\n ],\n caretDownIcon: 'shr-block',\n clearButton: [\n 'smarthr-ui-SingleCombobox-clearButton',\n 'shr-group/clearButton',\n 'shr-me-0.5',\n 'focus-visible:shr-shadow-none',\n ],\n clearButtonIcon: [\n 'shr-block',\n 'group-focus-visible/clearButton:shr-focus-indicator group-focus-visible/clearButton:shr-rounded-full',\n ],\n },\n variants: {\n disabled: {\n true: {\n wrapper: 'shr-cursor-not-allowed',\n },\n },\n hidden: {\n true: {\n clearButton: 'shr-hidden',\n },\n },\n },\n})\n\nconst ActualSingleCombobox = <T,>(\n {\n items,\n selectedItem,\n defaultItem,\n name,\n disabled,\n readOnly,\n required,\n prefix,\n error,\n creatable,\n placeholder,\n autoComplete,\n dropdownHelpMessage,\n isLoading,\n width,\n dropdownWidth = 'auto',\n className,\n onChange,\n onChangeInput,\n onAdd,\n onSelect,\n onClear,\n onClearClick,\n onChangeSelected,\n onFocus,\n onBlur,\n onKeyPress,\n noResultText,\n style,\n ...rest\n }: Props<T>,\n ref: Ref<HTMLInputElement>,\n) => {\n const theme = useTheme()\n const { localize } = useIntl()\n const outerRef = useRef<HTMLDivElement>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const clearButtonRef = useRef<HTMLButtonElement>(null)\n const [isFocused, setIsFocused] = useState(false)\n const [isExpanded, setIsExpanded] = useState(false)\n const [inputValue, setInputValue] = useState('')\n const [isComposing, setIsComposing] = useState(false)\n const [isEditing, setIsEditing] = useState(false)\n\n useImperativeHandle<HTMLInputElement | null, HTMLInputElement | null>(ref, () => inputRef.current)\n\n const { options } = useSingleOptions({\n items,\n selected: selectedItem,\n creatable,\n inputValue,\n isFilteringDisabled: !isEditing,\n })\n\n const { renderListBox, activeOption, onKeyDownListBox, listBoxId, listBoxRef } = useListbox<T>({\n options,\n dropdownHelpMessage,\n dropdownWidth,\n onAdd,\n onSelect: useCallback(\n (selected: ComboboxItem<T>) => {\n onSelect?.(selected)\n onChangeSelected?.(selected)\n\n // 制御コンポーネントの場合に親側でinputValueを更新できるように、選択時にonChangeInputを空文字で発火する\n onChangeInput?.(EMPTY_INPUT_CHANGE_EVENT)\n\n // HINT: Dropdown系コンポーネント内でComboboxを使うと、選択肢がportalで表現されている関係上Dropdownが閉じてしまう\n // requestAnimationFrameを追加、処理を遅延させることで正常に閉じる/閉じないの判定を行えるようにする\n requestAnimationFrame(() => {\n setIsExpanded(false)\n })\n\n setIsEditing(false)\n },\n [onChangeSelected, onSelect, onChangeInput],\n ),\n isExpanded,\n isLoading,\n triggerRef: outerRef,\n noResultText,\n })\n\n const selectDefaultItem = useMemo(\n () => (onSelect && defaultItem ? () => onSelect(defaultItem) : NOOP),\n [onSelect, defaultItem],\n )\n\n const focus = useCallback(() => {\n onFocus?.()\n inputRef.current?.focus()\n setIsFocused(true)\n\n if (!isFocused) {\n setIsExpanded(true)\n }\n }, [onFocus, isFocused])\n const unfocus = useCallback(() => {\n if (!isFocused) return\n\n onBlur?.()\n\n setIsFocused(false)\n setIsExpanded(false)\n setIsEditing(false)\n\n if (selectedItem) {\n setInputValue(innerText(selectedItem.label))\n } else {\n selectDefaultItem()\n }\n }, [isFocused, onBlur, selectedItem, selectDefaultItem])\n const onClickClear = useCallback(\n (e: MouseEvent) => {\n e.stopPropagation()\n\n let isExecutedPreventDefault = false\n\n onClearClick?.({\n ...e,\n preventDefault: () => {\n e.preventDefault()\n isExecutedPreventDefault = true\n },\n })\n\n if (!isExecutedPreventDefault) {\n onClear?.()\n onChangeSelected?.(null)\n\n inputRef.current?.focus()\n\n setIsFocused(true)\n setIsExpanded(true)\n }\n },\n [onClearClick, onClear, onChangeSelected],\n )\n const onClickInput = useCallback(\n (e: MouseEvent) => {\n if (disabled || readOnly) {\n e.stopPropagation()\n\n return\n }\n\n inputRef.current?.focus()\n\n if (!isExpanded) {\n setIsExpanded(true)\n }\n },\n [disabled, readOnly, inputRef, isExpanded],\n )\n const onDelegateClickIcon = onClickInput\n const actualOnChangeInput = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n onChange?.(e)\n onChangeInput?.(e)\n\n if (!isEditing) setIsEditing(true)\n\n const { value } = e.currentTarget\n\n setInputValue(value)\n\n if (value === '') {\n onClear?.()\n onChangeSelected?.(null)\n }\n },\n [isEditing, onChange, onChangeInput, onClear, onChangeSelected],\n )\n const onCompositionStart = useCallback(() => setIsComposing(true), [])\n const onCompositionEnd = useCallback(() => setIsComposing(false), [])\n const onKeyDownInput = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (isComposing) {\n return\n }\n\n if (ESCAPE_KEY_REGEX.test(e.key)) {\n if (isExpanded) {\n e.stopPropagation()\n setIsExpanded(false)\n }\n } else if (e.key === 'Tab') {\n unfocus()\n } else {\n if (ARROW_UP_DOWN_REGEX.test(e.key)) {\n e.preventDefault()\n }\n\n inputRef.current?.focus()\n\n if (!isExpanded) {\n setIsExpanded(true)\n }\n }\n onKeyDownListBox(e)\n },\n [isComposing, isExpanded, unfocus, onKeyDownListBox],\n )\n\n // HINT: form内にcomboboxを設置 & 検索inputにfocusした状態で\n // アイテムをキーボードで選択し、Enterを押すとinput上でEnterを押したことになるため、\n // submitイベントが発生し、formが送信される場合がある\n const handleKeyPress = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') e.preventDefault()\n\n onKeyPress?.(e)\n },\n [onKeyPress],\n )\n\n const caretIconColor = useMemo(() => {\n if (isFocused) return theme.textColor.black\n if (disabled || readOnly) return theme.textColor.disabled\n\n return theme.textColor.grey\n }, [disabled, readOnly, isFocused, theme.textColor])\n\n useClick(\n useMemo(() => [outerRef, listBoxRef, clearButtonRef], [outerRef, listBoxRef, clearButtonRef]),\n isFocused || selectedItem ? NOOP : selectDefaultItem,\n unfocus,\n )\n\n // selectedItem.label はプリミティブ値でないデータ型の可能性があり、そのまま useEffect の依存配列に入れると意図せぬエフェクトの実行を引き起こしてしまう可能性があるので、プリミティブ値である string 型に変換したものを依存配列に入れています。\n const selectedItemLabelText = innerText(selectedItem?.label)\n useEffect(() => {\n setInputValue(selectedItemLabelText)\n }, [selectedItemLabelText])\n\n const wrapperStyle = useMemo(\n () => ({\n ...style,\n width: typeof width === 'number' ? `${width}px` : width,\n }),\n [style, width],\n )\n\n const notSelected = selectedItem === null\n\n const classNames = useMemo(() => {\n const { wrapper, input, caretDownLayout, caretDownIcon, clearButton, clearButtonIcon } =\n classNameGenerator()\n\n return {\n wrapper: wrapper({ disabled, className }),\n input: input(),\n caretDownLayout: caretDownLayout(),\n caretDownIcon: caretDownIcon(),\n clearButton: clearButton({ hidden: notSelected || disabled || readOnly }),\n clearButtonIcon: clearButtonIcon(),\n }\n }, [notSelected, disabled, readOnly, className])\n\n const destroyButtonIconAlt = useMemo(\n () =>\n localize({\n id: 'smarthr-ui/SingleCombobox/destroyButtonIconAlt',\n defaultText: 'クリア',\n }),\n [localize],\n )\n\n return (\n <div role=\"group\" className={classNames.wrapper} style={wrapperStyle} ref={outerRef}>\n <Input\n {...rest}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n name={name}\n value={inputValue}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n autoComplete={autoComplete ?? 'off'}\n aria-haspopup=\"listbox\"\n aria-controls={listBoxId}\n aria-expanded={isFocused}\n aria-activedescendant={activeOption?.id}\n aria-autocomplete=\"list\"\n /* eslint-disable-next-line smarthr/a11y-prohibit-input-placeholder */\n placeholder={placeholder}\n onClick={onClickInput}\n onChange={actualOnChangeInput}\n onFocus={isFocused ? undefined : focus}\n onCompositionStart={onCompositionStart}\n onCompositionEnd={onCompositionEnd}\n onKeyDown={onKeyDownInput}\n onKeyPress={handleKeyPress}\n error={error}\n prefix={prefix}\n suffix={\n <>\n <UnstyledButton\n onClick={onClickClear}\n ref={clearButtonRef}\n className={classNames.clearButton}\n >\n <FaCircleXmarkIcon\n color=\"TEXT_BLACK\"\n alt={destroyButtonIconAlt}\n className={classNames.clearButtonIcon}\n />\n </UnstyledButton>\n <span\n role=\"presentation\"\n onClick={onDelegateClickIcon}\n className={classNames.caretDownLayout}\n >\n <FaCaretDownIcon color={caretIconColor} className={classNames.caretDownIcon} />\n </span>\n </>\n }\n className={classNames.input}\n data-smarthr-ui-input=\"true\"\n />\n {!readOnly && renderListBox()}\n </div>\n )\n}\n\nexport const SingleCombobox = genericsForwardRef(ActualSingleCombobox)\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAyEA;AAEA;AACA;AAEA;AACE;AACA;;AAGF;AACE;AACE;AACA;AACA;;;;AAIC;AACD;AACA;;;;;AAKC;AACD;;;AAGC;AACF;AACD;AACE;AACE;AACE;AACD;AACF;AACD;AACE;AACE;AACD;AACF;AACF;AACF;AAED;AAmCE;AACA;AACA;AACA;AACA;;;;;;;AASA;;AAEE;;;;AAID;AAED;;;;;AAKE;AAEI;AACA;;AAGA;;;;;AAMA;;;;;AAQJ;;AAED;AAED;AAKA;;AAEE;;;;;AAMF;AACA;AACE;;;;;;;;;;AAWE;;;AAGJ;;;AAMI;AACE;;;;;AAKD;;;AAIC;AAEA;;;;;AAQN;AAEI;;;;AAMA;;;;;;AASJ;AAEI;AACA;AAEA;;AAEA;;AAIA;;AAEE;;AAEJ;AAGF;AACA;AACA;;;;;;;;;;AAWW;AACL;;;;;;AAMA;;;;;;;;;;AAcN;AAEI;;AAEA;AACF;AAIF;AACE;AAAe;;AACW;AAE1B;AACF;AAEA;;;;;AAUA;AAEA;AAEI;AACA;AACD;AAIH;AAEA;AACE;;;;;;AAQE;;;;;AAQE;AACA;AACD;AAIL;;AAmBM;AAsCR;;;"}
1
+ {"version":3,"file":"SingleCombobox.cjs","sources":["../../../../src/components/Combobox/SingleCombobox/SingleCombobox.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n type Ref,\n type RefObject,\n memo,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport innerText from 'react-innertext'\nimport { tv } from 'tailwind-variants'\n\nimport { useClick } from '../../../hooks/useClick'\nimport { useLatest } from '../../../hooks/useLatest'\nimport { useTheme } from '../../../hooks/useTheme'\nimport { useIntl } from '../../../intl'\nimport { genericsForwardRef } from '../../../libs/util'\nimport { UnstyledButton } from '../../Button'\nimport { FaCaretDownIcon, FaCircleXmarkIcon } from '../../Icon'\nimport { Input } from '../../Input'\nimport { useListbox } from '../useListbox'\nimport { useSingleOptions } from '../useOptions'\n\nimport type { ComboboxItem, AbstractProps as ComboboxProps } from '../types'\n\ntype AbstractProps<T> = ComboboxProps<T> & {\n /**\n * 選択されているアイテム\n */\n selectedItem: ComboboxItem<T> | null\n /**\n * デフォルトで選択されるアイテム\n */\n defaultItem?: ComboboxItem<T>\n /**\n * コンポーネント内の先頭に表示する内容\n */\n prefix?: ReactNode\n /**\n * 選択されているアイテムがクリアされた時に発火するコールバック関数\n */\n onClear?: () => void\n /**\n * 選択されているアイテムがクリアされた時に発火するコールバック関数\n * 指定している場合、クリア時にonClickを実行せずにonClearClickのみ実行する\n */\n onClearClick?: (e: MouseEvent) => void\n /**\n * 選択されているアイテムのリストが変わった時に発火するコールバック関数\n */\n onChangeSelected?: (selectedItem: ComboboxItem<T> | null) => void\n /**\n * コンポーネントがフォーカスされたときに発火するコールバック関数\n */\n onFocus?: () => void\n /**\n * コンポーネントからフォーカスが外れた時に発火するコールバック関数\n */\n onBlur?: () => void\n /**\n * 検索結果が0件の時に表示するコンテンツ\n */\n noResultText?: ReactNode\n}\ntype Props<T> = AbstractProps<T> &\n Omit<ComponentPropsWithoutRef<'input'>, keyof AbstractProps<unknown>>\n\nconst NOOP = () => undefined\n\nconst ESCAPE_KEY_REGEX = /^Esc(ape)?$/\nconst ARROW_UP_DOWN_REGEX = /^(Arrow)?(Up|Down)$/\n\nconst EMPTY_INPUT_CHANGE_EVENT = {\n currentTarget: { value: '' },\n target: { value: '' },\n} as ChangeEvent<HTMLInputElement>\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-SingleCombobox shr-inline-block',\n input: 'smarthr-ui-SingleCombobox-input shr-w-full',\n caretDownLayout: [\n 'shr-relative -shr-me-0.5 shr-p-0.5',\n 'before:shr-border-0',\n 'before:shr-absolute before:shr-inset-x-0 before:shr-inset-y-0.25 before:shr-w-0 before:shr-border-l before:shr-border-solid before:shr-border-default before:shr-content-[\"\"]',\n ],\n caretDownIcon: 'shr-block',\n clearButton: [\n 'smarthr-ui-SingleCombobox-clearButton',\n 'shr-group/clearButton',\n 'shr-me-0.5',\n 'focus-visible:shr-shadow-none',\n ],\n clearButtonIcon: [\n 'shr-block',\n 'group-focus-visible/clearButton:shr-focus-indicator group-focus-visible/clearButton:shr-rounded-full',\n ],\n },\n variants: {\n disabled: {\n true: {\n wrapper: 'shr-cursor-not-allowed',\n },\n },\n hidden: {\n true: {\n clearButton: 'shr-hidden',\n },\n },\n },\n})\n\ntype SuffixButtonsProps = {\n onClickClear: (e: MouseEvent) => void\n clearButtonRef: RefObject<HTMLButtonElement>\n onClickIcon: (e: MouseEvent) => void\n caretIconColor: string\n destroyButtonIconAlt: string\n classNames: {\n clearButton: string\n clearButtonIcon: string\n caretDownLayout: string\n caretDownIcon: string\n }\n}\n\nconst SuffixButtons = memo<SuffixButtonsProps>(\n ({\n onClickClear,\n clearButtonRef,\n onClickIcon: onDelegateClickIcon,\n caretIconColor,\n destroyButtonIconAlt,\n classNames,\n }) => (\n <>\n <UnstyledButton\n onClick={onClickClear}\n ref={clearButtonRef}\n className={classNames.clearButton}\n >\n <FaCircleXmarkIcon\n color=\"TEXT_BLACK\"\n alt={destroyButtonIconAlt}\n className={classNames.clearButtonIcon}\n />\n </UnstyledButton>\n <span\n role=\"presentation\"\n onClick={onDelegateClickIcon}\n className={classNames.caretDownLayout}\n >\n <FaCaretDownIcon color={caretIconColor} className={classNames.caretDownIcon} />\n </span>\n </>\n ),\n)\n\nconst ActualSingleCombobox = <T,>(\n {\n items,\n selectedItem,\n defaultItem,\n name,\n disabled,\n readOnly,\n required,\n prefix,\n error,\n creatable,\n placeholder,\n autoComplete,\n dropdownHelpMessage,\n isLoading,\n width,\n dropdownWidth = 'auto',\n className,\n onChange,\n onChangeInput,\n onAdd,\n onSelect,\n onClear,\n onClearClick,\n onChangeSelected,\n onFocus,\n onBlur,\n onKeyPress,\n noResultText,\n style,\n ...rest\n }: Props<T>,\n ref: Ref<HTMLInputElement>,\n) => {\n const theme = useTheme()\n const { localize } = useIntl()\n const outerRef = useRef<HTMLDivElement>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const clearButtonRef = useRef<HTMLButtonElement>(null)\n const [isFocused, setIsFocused] = useState(false)\n const [isExpanded, setIsExpanded] = useState(false)\n const [inputValue, setInputValue] = useState('')\n const [isComposing, setIsComposing] = useState(false)\n const [isEditing, setIsEditing] = useState(false)\n\n const latest = useLatest({\n onChange,\n onChangeInput,\n onAdd,\n onSelect,\n onClear,\n onClearClick,\n onChangeSelected,\n onFocus,\n onBlur,\n onKeyPress,\n defaultItem,\n selectedItem,\n isFocused,\n isExpanded,\n isComposing,\n isEditing,\n })\n\n useImperativeHandle<HTMLInputElement | null, HTMLInputElement | null>(ref, () => inputRef.current)\n\n const { options } = useSingleOptions({\n items,\n selected: selectedItem,\n creatable,\n inputValue,\n isFilteringDisabled: !isEditing,\n })\n\n const { renderListBox, activeOption, onKeyDownListBox, listBoxId, listBoxRef } = useListbox<T>({\n options,\n dropdownHelpMessage,\n dropdownWidth,\n onAdd,\n onSelect: useCallback(\n (selected: ComboboxItem<T>) => {\n latest.onSelect?.(selected)\n latest.onChangeSelected?.(selected)\n\n // HINT: Dropdown系コンポーネント内でComboboxを使うと、選択肢がportalで表現されている関係上Dropdownが閉じてしまう\n // requestAnimationFrameを追加、処理を遅延させることで正常に閉じる/閉じないの判定を行えるようにする\n requestAnimationFrame(() => {\n setIsExpanded(false)\n // HINT:\n // - 制御コンポーネントの場合に親側でinputValueを更新できるように、選択時にonChangeInputを空文字で発火する\n // - 対応するdropdownを閉じて以降にonChangeInputを発火する必要がある\n // - 先にclearしてしまうと意図せずこの要素のドロップダウンを閉じる前に他要素の再レンダリングを引き起こす可能性がある\n // - 例えばFilterDropdownなどで当comboboxを使っている場合、レイアウト上comboboxのdropdown以下の要素がクリックされた扱いになってしまい\n // FilterDropdownを意図せず閉じてしまうなどの挙動のバグを引き起こす可能性がある\n latest.onChangeInput?.(EMPTY_INPUT_CHANGE_EVENT)\n })\n\n setIsEditing(false)\n },\n [latest],\n ),\n isExpanded,\n isLoading,\n triggerRef: outerRef,\n noResultText,\n })\n\n const selectDefaultItem = useCallback(() => {\n if (latest.onSelect && latest.defaultItem) {\n latest.onSelect(latest.defaultItem)\n }\n }, [latest])\n\n const focus = useCallback(() => {\n latest.onFocus?.()\n inputRef.current?.focus()\n setIsFocused(true)\n\n if (!latest.isFocused) {\n setIsExpanded(true)\n }\n }, [latest])\n const unfocus = useCallback(() => {\n if (!latest.isFocused) return\n\n latest.onBlur?.()\n\n setIsFocused(false)\n setIsExpanded(false)\n setIsEditing(false)\n\n if (latest.selectedItem) {\n setInputValue(innerText(latest.selectedItem.label))\n } else {\n selectDefaultItem()\n }\n }, [selectDefaultItem, latest])\n const onClickClear = useCallback(\n (e: MouseEvent) => {\n e.stopPropagation()\n\n let isExecutedPreventDefault = false\n\n latest.onClearClick?.({\n ...e,\n preventDefault: () => {\n e.preventDefault()\n isExecutedPreventDefault = true\n },\n })\n\n if (!isExecutedPreventDefault) {\n latest.onClear?.()\n latest.onChangeSelected?.(null)\n\n inputRef.current?.focus()\n\n setIsFocused(true)\n setIsExpanded(true)\n }\n },\n [latest],\n )\n const onClickInput = useCallback(\n (e: MouseEvent) => {\n if (disabled || readOnly) {\n e.stopPropagation()\n\n return\n }\n\n inputRef.current?.focus()\n\n if (!latest.isExpanded) {\n setIsExpanded(true)\n }\n },\n [disabled, readOnly, latest],\n )\n const actualOnChangeInput = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n latest.onChange?.(e)\n latest.onChangeInput?.(e)\n\n if (!latest.isEditing) setIsEditing(true)\n\n const { value } = e.currentTarget\n\n setInputValue(value)\n\n if (value === '') {\n latest.onClear?.()\n latest.onChangeSelected?.(null)\n }\n },\n [latest],\n )\n const onCompositionStart = useCallback(() => setIsComposing(true), [])\n const onCompositionEnd = useCallback(() => setIsComposing(false), [])\n const onKeyDownInput = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (latest.isComposing) {\n return\n }\n\n if (ESCAPE_KEY_REGEX.test(e.key)) {\n if (latest.isExpanded) {\n e.stopPropagation()\n setIsExpanded(false)\n }\n } else if (e.key === 'Tab') {\n unfocus()\n } else {\n if (ARROW_UP_DOWN_REGEX.test(e.key)) {\n e.preventDefault()\n }\n\n inputRef.current?.focus()\n\n if (!latest.isExpanded) {\n setIsExpanded(true)\n }\n }\n onKeyDownListBox(e)\n },\n [unfocus, onKeyDownListBox, latest],\n )\n\n // HINT: form内にcomboboxを設置 & 検索inputにfocusした状態で\n // アイテムをキーボードで選択し、Enterを押すとinput上でEnterを押したことになるため、\n // submitイベントが発生し、formが送信される場合がある\n const handleKeyPress = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') e.preventDefault()\n\n latest.onKeyPress?.(e)\n },\n [latest],\n )\n\n const caretIconColor = isFocused\n ? theme.textColor.black\n : disabled || readOnly\n ? theme.textColor.disabled\n : theme.textColor.grey\n\n useClick(\n useMemo(() => [outerRef, listBoxRef, clearButtonRef], [listBoxRef]),\n isFocused || selectedItem ? NOOP : selectDefaultItem,\n unfocus,\n )\n\n // selectedItem.label はプリミティブ値でないデータ型の可能性があり、そのまま useEffect の依存配列に入れると意図せぬエフェクトの実行を引き起こしてしまう可能性があるので、プリミティブ値である string 型に変換したものを依存配列に入れています。\n const selectedItemLabelText = innerText(selectedItem?.label)\n useEffect(() => {\n setInputValue(selectedItemLabelText)\n }, [selectedItemLabelText])\n\n const wrapperStyle = useMemo(\n () => ({\n ...style,\n width: typeof width === 'number' ? `${width}px` : width,\n }),\n [style, width],\n )\n\n const hasSelectedItem = selectedItem !== null\n\n const classNames = useMemo(() => {\n const { wrapper, input, caretDownLayout, caretDownIcon, clearButton, clearButtonIcon } =\n classNameGenerator()\n\n return {\n wrapper: wrapper({ disabled, className }),\n input: input(),\n caretDownLayout: caretDownLayout(),\n caretDownIcon: caretDownIcon(),\n clearButton: clearButton({\n hidden: !hasSelectedItem || disabled || readOnly,\n }),\n clearButtonIcon: clearButtonIcon(),\n }\n }, [hasSelectedItem, disabled, readOnly, className])\n\n const destroyButtonIconAlt = useMemo(\n () =>\n localize({\n id: 'smarthr-ui/SingleCombobox/destroyButtonIconAlt',\n defaultText: 'クリア',\n }),\n [localize],\n )\n\n return (\n <div role=\"group\" className={classNames.wrapper} style={wrapperStyle} ref={outerRef}>\n <Input\n {...rest}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n name={name}\n value={inputValue}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n autoComplete={autoComplete ?? 'off'}\n aria-haspopup=\"listbox\"\n aria-controls={listBoxId}\n aria-expanded={isFocused}\n aria-activedescendant={activeOption?.id}\n aria-autocomplete=\"list\"\n /* eslint-disable-next-line smarthr/a11y-prohibit-input-placeholder */\n placeholder={placeholder}\n onClick={onClickInput}\n onChange={actualOnChangeInput}\n onFocus={isFocused ? undefined : focus}\n onCompositionStart={onCompositionStart}\n onCompositionEnd={onCompositionEnd}\n onKeyDown={onKeyDownInput}\n onKeyPress={handleKeyPress}\n error={error}\n prefix={prefix}\n suffix={\n <SuffixButtons\n onClickClear={onClickClear}\n clearButtonRef={clearButtonRef}\n onClickIcon={onClickInput}\n caretIconColor={caretIconColor}\n destroyButtonIconAlt={destroyButtonIconAlt}\n classNames={{\n clearButton: classNames.clearButton,\n clearButtonIcon: classNames.clearButtonIcon,\n caretDownLayout: classNames.caretDownLayout,\n caretDownIcon: classNames.caretDownIcon,\n }}\n />\n }\n className={classNames.input}\n data-smarthr-ui-input=\"true\"\n />\n {!readOnly && renderListBox()}\n </div>\n )\n}\n\nexport const SingleCombobox = genericsForwardRef(ActualSingleCombobox)\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4EA;AAEA;AACA;AAEA;AACE;AACA;;AAGF;AACE;AACE;AACA;AACA;;;;AAIC;AACD;AACA;;;;;AAKC;AACD;;;AAGC;AACF;AACD;AACE;AACE;AACE;AACD;AACF;AACD;AACE;AACE;AACD;AACF;AACF;AACF;AAgBD;AAgCA;AAmCE;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;AAwBC;;AAID;;AAEE;;;;AAID;AAED;;;;;AAKE;AAEI;AACA;;;;;;;;;;;AAYE;AACF;;AAGF;;;AAKF;;AAED;AAED;;AAEI;;AAEJ;AAEA;AACE;AACA;;AAGA;;;AAGF;AACA;;;AAGE;;;;AAMA;;;;AAGE;;AAEJ;AACA;;;;AAOM;;;;;AAKD;;AAGC;AACA;AAEA;;;;AAKJ;AAGF;AAEI;;;;AAMA;AAEA;;;;AAMJ;AAEI;AACA;;;AAIA;;AAIA;AACE;AACA;;AAEJ;AAGF;AACA;AACA;AAEI;;;;AAKE;;;;;AAIK;AACL;;;;;;AAMA;AAEA;;;;;;;;;AAYN;AAEI;;AAEA;AACF;;AAKA;;AAEE;AACA;AAEJ;;;;;AAUA;AAEA;AAEI;AACA;AACD;AAIH;AAEA;AACE;;;;;;;AASI;;;;;;AASA;AACA;AACD;AAIL;;AAmBM;;;;;AAsBK;AASb;;;"}
@@ -1,13 +1,14 @@
1
1
  "use client";
2
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
- import { useRef, useState, useImperativeHandle, useCallback, useMemo, useEffect } from 'react';
2
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
+ import { memo, useRef, useState, useImperativeHandle, useCallback, useMemo, useEffect } from 'react';
4
4
  import innerText from '../../../_virtual/index3.js';
5
5
  import { tv as ce } from './../../../vendor/.pnpm/tailwind-variants@0.3.1_tailwindcss@3.4.19_ts-node@10.9.2_@swc_core@1.15.17_@types_node@20.19.35_typescript@5.9.3__/vendor/tailwind-variants/dist/index.js';
6
6
  import { useClick } from '../../../hooks/useClick.js';
7
+ import { useLatest } from '../../../hooks/useLatest.js';
7
8
  import { useTheme } from '../../../hooks/useTheme.js';
8
9
  import '../../../intl/IntlProvider.js';
9
10
  import { useIntl } from '../../../intl/useIntl.js';
10
- import 'react-intl';
11
+ import '../../../intl/Localizer.js';
11
12
  import '../../../_virtual/dayjs.min.js';
12
13
  import '../../../intl/TimeFormatter.js';
13
14
  import { genericsForwardRef } from '../../../libs/util.js';
@@ -64,6 +65,7 @@ const classNameGenerator = ce({
64
65
  },
65
66
  },
66
67
  });
68
+ const SuffixButtons = memo(({ onClickClear, clearButtonRef, onClickIcon: onDelegateClickIcon, caretIconColor, destroyButtonIconAlt, classNames, }) => (jsxs(Fragment, { children: [jsx(UnstyledButton, { onClick: onClickClear, ref: clearButtonRef, className: classNames.clearButton, children: jsx(FaCircleXmarkIcon, { color: "TEXT_BLACK", alt: destroyButtonIconAlt, className: classNames.clearButtonIcon }) }), jsx("span", { role: "presentation", onClick: onDelegateClickIcon, className: classNames.caretDownLayout, children: jsx(FaCaretDownIcon, { color: caretIconColor, className: classNames.caretDownIcon }) })] })));
67
69
  const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled, readOnly, required, prefix, error, creatable, placeholder, autoComplete, dropdownHelpMessage, isLoading, width, dropdownWidth = 'auto', className, onChange, onChangeInput, onAdd, onSelect, onClear, onClearClick, onChangeSelected, onFocus, onBlur, onKeyPress, noResultText, style, ...rest }, ref) => {
68
70
  const theme = useTheme();
69
71
  const { localize } = useIntl();
@@ -75,6 +77,24 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
75
77
  const [inputValue, setInputValue] = useState('');
76
78
  const [isComposing, setIsComposing] = useState(false);
77
79
  const [isEditing, setIsEditing] = useState(false);
80
+ const latest = useLatest({
81
+ onChange,
82
+ onChangeInput,
83
+ onAdd,
84
+ onSelect,
85
+ onClear,
86
+ onClearClick,
87
+ onChangeSelected,
88
+ onFocus,
89
+ onBlur,
90
+ onKeyPress,
91
+ defaultItem,
92
+ selectedItem,
93
+ isFocused,
94
+ isExpanded,
95
+ isComposing,
96
+ isEditing,
97
+ });
78
98
  useImperativeHandle(ref, () => inputRef.current);
79
99
  const { options } = useSingleOptions({
80
100
  items,
@@ -89,49 +109,58 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
89
109
  dropdownWidth,
90
110
  onAdd,
91
111
  onSelect: useCallback((selected) => {
92
- onSelect?.(selected);
93
- onChangeSelected?.(selected);
94
- // 制御コンポーネントの場合に親側でinputValueを更新できるように、選択時にonChangeInputを空文字で発火する
95
- onChangeInput?.(EMPTY_INPUT_CHANGE_EVENT);
112
+ latest.onSelect?.(selected);
113
+ latest.onChangeSelected?.(selected);
96
114
  // HINT: Dropdown系コンポーネント内でComboboxを使うと、選択肢がportalで表現されている関係上Dropdownが閉じてしまう
97
115
  // requestAnimationFrameを追加、処理を遅延させることで正常に閉じる/閉じないの判定を行えるようにする
98
116
  requestAnimationFrame(() => {
99
117
  setIsExpanded(false);
118
+ // HINT:
119
+ // - 制御コンポーネントの場合に親側でinputValueを更新できるように、選択時にonChangeInputを空文字で発火する
120
+ // - 対応するdropdownを閉じて以降にonChangeInputを発火する必要がある
121
+ // - 先にclearしてしまうと意図せずこの要素のドロップダウンを閉じる前に他要素の再レンダリングを引き起こす可能性がある
122
+ // - 例えばFilterDropdownなどで当comboboxを使っている場合、レイアウト上comboboxのdropdown以下の要素がクリックされた扱いになってしまい
123
+ // FilterDropdownを意図せず閉じてしまうなどの挙動のバグを引き起こす可能性がある
124
+ latest.onChangeInput?.(EMPTY_INPUT_CHANGE_EVENT);
100
125
  });
101
126
  setIsEditing(false);
102
- }, [onChangeSelected, onSelect, onChangeInput]),
127
+ }, [latest]),
103
128
  isExpanded,
104
129
  isLoading,
105
130
  triggerRef: outerRef,
106
131
  noResultText,
107
132
  });
108
- const selectDefaultItem = useMemo(() => (onSelect && defaultItem ? () => onSelect(defaultItem) : NOOP), [onSelect, defaultItem]);
133
+ const selectDefaultItem = useCallback(() => {
134
+ if (latest.onSelect && latest.defaultItem) {
135
+ latest.onSelect(latest.defaultItem);
136
+ }
137
+ }, [latest]);
109
138
  const focus = useCallback(() => {
110
- onFocus?.();
139
+ latest.onFocus?.();
111
140
  inputRef.current?.focus();
112
141
  setIsFocused(true);
113
- if (!isFocused) {
142
+ if (!latest.isFocused) {
114
143
  setIsExpanded(true);
115
144
  }
116
- }, [onFocus, isFocused]);
145
+ }, [latest]);
117
146
  const unfocus = useCallback(() => {
118
- if (!isFocused)
147
+ if (!latest.isFocused)
119
148
  return;
120
- onBlur?.();
149
+ latest.onBlur?.();
121
150
  setIsFocused(false);
122
151
  setIsExpanded(false);
123
152
  setIsEditing(false);
124
- if (selectedItem) {
125
- setInputValue(innerText(selectedItem.label));
153
+ if (latest.selectedItem) {
154
+ setInputValue(innerText(latest.selectedItem.label));
126
155
  }
127
156
  else {
128
157
  selectDefaultItem();
129
158
  }
130
- }, [isFocused, onBlur, selectedItem, selectDefaultItem]);
159
+ }, [selectDefaultItem, latest]);
131
160
  const onClickClear = useCallback((e) => {
132
161
  e.stopPropagation();
133
162
  let isExecutedPreventDefault = false;
134
- onClearClick?.({
163
+ latest.onClearClick?.({
135
164
  ...e,
136
165
  preventDefault: () => {
137
166
  e.preventDefault();
@@ -139,44 +168,43 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
139
168
  },
140
169
  });
141
170
  if (!isExecutedPreventDefault) {
142
- onClear?.();
143
- onChangeSelected?.(null);
171
+ latest.onClear?.();
172
+ latest.onChangeSelected?.(null);
144
173
  inputRef.current?.focus();
145
174
  setIsFocused(true);
146
175
  setIsExpanded(true);
147
176
  }
148
- }, [onClearClick, onClear, onChangeSelected]);
177
+ }, [latest]);
149
178
  const onClickInput = useCallback((e) => {
150
179
  if (disabled || readOnly) {
151
180
  e.stopPropagation();
152
181
  return;
153
182
  }
154
183
  inputRef.current?.focus();
155
- if (!isExpanded) {
184
+ if (!latest.isExpanded) {
156
185
  setIsExpanded(true);
157
186
  }
158
- }, [disabled, readOnly, inputRef, isExpanded]);
159
- const onDelegateClickIcon = onClickInput;
187
+ }, [disabled, readOnly, latest]);
160
188
  const actualOnChangeInput = useCallback((e) => {
161
- onChange?.(e);
162
- onChangeInput?.(e);
163
- if (!isEditing)
189
+ latest.onChange?.(e);
190
+ latest.onChangeInput?.(e);
191
+ if (!latest.isEditing)
164
192
  setIsEditing(true);
165
193
  const { value } = e.currentTarget;
166
194
  setInputValue(value);
167
195
  if (value === '') {
168
- onClear?.();
169
- onChangeSelected?.(null);
196
+ latest.onClear?.();
197
+ latest.onChangeSelected?.(null);
170
198
  }
171
- }, [isEditing, onChange, onChangeInput, onClear, onChangeSelected]);
199
+ }, [latest]);
172
200
  const onCompositionStart = useCallback(() => setIsComposing(true), []);
173
201
  const onCompositionEnd = useCallback(() => setIsComposing(false), []);
174
202
  const onKeyDownInput = useCallback((e) => {
175
- if (isComposing) {
203
+ if (latest.isComposing) {
176
204
  return;
177
205
  }
178
206
  if (ESCAPE_KEY_REGEX.test(e.key)) {
179
- if (isExpanded) {
207
+ if (latest.isExpanded) {
180
208
  e.stopPropagation();
181
209
  setIsExpanded(false);
182
210
  }
@@ -189,28 +217,26 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
189
217
  e.preventDefault();
190
218
  }
191
219
  inputRef.current?.focus();
192
- if (!isExpanded) {
220
+ if (!latest.isExpanded) {
193
221
  setIsExpanded(true);
194
222
  }
195
223
  }
196
224
  onKeyDownListBox(e);
197
- }, [isComposing, isExpanded, unfocus, onKeyDownListBox]);
225
+ }, [unfocus, onKeyDownListBox, latest]);
198
226
  // HINT: form内にcomboboxを設置 & 検索inputにfocusした状態で
199
227
  // アイテムをキーボードで選択し、Enterを押すとinput上でEnterを押したことになるため、
200
228
  // submitイベントが発生し、formが送信される場合がある
201
229
  const handleKeyPress = useCallback((e) => {
202
230
  if (e.key === 'Enter')
203
231
  e.preventDefault();
204
- onKeyPress?.(e);
205
- }, [onKeyPress]);
206
- const caretIconColor = useMemo(() => {
207
- if (isFocused)
208
- return theme.textColor.black;
209
- if (disabled || readOnly)
210
- return theme.textColor.disabled;
211
- return theme.textColor.grey;
212
- }, [disabled, readOnly, isFocused, theme.textColor]);
213
- useClick(useMemo(() => [outerRef, listBoxRef, clearButtonRef], [outerRef, listBoxRef, clearButtonRef]), isFocused || selectedItem ? NOOP : selectDefaultItem, unfocus);
232
+ latest.onKeyPress?.(e);
233
+ }, [latest]);
234
+ const caretIconColor = isFocused
235
+ ? theme.textColor.black
236
+ : disabled || readOnly
237
+ ? theme.textColor.disabled
238
+ : theme.textColor.grey;
239
+ useClick(useMemo(() => [outerRef, listBoxRef, clearButtonRef], [listBoxRef]), isFocused || selectedItem ? NOOP : selectDefaultItem, unfocus);
214
240
  // selectedItem.label はプリミティブ値でないデータ型の可能性があり、そのまま useEffect の依存配列に入れると意図せぬエフェクトの実行を引き起こしてしまう可能性があるので、プリミティブ値である string 型に変換したものを依存配列に入れています。
215
241
  const selectedItemLabelText = innerText(selectedItem?.label);
216
242
  useEffect(() => {
@@ -220,7 +246,7 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
220
246
  ...style,
221
247
  width: typeof width === 'number' ? `${width}px` : width,
222
248
  }), [style, width]);
223
- const notSelected = selectedItem === null;
249
+ const hasSelectedItem = selectedItem !== null;
224
250
  const classNames = useMemo(() => {
225
251
  const { wrapper, input, caretDownLayout, caretDownIcon, clearButton, clearButtonIcon } = classNameGenerator();
226
252
  return {
@@ -228,17 +254,24 @@ const ActualSingleCombobox = ({ items, selectedItem, defaultItem, name, disabled
228
254
  input: input(),
229
255
  caretDownLayout: caretDownLayout(),
230
256
  caretDownIcon: caretDownIcon(),
231
- clearButton: clearButton({ hidden: notSelected || disabled || readOnly }),
257
+ clearButton: clearButton({
258
+ hidden: !hasSelectedItem || disabled || readOnly,
259
+ }),
232
260
  clearButtonIcon: clearButtonIcon(),
233
261
  };
234
- }, [notSelected, disabled, readOnly, className]);
262
+ }, [hasSelectedItem, disabled, readOnly, className]);
235
263
  const destroyButtonIconAlt = useMemo(() => localize({
236
264
  id: 'smarthr-ui/SingleCombobox/destroyButtonIconAlt',
237
265
  defaultText: 'クリア',
238
266
  }), [localize]);
239
267
  return (jsxs("div", { role: "group", className: classNames.wrapper, style: wrapperStyle, ref: outerRef, children: [jsx(Input, { ...rest, ref: inputRef, type: "text", role: "combobox", name: name, value: inputValue, disabled: disabled, readOnly: readOnly, required: required, autoComplete: autoComplete ?? 'off', "aria-haspopup": "listbox", "aria-controls": listBoxId, "aria-expanded": isFocused, "aria-activedescendant": activeOption?.id, "aria-autocomplete": "list",
240
268
  /* eslint-disable-next-line smarthr/a11y-prohibit-input-placeholder */
241
- placeholder: placeholder, onClick: onClickInput, onChange: actualOnChangeInput, onFocus: isFocused ? undefined : focus, onCompositionStart: onCompositionStart, onCompositionEnd: onCompositionEnd, onKeyDown: onKeyDownInput, onKeyPress: handleKeyPress, error: error, prefix: prefix, suffix: jsxs(Fragment, { children: [jsx(UnstyledButton, { onClick: onClickClear, ref: clearButtonRef, className: classNames.clearButton, children: jsx(FaCircleXmarkIcon, { color: "TEXT_BLACK", alt: destroyButtonIconAlt, className: classNames.clearButtonIcon }) }), jsx("span", { role: "presentation", onClick: onDelegateClickIcon, className: classNames.caretDownLayout, children: jsx(FaCaretDownIcon, { color: caretIconColor, className: classNames.caretDownIcon }) })] }), className: classNames.input, "data-smarthr-ui-input": "true" }), !readOnly && renderListBox()] }));
269
+ placeholder: placeholder, onClick: onClickInput, onChange: actualOnChangeInput, onFocus: isFocused ? undefined : focus, onCompositionStart: onCompositionStart, onCompositionEnd: onCompositionEnd, onKeyDown: onKeyDownInput, onKeyPress: handleKeyPress, error: error, prefix: prefix, suffix: jsx(SuffixButtons, { onClickClear: onClickClear, clearButtonRef: clearButtonRef, onClickIcon: onClickInput, caretIconColor: caretIconColor, destroyButtonIconAlt: destroyButtonIconAlt, classNames: {
270
+ clearButton: classNames.clearButton,
271
+ clearButtonIcon: classNames.clearButtonIcon,
272
+ caretDownLayout: classNames.caretDownLayout,
273
+ caretDownIcon: classNames.caretDownIcon,
274
+ } }), className: classNames.input, "data-smarthr-ui-input": "true" }), !readOnly && renderListBox()] }));
242
275
  };
243
276
  const SingleCombobox = genericsForwardRef(ActualSingleCombobox);
244
277