smarthr-ui 99.3.1 → 99.3.2

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 (189) hide show
  1. package/lib/_virtual/index.cjs +2 -2
  2. package/lib/_virtual/index.js +2 -2
  3. package/lib/_virtual/index2.cjs +2 -2
  4. package/lib/_virtual/index2.js +2 -2
  5. package/lib/components/Combobox/ItemButton.cjs +11 -2
  6. package/lib/components/Combobox/ItemButton.cjs.map +1 -1
  7. package/lib/components/Combobox/ItemButton.js +11 -2
  8. package/lib/components/Combobox/ItemButton.js.map +1 -1
  9. package/lib/components/Combobox/MultiCombobox/MultiCombobox.cjs +1 -1
  10. package/lib/components/Combobox/MultiCombobox/MultiCombobox.cjs.map +1 -1
  11. package/lib/components/Combobox/MultiCombobox/MultiCombobox.js +1 -1
  12. package/lib/components/Combobox/MultiCombobox/MultiCombobox.js.map +1 -1
  13. package/lib/components/Combobox/SingleCombobox/SingleCombobox.cjs +1 -1
  14. package/lib/components/Combobox/SingleCombobox/SingleCombobox.cjs.map +1 -1
  15. package/lib/components/Combobox/SingleCombobox/SingleCombobox.js +1 -1
  16. package/lib/components/Combobox/SingleCombobox/SingleCombobox.js.map +1 -1
  17. package/lib/components/DatePicker/DatePicker.cjs +1 -1
  18. package/lib/components/DatePicker/DatePicker.cjs.map +1 -1
  19. package/lib/components/DatePicker/DatePicker.js +1 -1
  20. package/lib/components/DatePicker/DatePicker.js.map +1 -1
  21. package/lib/components/Dialog/FocusTrap.cjs +8 -8
  22. package/lib/components/Dialog/FocusTrap.cjs.map +1 -1
  23. package/lib/components/Dialog/FocusTrap.js +9 -9
  24. package/lib/components/Dialog/FocusTrap.js.map +1 -1
  25. package/lib/components/Dialog/ModelessDialog/ModelessDialog.cjs +2 -1
  26. package/lib/components/Dialog/ModelessDialog/ModelessDialog.cjs.map +1 -1
  27. package/lib/components/Dialog/ModelessDialog/ModelessDialog.js +2 -1
  28. package/lib/components/Dialog/ModelessDialog/ModelessDialog.js.map +1 -1
  29. package/lib/components/Input/CurrencyInput/CurrencyInput.cjs +2 -2
  30. package/lib/components/Input/CurrencyInput/CurrencyInput.cjs.map +1 -1
  31. package/lib/components/Input/CurrencyInput/CurrencyInput.js +2 -2
  32. package/lib/components/Input/CurrencyInput/CurrencyInput.js.map +1 -1
  33. package/lib/components/Input/Input.cjs +14 -16
  34. package/lib/components/Input/Input.cjs.map +1 -1
  35. package/lib/components/Input/Input.js +14 -16
  36. package/lib/components/Input/Input.js.map +1 -1
  37. package/lib/components/InputFile/InputFileMultiplyAppendable.cjs +8 -7
  38. package/lib/components/InputFile/InputFileMultiplyAppendable.cjs.map +1 -1
  39. package/lib/components/InputFile/InputFileMultiplyAppendable.js +8 -7
  40. package/lib/components/InputFile/InputFileMultiplyAppendable.js.map +1 -1
  41. package/lib/components/InputFile/InputFileNative.cjs +6 -5
  42. package/lib/components/InputFile/InputFileNative.cjs.map +1 -1
  43. package/lib/components/InputFile/InputFileNative.js +6 -5
  44. package/lib/components/InputFile/InputFileNative.js.map +1 -1
  45. package/lib/components/Layout/Container/Container.cjs.map +1 -1
  46. package/lib/components/Layout/Container/Container.js.map +1 -1
  47. package/lib/components/Pagination/Pagination.cjs +3 -2
  48. package/lib/components/Pagination/Pagination.cjs.map +1 -1
  49. package/lib/components/Pagination/Pagination.js +2 -1
  50. package/lib/components/Pagination/Pagination.js.map +1 -1
  51. package/lib/components/Panel/Groupbox/Groupbox.cjs +1 -0
  52. package/lib/components/Panel/Groupbox/Groupbox.cjs.map +1 -1
  53. package/lib/components/Panel/Groupbox/Groupbox.js +1 -0
  54. package/lib/components/Panel/Groupbox/Groupbox.js.map +1 -1
  55. package/lib/components/Select/Select.cjs +12 -14
  56. package/lib/components/Select/Select.cjs.map +1 -1
  57. package/lib/components/Select/Select.js +12 -14
  58. package/lib/components/Select/Select.js.map +1 -1
  59. package/lib/components/Table/TableScroller.cjs +13 -15
  60. package/lib/components/Table/TableScroller.cjs.map +1 -1
  61. package/lib/components/Table/TableScroller.js +14 -16
  62. package/lib/components/Table/TableScroller.js.map +1 -1
  63. package/lib/components/Textarea/Textarea.cjs +18 -12
  64. package/lib/components/Textarea/Textarea.cjs.map +1 -1
  65. package/lib/components/Textarea/Textarea.js +19 -13
  66. package/lib/components/Textarea/Textarea.js.map +1 -1
  67. package/lib/components/Tooltip/TooltipPortal.cjs +1 -0
  68. package/lib/components/Tooltip/TooltipPortal.cjs.map +1 -1
  69. package/lib/components/Tooltip/TooltipPortal.js +1 -0
  70. package/lib/components/Tooltip/TooltipPortal.js.map +1 -1
  71. package/lib/hooks/useClick.cjs +7 -4
  72. package/lib/hooks/useClick.cjs.map +1 -1
  73. package/lib/hooks/useClick.js +7 -4
  74. package/lib/hooks/useClick.js.map +1 -1
  75. package/lib/hooks/useOuterClick.cjs +5 -6
  76. package/lib/hooks/useOuterClick.cjs.map +1 -1
  77. package/lib/hooks/useOuterClick.js +6 -7
  78. package/lib/hooks/useOuterClick.js.map +1 -1
  79. package/lib/hooks/usePortal.cjs +24 -17
  80. package/lib/hooks/usePortal.cjs.map +1 -1
  81. package/lib/hooks/usePortal.d.ts +1 -1
  82. package/lib/hooks/usePortal.js +25 -18
  83. package/lib/hooks/usePortal.js.map +1 -1
  84. package/lib/hooks/useResponseStatus.cjs +20 -23
  85. package/lib/hooks/useResponseStatus.cjs.map +1 -1
  86. package/lib/hooks/useResponseStatus.js +20 -23
  87. package/lib/hooks/useResponseStatus.js.map +1 -1
  88. package/lib/intl/locales/en_us.json.cjs +1 -0
  89. package/lib/intl/locales/en_us.json.cjs.map +1 -1
  90. package/lib/intl/locales/en_us.json.js +1 -0
  91. package/lib/intl/locales/en_us.json.js.map +1 -1
  92. package/lib/intl/locales/id_id.json.cjs +0 -8
  93. package/lib/intl/locales/id_id.json.cjs.map +1 -1
  94. package/lib/intl/locales/id_id.json.js +0 -8
  95. package/lib/intl/locales/id_id.json.js.map +1 -1
  96. package/lib/intl/locales/index.d.ts +6 -16
  97. package/lib/intl/locales/ja_easy.json.cjs +1 -0
  98. package/lib/intl/locales/ja_easy.json.cjs.map +1 -1
  99. package/lib/intl/locales/ja_easy.json.js +1 -0
  100. package/lib/intl/locales/ja_easy.json.js.map +1 -1
  101. package/lib/intl/locales/ko_kr.json.cjs +1 -0
  102. package/lib/intl/locales/ko_kr.json.cjs.map +1 -1
  103. package/lib/intl/locales/ko_kr.json.js +1 -0
  104. package/lib/intl/locales/ko_kr.json.js.map +1 -1
  105. package/lib/intl/locales/pt_br.json.cjs +0 -8
  106. package/lib/intl/locales/pt_br.json.cjs.map +1 -1
  107. package/lib/intl/locales/pt_br.json.js +0 -8
  108. package/lib/intl/locales/pt_br.json.js.map +1 -1
  109. package/lib/intl/locales/vi_vn.json.cjs +1 -0
  110. package/lib/intl/locales/vi_vn.json.cjs.map +1 -1
  111. package/lib/intl/locales/vi_vn.json.js +1 -0
  112. package/lib/intl/locales/vi_vn.json.js.map +1 -1
  113. package/lib/intl/locales/zh_hans_cn.json.cjs +1 -0
  114. package/lib/intl/locales/zh_hans_cn.json.cjs.map +1 -1
  115. package/lib/intl/locales/zh_hans_cn.json.js +1 -0
  116. package/lib/intl/locales/zh_hans_cn.json.js.map +1 -1
  117. package/lib/intl/locales/zh_hant_tw.json.cjs +1 -0
  118. package/lib/intl/locales/zh_hant_tw.json.cjs.map +1 -1
  119. package/lib/intl/locales/zh_hant_tw.json.js +1 -0
  120. package/lib/intl/locales/zh_hant_tw.json.js.map +1 -1
  121. package/lib/intl/useDateFormat.cjs +1 -2
  122. package/lib/intl/useDateFormat.cjs.map +1 -1
  123. package/lib/intl/useDateFormat.js +1 -2
  124. package/lib/intl/useDateFormat.js.map +1 -1
  125. package/lib/intl/useIntl.cjs +2 -4
  126. package/lib/intl/useIntl.cjs.map +1 -1
  127. package/lib/intl/useIntl.js +2 -4
  128. package/lib/intl/useIntl.js.map +1 -1
  129. package/lib/libs/debounce.cjs +10 -2
  130. package/lib/libs/debounce.cjs.map +1 -1
  131. package/lib/libs/debounce.d.ts +4 -2
  132. package/lib/libs/debounce.js +10 -2
  133. package/lib/libs/debounce.js.map +1 -1
  134. package/lib/libs/lodash.cjs +3 -4
  135. package/lib/libs/lodash.cjs.map +1 -1
  136. package/lib/libs/lodash.d.ts +2 -11
  137. package/lib/libs/lodash.js +2 -7
  138. package/lib/libs/lodash.js.map +1 -1
  139. package/lib/libs/map.cjs +1 -5
  140. package/lib/libs/map.cjs.map +1 -1
  141. package/lib/libs/map.js +1 -5
  142. package/lib/libs/map.js.map +1 -1
  143. package/lib/themes/createBackgroundColor.cjs +3 -2
  144. package/lib/themes/createBackgroundColor.cjs.map +1 -1
  145. package/lib/themes/createBackgroundColor.js +2 -1
  146. package/lib/themes/createBackgroundColor.js.map +1 -1
  147. package/lib/themes/createBorder.cjs +3 -2
  148. package/lib/themes/createBorder.cjs.map +1 -1
  149. package/lib/themes/createBorder.js +2 -1
  150. package/lib/themes/createBorder.js.map +1 -1
  151. package/lib/themes/createBreakpoint.cjs +3 -2
  152. package/lib/themes/createBreakpoint.cjs.map +1 -1
  153. package/lib/themes/createBreakpoint.js +2 -1
  154. package/lib/themes/createBreakpoint.js.map +1 -1
  155. package/lib/themes/createColor.cjs +3 -2
  156. package/lib/themes/createColor.cjs.map +1 -1
  157. package/lib/themes/createColor.js +2 -1
  158. package/lib/themes/createColor.js.map +1 -1
  159. package/lib/themes/createFontSize.cjs +3 -2
  160. package/lib/themes/createFontSize.cjs.map +1 -1
  161. package/lib/themes/createFontSize.js +2 -1
  162. package/lib/themes/createFontSize.js.map +1 -1
  163. package/lib/themes/createInteraction.cjs +3 -2
  164. package/lib/themes/createInteraction.cjs.map +1 -1
  165. package/lib/themes/createInteraction.js +2 -1
  166. package/lib/themes/createInteraction.js.map +1 -1
  167. package/lib/themes/createLeading.cjs +3 -2
  168. package/lib/themes/createLeading.cjs.map +1 -1
  169. package/lib/themes/createLeading.js +2 -1
  170. package/lib/themes/createLeading.js.map +1 -1
  171. package/lib/themes/createRadius.cjs +3 -2
  172. package/lib/themes/createRadius.cjs.map +1 -1
  173. package/lib/themes/createRadius.js +2 -1
  174. package/lib/themes/createRadius.js.map +1 -1
  175. package/lib/themes/createShadow/createShadow.cjs +3 -2
  176. package/lib/themes/createShadow/createShadow.cjs.map +1 -1
  177. package/lib/themes/createShadow/createShadow.js +2 -1
  178. package/lib/themes/createShadow/createShadow.js.map +1 -1
  179. package/lib/themes/createTextColor.cjs +3 -2
  180. package/lib/themes/createTextColor.cjs.map +1 -1
  181. package/lib/themes/createTextColor.js +2 -1
  182. package/lib/themes/createTextColor.js.map +1 -1
  183. package/lib/themes/createZIndex.cjs +3 -2
  184. package/lib/themes/createZIndex.cjs.map +1 -1
  185. package/lib/themes/createZIndex.js +2 -1
  186. package/lib/themes/createZIndex.js.map +1 -1
  187. package/metadata.json +1 -1
  188. package/package.json +1 -1
  189. package/smarthr-ui.css +27 -7
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.cjs","sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ElementType,\n type FC,\n type HTMLAttributes,\n type MouseEvent,\n memo,\n useMemo,\n} from 'react'\nimport { tv } from 'tailwind-variants'\n\nimport { useLatest } from '../../hooks/useLatest'\nimport { useLocalize } from '../../intl'\nimport { range } from '../../libs/lodash'\nimport { Cluster, Reel } from '../Layout'\nimport { Nav } from '../SectioningContent'\n\nimport { PaginationControllerItemButton } from './PaginationControllerItemButton'\nimport { PaginationItemButton } from './PaginationItemButton'\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-Pagination shr-inline-block shr-max-w-full',\n list: 'shr-m-0.25 shr-list-none shr-ps-[unset]',\n firstListItem: 'smarthr-ui-Pagination-first',\n prevListItem: 'smarthr-ui-Pagination-prev',\n nextListItem: 'smarthr-ui-Pagination-next',\n lastListItem: 'smarthr-ui-Pagination-last',\n },\n variants: {\n withoutNumbers: {\n true: {\n firstListItem: 'shr-mr-0.5',\n prevListItem: 'shr-mr-0',\n nextListItem: 'shr-ml-0',\n lastListItem: 'shr-ml-0.5',\n },\n false: {\n prevListItem: 'shr-mr-0.5',\n nextListItem: 'shr-ml-0.5',\n },\n },\n },\n})\n\ntype CommonProps = {\n /** 全ページ数 */\n total: number\n /** 現在のページ */\n current: number\n /** 現在のページの前後に表示するページ番号のボタンの数 */\n padding?: number\n /** `true` のとき、ページ番号のボタンを表示しない */\n withoutNumbers?: boolean\n}\n\ntype ButtonProps = CommonProps & {\n /** ボタンを押下したときに発火するコールバック関数 */\n onClick: (pageNumber: number, e: MouseEvent<HTMLElement>) => void\n /** href属性生成用関数。設定した場合、番号やarrowがbuttonからa要素に置き換わります */\n hrefTemplate?: undefined\n /** next/linkなどのカスタムコンポーネントを指定します。指定がない場合はデフォルトで `a` タグが使用されます。 */\n linkAs?: undefined\n}\ntype AnchorProps = CommonProps & {\n /** リンクを押下したときに発火するコールバック関数 */\n onClick?: (href: string, e: MouseEvent<HTMLElement>) => void\n /** href属性生成用関数。設定した場合、番号やarrowがbuttonからa要素に置き換わります */\n hrefTemplate: (pageNumber: number) => string\n /** next/linkなどのカスタムコンポーネントを指定します。指定がない場合はデフォルトで `a` タグが使用されます。 */\n linkAs?: ElementType\n}\n\ntype BaseProps = ButtonProps | AnchorProps\ntype Props = BaseProps & Omit<HTMLAttributes<HTMLElement>, keyof BaseProps>\n\nconst BUTTON_REGEX = /^button$/i\nconst ANCHOR_REGEX = /^a/i\n\nconst getTargetDelegateElement = (e: MouseEvent<HTMLElement>, regex: RegExp) =>\n (e.nativeEvent.composedPath() as HTMLElement[]).find((elm) => regex.test(elm.tagName))\n\nexport const Pagination: FC<Props> = (props) =>\n props.total > 1 ? <ActualPagination {...props} /> : null\n\nconst ActualPagination: FC<Props> = ({\n total,\n current,\n onClick,\n padding,\n className,\n withoutNumbers,\n hrefTemplate,\n linkAs,\n ...rest\n}) => {\n const classNames = useMemo(() => {\n const { wrapper, list, firstListItem, prevListItem, nextListItem, lastListItem } =\n classNameGenerator()\n const itemArg = { withoutNumbers: withoutNumbers || false }\n\n return {\n wrapper: wrapper({ className }),\n list: list(),\n firstListItem: firstListItem(itemArg),\n prevListItem: prevListItem(itemArg),\n nextListItem: nextListItem(itemArg),\n lastListItem: lastListItem(itemArg),\n }\n }, [className, withoutNumbers])\n\n const latest = useLatest({ onClick, hrefTemplate })\n const hasHrefTemplate = !!hrefTemplate\n\n const functions = useMemo(\n () => ({\n actualHrefTemplate: hasHrefTemplate\n ? (pageNumber: number) => latest.hrefTemplate!(pageNumber)\n : undefined,\n handleDelegateClick: (e: MouseEvent<HTMLElement>) => {\n if (!latest.onClick) {\n return\n }\n\n if (latest.hrefTemplate) {\n const anchor = getTargetDelegateElement(e, ANCHOR_REGEX)\n\n if (!anchor) {\n return\n }\n\n const href = (anchor as HTMLAnchorElement).href\n\n if (href) {\n ;(latest.onClick as (href: string, e: MouseEvent<HTMLElement>) => void)(href, e)\n }\n } else {\n const button = getTargetDelegateElement(e, BUTTON_REGEX)\n\n if (button) {\n ;(latest.onClick as (pageNumber: number, e: MouseEvent<HTMLElement>) => void)(\n parseInt((button as HTMLButtonElement).value, 10),\n e,\n )\n }\n }\n },\n }),\n [hasHrefTemplate, latest],\n )\n\n const { navigationLabel } = useLocalize({\n navigationLabel: {\n id: 'smarthr-ui/Pagination/navigationLabel',\n defaultText: 'ページネーション',\n },\n })\n\n return (\n <Nav {...rest} className={classNames.wrapper} aria-label={navigationLabel}>\n <Reel onClick={functions.handleDelegateClick}>\n <ItemButtons\n total={total}\n current={current}\n padding={padding}\n withoutNumbers={withoutNumbers}\n hrefTemplate={functions.actualHrefTemplate}\n classNames={classNames}\n linkAs={linkAs}\n />\n </Reel>\n </Nav>\n )\n}\n\nconst ItemButtons = memo<\n Pick<Props, 'total' | 'current' | 'padding' | 'withoutNumbers' | 'hrefTemplate' | 'linkAs'> & {\n classNames: {\n list: string\n firstListItem: string\n prevListItem: string\n nextListItem: string\n lastListItem: string\n }\n }\n>(({ total, current, padding, withoutNumbers, hrefTemplate, classNames, linkAs }) => {\n const pageNumbers = useMemo(() => {\n if (withoutNumbers) {\n return []\n }\n\n const actualPadding = padding ?? 4\n\n return range(Math.max(current - actualPadding, 1), Math.min(current + actualPadding, total) + 1)\n }, [current, total, padding, withoutNumbers])\n\n const prevAttrs = {\n disabled: current === 1,\n direction: 'prev' as const,\n hrefTemplate,\n linkAs,\n }\n const nextAttrs = {\n disabled: current === total,\n direction: 'next' as const,\n hrefTemplate,\n linkAs,\n }\n\n return (\n <Cluster as=\"ul\" className={classNames.list}>\n <DoubleIconItemButton {...prevAttrs} targetPage={1} className={classNames.firstListItem} />\n <li className={classNames.prevListItem}>\n <PaginationControllerItemButton {...prevAttrs} targetPage={current - 1} />\n </li>\n {pageNumbers.map((page) => (\n <NumberItemButton\n key={page}\n page={page}\n disabled={page === current}\n hrefTemplate={hrefTemplate}\n linkAs={linkAs}\n />\n ))}\n <li className={classNames.nextListItem}>\n <PaginationControllerItemButton {...nextAttrs} targetPage={current + 1} />\n </li>\n <DoubleIconItemButton {...nextAttrs} targetPage={total} className={classNames.lastListItem} />\n </Cluster>\n )\n})\n\nconst NumberItemButton = memo<\n Pick<Props, 'hrefTemplate' | 'linkAs'> & { page: number; disabled: boolean }\n>(({ disabled, ...rest }) => (\n <li className={`smarthr-ui-Pagination-${disabled ? 'current' : 'page'}`}>\n <PaginationItemButton {...rest} disabled={disabled} />\n </li>\n))\n\nconst DoubleIconItemButton = memo<\n Pick<Props, 'hrefTemplate' | 'linkAs'> & {\n disabled: boolean\n direction: 'prev' | 'next'\n targetPage: number\n className: string\n }\n>(({ className, ...rest }) => (\n <li className={className}>\n <PaginationControllerItemButton {...rest} double />\n </li>\n))\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA;AACE;AACE;AACA;AACA;AACA;AACA;AACA;AACD;AACD;AACE;AACE;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACD;AACF;AACF;AACF;AAiCD;AACA;AAEA;AAGO;AAGP;AAWE;AACE;;;AAKE;;AAEA;AACA;AACA;AACA;;AAEJ;;AAGA;AAEA;AAEI;;AAEE;AACF;AACE;;;AAIA;;;;;AAOE;;AAGI;;;;;;AAMA;;;;AAOT;AAIH;AACE;AACE;AACA;AACD;AACF;;AAiBH;AAEA;AAWE;;AAEI;;AAGF;;;AAKF;;AAEE;;;;AAIF;;AAEE;;;;;AA0BJ;AAEA;AAQA;;"}
1
+ {"version":3,"file":"Pagination.cjs","sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ElementType,\n type FC,\n type HTMLAttributes,\n type MouseEvent,\n memo,\n useMemo,\n} from 'react'\nimport { tv } from 'tailwind-variants'\n\nimport { useLatest } from '../../hooks/useLatest'\nimport { useLocalize } from '../../intl'\nimport { range } from '../../libs/lodash'\nimport { Cluster, Reel } from '../Layout'\nimport { Nav } from '../SectioningContent'\n\nimport { PaginationControllerItemButton } from './PaginationControllerItemButton'\nimport { PaginationItemButton } from './PaginationItemButton'\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-Pagination shr-inline-block shr-max-w-full',\n list: 'shr-m-0.25 shr-list-none shr-ps-[unset]',\n firstListItem: 'smarthr-ui-Pagination-first',\n prevListItem: 'smarthr-ui-Pagination-prev',\n nextListItem: 'smarthr-ui-Pagination-next',\n lastListItem: 'smarthr-ui-Pagination-last',\n },\n variants: {\n withoutNumbers: {\n true: {\n firstListItem: 'shr-mr-0.5',\n prevListItem: 'shr-mr-0',\n nextListItem: 'shr-ml-0',\n lastListItem: 'shr-ml-0.5',\n },\n false: {\n prevListItem: 'shr-mr-0.5',\n nextListItem: 'shr-ml-0.5',\n },\n },\n },\n})\n\ntype CommonProps = {\n /** 全ページ数 */\n total: number\n /** 現在のページ */\n current: number\n /** 現在のページの前後に表示するページ番号のボタンの数 */\n padding?: number\n /** `true` のとき、ページ番号のボタンを表示しない */\n withoutNumbers?: boolean\n}\n\ntype ButtonProps = CommonProps & {\n /** ボタンを押下したときに発火するコールバック関数 */\n onClick: (pageNumber: number, e: MouseEvent<HTMLElement>) => void\n /** href属性生成用関数。設定した場合、番号やarrowがbuttonからa要素に置き換わります */\n hrefTemplate?: undefined\n /** next/linkなどのカスタムコンポーネントを指定します。指定がない場合はデフォルトで `a` タグが使用されます。 */\n linkAs?: undefined\n}\ntype AnchorProps = CommonProps & {\n /** リンクを押下したときに発火するコールバック関数 */\n onClick?: (href: string, e: MouseEvent<HTMLElement>) => void\n /** href属性生成用関数。設定した場合、番号やarrowがbuttonからa要素に置き換わります */\n hrefTemplate: (pageNumber: number) => string\n /** next/linkなどのカスタムコンポーネントを指定します。指定がない場合はデフォルトで `a` タグが使用されます。 */\n linkAs?: ElementType\n}\n\ntype BaseProps = ButtonProps | AnchorProps\ntype Props = BaseProps & Omit<HTMLAttributes<HTMLElement>, keyof BaseProps>\n\nconst BUTTON_REGEX = /^button$/i\nconst ANCHOR_REGEX = /^a/i\n\nconst getTargetDelegateElement = (e: MouseEvent<HTMLElement>, regex: RegExp) =>\n (e.nativeEvent.composedPath() as HTMLElement[]).find((elm) => regex.test(elm.tagName))\n\nexport const Pagination: FC<Props> = (props) =>\n props.total > 1 ? <ActualPagination {...props} /> : null\n\nconst ActualPagination: FC<Props> = ({\n total,\n current,\n onClick,\n padding,\n className,\n withoutNumbers,\n hrefTemplate,\n linkAs,\n ...rest\n}) => {\n const classNames = useMemo(() => {\n const { wrapper, list, firstListItem, prevListItem, nextListItem, lastListItem } =\n classNameGenerator()\n const itemArg = { withoutNumbers: withoutNumbers || false }\n\n return {\n wrapper: wrapper({ className }),\n list: list(),\n firstListItem: firstListItem(itemArg),\n prevListItem: prevListItem(itemArg),\n nextListItem: nextListItem(itemArg),\n lastListItem: lastListItem(itemArg),\n }\n }, [className, withoutNumbers])\n\n const latest = useLatest({ onClick, hrefTemplate })\n const hasHrefTemplate = !!hrefTemplate\n\n const functions = useMemo(\n () => ({\n actualHrefTemplate: hasHrefTemplate\n ? (pageNumber: number) => latest.hrefTemplate!(pageNumber)\n : undefined,\n handleDelegateClick: (e: MouseEvent<HTMLElement>) => {\n if (!latest.onClick) {\n return\n }\n\n if (latest.hrefTemplate) {\n const anchor = getTargetDelegateElement(e, ANCHOR_REGEX)\n\n if (!anchor) {\n return\n }\n\n const href = (anchor as HTMLAnchorElement).href\n\n if (href) {\n ;(latest.onClick as (href: string, e: MouseEvent<HTMLElement>) => void)(href, e)\n }\n } else {\n const button = getTargetDelegateElement(e, BUTTON_REGEX)\n\n if (button) {\n ;(latest.onClick as (pageNumber: number, e: MouseEvent<HTMLElement>) => void)(\n parseInt((button as HTMLButtonElement).value, 10),\n e,\n )\n }\n }\n },\n }),\n [hasHrefTemplate, latest],\n )\n\n const { navigationLabel } = useLocalize({\n navigationLabel: {\n id: 'smarthr-ui/Pagination/navigationLabel',\n defaultText: 'ページネーション',\n },\n })\n\n return (\n <Nav {...rest} className={classNames.wrapper} aria-label={navigationLabel}>\n <Reel onClick={functions.handleDelegateClick}>\n <ItemButtons\n total={total}\n current={current}\n padding={padding}\n withoutNumbers={withoutNumbers}\n hrefTemplate={functions.actualHrefTemplate}\n classNames={classNames}\n linkAs={linkAs}\n />\n </Reel>\n </Nav>\n )\n}\n\nconst ItemButtons = memo<\n Pick<Props, 'total' | 'current' | 'padding' | 'withoutNumbers' | 'hrefTemplate' | 'linkAs'> & {\n classNames: {\n list: string\n firstListItem: string\n prevListItem: string\n nextListItem: string\n lastListItem: string\n }\n }\n>(({ total, current, padding, withoutNumbers, hrefTemplate, classNames, linkAs }) => {\n const pageNumbers = useMemo(() => {\n if (withoutNumbers) {\n return []\n }\n\n const actualPadding = padding ?? 4\n\n return range(Math.max(current - actualPadding, 1), Math.min(current + actualPadding, total) + 1)\n }, [current, total, padding, withoutNumbers])\n\n const prevAttrs = {\n disabled: current === 1,\n direction: 'prev' as const,\n hrefTemplate,\n linkAs,\n }\n const nextAttrs = {\n disabled: current === total,\n direction: 'next' as const,\n hrefTemplate,\n linkAs,\n }\n\n return (\n <Cluster as=\"ul\" className={classNames.list}>\n <DoubleIconItemButton {...prevAttrs} targetPage={1} className={classNames.firstListItem} />\n <li className={classNames.prevListItem}>\n <PaginationControllerItemButton {...prevAttrs} targetPage={current - 1} />\n </li>\n {pageNumbers.map((page) => (\n <NumberItemButton\n key={page}\n page={page}\n disabled={page === current}\n hrefTemplate={hrefTemplate}\n linkAs={linkAs}\n />\n ))}\n <li className={classNames.nextListItem}>\n <PaginationControllerItemButton {...nextAttrs} targetPage={current + 1} />\n </li>\n <DoubleIconItemButton {...nextAttrs} targetPage={total} className={classNames.lastListItem} />\n </Cluster>\n )\n})\n\nconst NumberItemButton = memo<\n Pick<Props, 'hrefTemplate' | 'linkAs'> & { page: number; disabled: boolean }\n>(({ disabled, ...rest }) => (\n <li className={`smarthr-ui-Pagination-${disabled ? 'current' : 'page'}`}>\n <PaginationItemButton {...rest} disabled={disabled} />\n </li>\n))\n\nconst DoubleIconItemButton = memo<\n Pick<Props, 'hrefTemplate' | 'linkAs'> & {\n disabled: boolean\n direction: 'prev' | 'next'\n targetPage: number\n className: string\n }\n>(({ className, ...rest }) => (\n <li className={className}>\n <PaginationControllerItemButton {...rest} double />\n </li>\n))\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA;AACE;AACE;AACA;AACA;AACA;AACA;AACA;AACD;AACD;AACE;AACE;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACD;AACF;AACF;AACF;AAiCD;AACA;AAEA;AAGO;AAGP;AAWE;AACE;;;AAKE;;AAEA;AACA;AACA;AACA;;AAEJ;;AAGA;AAEA;AAEI;;AAEE;AACF;AACE;;;AAIA;;;;;AAOE;;AAGI;;;;;;AAMA;;;;AAOT;AAIH;AACE;AACE;AACA;AACD;AACF;;AAiBH;AAEA;AAWE;;AAEI;;AAGF;;;AAKF;;AAEE;;;;AAIF;;AAEE;;;;;AA0BJ;AAEA;AAQA;;"}
@@ -9,7 +9,8 @@ import 'react-intl';
9
9
  import '../../intl/Localizer.js';
10
10
  import '../../_virtual/dayjs.min.js';
11
11
  import '../../intl/TimeFormatter.js';
12
- import { range } from '../../libs/lodash.js';
12
+ import '../../_virtual/index.js';
13
+ import range from '../../_virtual/index2.js';
13
14
  import '../Layout/Stack/Stack.js';
14
15
  import { Cluster } from '../Layout/Cluster/Cluster.js';
15
16
  import { Reel } from '../Layout/Reel/Reel.js';
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.js","sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ElementType,\n type FC,\n type HTMLAttributes,\n type MouseEvent,\n memo,\n useMemo,\n} from 'react'\nimport { tv } from 'tailwind-variants'\n\nimport { useLatest } from '../../hooks/useLatest'\nimport { useLocalize } from '../../intl'\nimport { range } from '../../libs/lodash'\nimport { Cluster, Reel } from '../Layout'\nimport { Nav } from '../SectioningContent'\n\nimport { PaginationControllerItemButton } from './PaginationControllerItemButton'\nimport { PaginationItemButton } from './PaginationItemButton'\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-Pagination shr-inline-block shr-max-w-full',\n list: 'shr-m-0.25 shr-list-none shr-ps-[unset]',\n firstListItem: 'smarthr-ui-Pagination-first',\n prevListItem: 'smarthr-ui-Pagination-prev',\n nextListItem: 'smarthr-ui-Pagination-next',\n lastListItem: 'smarthr-ui-Pagination-last',\n },\n variants: {\n withoutNumbers: {\n true: {\n firstListItem: 'shr-mr-0.5',\n prevListItem: 'shr-mr-0',\n nextListItem: 'shr-ml-0',\n lastListItem: 'shr-ml-0.5',\n },\n false: {\n prevListItem: 'shr-mr-0.5',\n nextListItem: 'shr-ml-0.5',\n },\n },\n },\n})\n\ntype CommonProps = {\n /** 全ページ数 */\n total: number\n /** 現在のページ */\n current: number\n /** 現在のページの前後に表示するページ番号のボタンの数 */\n padding?: number\n /** `true` のとき、ページ番号のボタンを表示しない */\n withoutNumbers?: boolean\n}\n\ntype ButtonProps = CommonProps & {\n /** ボタンを押下したときに発火するコールバック関数 */\n onClick: (pageNumber: number, e: MouseEvent<HTMLElement>) => void\n /** href属性生成用関数。設定した場合、番号やarrowがbuttonからa要素に置き換わります */\n hrefTemplate?: undefined\n /** next/linkなどのカスタムコンポーネントを指定します。指定がない場合はデフォルトで `a` タグが使用されます。 */\n linkAs?: undefined\n}\ntype AnchorProps = CommonProps & {\n /** リンクを押下したときに発火するコールバック関数 */\n onClick?: (href: string, e: MouseEvent<HTMLElement>) => void\n /** href属性生成用関数。設定した場合、番号やarrowがbuttonからa要素に置き換わります */\n hrefTemplate: (pageNumber: number) => string\n /** next/linkなどのカスタムコンポーネントを指定します。指定がない場合はデフォルトで `a` タグが使用されます。 */\n linkAs?: ElementType\n}\n\ntype BaseProps = ButtonProps | AnchorProps\ntype Props = BaseProps & Omit<HTMLAttributes<HTMLElement>, keyof BaseProps>\n\nconst BUTTON_REGEX = /^button$/i\nconst ANCHOR_REGEX = /^a/i\n\nconst getTargetDelegateElement = (e: MouseEvent<HTMLElement>, regex: RegExp) =>\n (e.nativeEvent.composedPath() as HTMLElement[]).find((elm) => regex.test(elm.tagName))\n\nexport const Pagination: FC<Props> = (props) =>\n props.total > 1 ? <ActualPagination {...props} /> : null\n\nconst ActualPagination: FC<Props> = ({\n total,\n current,\n onClick,\n padding,\n className,\n withoutNumbers,\n hrefTemplate,\n linkAs,\n ...rest\n}) => {\n const classNames = useMemo(() => {\n const { wrapper, list, firstListItem, prevListItem, nextListItem, lastListItem } =\n classNameGenerator()\n const itemArg = { withoutNumbers: withoutNumbers || false }\n\n return {\n wrapper: wrapper({ className }),\n list: list(),\n firstListItem: firstListItem(itemArg),\n prevListItem: prevListItem(itemArg),\n nextListItem: nextListItem(itemArg),\n lastListItem: lastListItem(itemArg),\n }\n }, [className, withoutNumbers])\n\n const latest = useLatest({ onClick, hrefTemplate })\n const hasHrefTemplate = !!hrefTemplate\n\n const functions = useMemo(\n () => ({\n actualHrefTemplate: hasHrefTemplate\n ? (pageNumber: number) => latest.hrefTemplate!(pageNumber)\n : undefined,\n handleDelegateClick: (e: MouseEvent<HTMLElement>) => {\n if (!latest.onClick) {\n return\n }\n\n if (latest.hrefTemplate) {\n const anchor = getTargetDelegateElement(e, ANCHOR_REGEX)\n\n if (!anchor) {\n return\n }\n\n const href = (anchor as HTMLAnchorElement).href\n\n if (href) {\n ;(latest.onClick as (href: string, e: MouseEvent<HTMLElement>) => void)(href, e)\n }\n } else {\n const button = getTargetDelegateElement(e, BUTTON_REGEX)\n\n if (button) {\n ;(latest.onClick as (pageNumber: number, e: MouseEvent<HTMLElement>) => void)(\n parseInt((button as HTMLButtonElement).value, 10),\n e,\n )\n }\n }\n },\n }),\n [hasHrefTemplate, latest],\n )\n\n const { navigationLabel } = useLocalize({\n navigationLabel: {\n id: 'smarthr-ui/Pagination/navigationLabel',\n defaultText: 'ページネーション',\n },\n })\n\n return (\n <Nav {...rest} className={classNames.wrapper} aria-label={navigationLabel}>\n <Reel onClick={functions.handleDelegateClick}>\n <ItemButtons\n total={total}\n current={current}\n padding={padding}\n withoutNumbers={withoutNumbers}\n hrefTemplate={functions.actualHrefTemplate}\n classNames={classNames}\n linkAs={linkAs}\n />\n </Reel>\n </Nav>\n )\n}\n\nconst ItemButtons = memo<\n Pick<Props, 'total' | 'current' | 'padding' | 'withoutNumbers' | 'hrefTemplate' | 'linkAs'> & {\n classNames: {\n list: string\n firstListItem: string\n prevListItem: string\n nextListItem: string\n lastListItem: string\n }\n }\n>(({ total, current, padding, withoutNumbers, hrefTemplate, classNames, linkAs }) => {\n const pageNumbers = useMemo(() => {\n if (withoutNumbers) {\n return []\n }\n\n const actualPadding = padding ?? 4\n\n return range(Math.max(current - actualPadding, 1), Math.min(current + actualPadding, total) + 1)\n }, [current, total, padding, withoutNumbers])\n\n const prevAttrs = {\n disabled: current === 1,\n direction: 'prev' as const,\n hrefTemplate,\n linkAs,\n }\n const nextAttrs = {\n disabled: current === total,\n direction: 'next' as const,\n hrefTemplate,\n linkAs,\n }\n\n return (\n <Cluster as=\"ul\" className={classNames.list}>\n <DoubleIconItemButton {...prevAttrs} targetPage={1} className={classNames.firstListItem} />\n <li className={classNames.prevListItem}>\n <PaginationControllerItemButton {...prevAttrs} targetPage={current - 1} />\n </li>\n {pageNumbers.map((page) => (\n <NumberItemButton\n key={page}\n page={page}\n disabled={page === current}\n hrefTemplate={hrefTemplate}\n linkAs={linkAs}\n />\n ))}\n <li className={classNames.nextListItem}>\n <PaginationControllerItemButton {...nextAttrs} targetPage={current + 1} />\n </li>\n <DoubleIconItemButton {...nextAttrs} targetPage={total} className={classNames.lastListItem} />\n </Cluster>\n )\n})\n\nconst NumberItemButton = memo<\n Pick<Props, 'hrefTemplate' | 'linkAs'> & { page: number; disabled: boolean }\n>(({ disabled, ...rest }) => (\n <li className={`smarthr-ui-Pagination-${disabled ? 'current' : 'page'}`}>\n <PaginationItemButton {...rest} disabled={disabled} />\n </li>\n))\n\nconst DoubleIconItemButton = memo<\n Pick<Props, 'hrefTemplate' | 'linkAs'> & {\n disabled: boolean\n direction: 'prev' | 'next'\n targetPage: number\n className: string\n }\n>(({ className, ...rest }) => (\n <li className={className}>\n <PaginationControllerItemButton {...rest} double />\n </li>\n))\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAqBA;AACE;AACE;AACA;AACA;AACA;AACA;AACA;AACD;AACD;AACE;AACE;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACD;AACF;AACF;AACF;AAiCD;AACA;AAEA;AAGO;AAGP;AAWE;AACE;;;AAKE;;AAEA;AACA;AACA;AACA;;AAEJ;;AAGA;AAEA;AAEI;;AAEE;AACF;AACE;;;AAIA;;;;;AAOE;;AAGI;;;;;;AAMA;;;;AAOT;AAIH;AACE;AACE;AACA;AACD;AACF;;AAiBH;AAEA;AAWE;;AAEI;;AAGF;;;AAKF;;AAEE;;;;AAIF;;AAEE;;;;;AA0BJ;AAEA;AAQA;;"}
1
+ {"version":3,"file":"Pagination.js","sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ElementType,\n type FC,\n type HTMLAttributes,\n type MouseEvent,\n memo,\n useMemo,\n} from 'react'\nimport { tv } from 'tailwind-variants'\n\nimport { useLatest } from '../../hooks/useLatest'\nimport { useLocalize } from '../../intl'\nimport { range } from '../../libs/lodash'\nimport { Cluster, Reel } from '../Layout'\nimport { Nav } from '../SectioningContent'\n\nimport { PaginationControllerItemButton } from './PaginationControllerItemButton'\nimport { PaginationItemButton } from './PaginationItemButton'\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-Pagination shr-inline-block shr-max-w-full',\n list: 'shr-m-0.25 shr-list-none shr-ps-[unset]',\n firstListItem: 'smarthr-ui-Pagination-first',\n prevListItem: 'smarthr-ui-Pagination-prev',\n nextListItem: 'smarthr-ui-Pagination-next',\n lastListItem: 'smarthr-ui-Pagination-last',\n },\n variants: {\n withoutNumbers: {\n true: {\n firstListItem: 'shr-mr-0.5',\n prevListItem: 'shr-mr-0',\n nextListItem: 'shr-ml-0',\n lastListItem: 'shr-ml-0.5',\n },\n false: {\n prevListItem: 'shr-mr-0.5',\n nextListItem: 'shr-ml-0.5',\n },\n },\n },\n})\n\ntype CommonProps = {\n /** 全ページ数 */\n total: number\n /** 現在のページ */\n current: number\n /** 現在のページの前後に表示するページ番号のボタンの数 */\n padding?: number\n /** `true` のとき、ページ番号のボタンを表示しない */\n withoutNumbers?: boolean\n}\n\ntype ButtonProps = CommonProps & {\n /** ボタンを押下したときに発火するコールバック関数 */\n onClick: (pageNumber: number, e: MouseEvent<HTMLElement>) => void\n /** href属性生成用関数。設定した場合、番号やarrowがbuttonからa要素に置き換わります */\n hrefTemplate?: undefined\n /** next/linkなどのカスタムコンポーネントを指定します。指定がない場合はデフォルトで `a` タグが使用されます。 */\n linkAs?: undefined\n}\ntype AnchorProps = CommonProps & {\n /** リンクを押下したときに発火するコールバック関数 */\n onClick?: (href: string, e: MouseEvent<HTMLElement>) => void\n /** href属性生成用関数。設定した場合、番号やarrowがbuttonからa要素に置き換わります */\n hrefTemplate: (pageNumber: number) => string\n /** next/linkなどのカスタムコンポーネントを指定します。指定がない場合はデフォルトで `a` タグが使用されます。 */\n linkAs?: ElementType\n}\n\ntype BaseProps = ButtonProps | AnchorProps\ntype Props = BaseProps & Omit<HTMLAttributes<HTMLElement>, keyof BaseProps>\n\nconst BUTTON_REGEX = /^button$/i\nconst ANCHOR_REGEX = /^a/i\n\nconst getTargetDelegateElement = (e: MouseEvent<HTMLElement>, regex: RegExp) =>\n (e.nativeEvent.composedPath() as HTMLElement[]).find((elm) => regex.test(elm.tagName))\n\nexport const Pagination: FC<Props> = (props) =>\n props.total > 1 ? <ActualPagination {...props} /> : null\n\nconst ActualPagination: FC<Props> = ({\n total,\n current,\n onClick,\n padding,\n className,\n withoutNumbers,\n hrefTemplate,\n linkAs,\n ...rest\n}) => {\n const classNames = useMemo(() => {\n const { wrapper, list, firstListItem, prevListItem, nextListItem, lastListItem } =\n classNameGenerator()\n const itemArg = { withoutNumbers: withoutNumbers || false }\n\n return {\n wrapper: wrapper({ className }),\n list: list(),\n firstListItem: firstListItem(itemArg),\n prevListItem: prevListItem(itemArg),\n nextListItem: nextListItem(itemArg),\n lastListItem: lastListItem(itemArg),\n }\n }, [className, withoutNumbers])\n\n const latest = useLatest({ onClick, hrefTemplate })\n const hasHrefTemplate = !!hrefTemplate\n\n const functions = useMemo(\n () => ({\n actualHrefTemplate: hasHrefTemplate\n ? (pageNumber: number) => latest.hrefTemplate!(pageNumber)\n : undefined,\n handleDelegateClick: (e: MouseEvent<HTMLElement>) => {\n if (!latest.onClick) {\n return\n }\n\n if (latest.hrefTemplate) {\n const anchor = getTargetDelegateElement(e, ANCHOR_REGEX)\n\n if (!anchor) {\n return\n }\n\n const href = (anchor as HTMLAnchorElement).href\n\n if (href) {\n ;(latest.onClick as (href: string, e: MouseEvent<HTMLElement>) => void)(href, e)\n }\n } else {\n const button = getTargetDelegateElement(e, BUTTON_REGEX)\n\n if (button) {\n ;(latest.onClick as (pageNumber: number, e: MouseEvent<HTMLElement>) => void)(\n parseInt((button as HTMLButtonElement).value, 10),\n e,\n )\n }\n }\n },\n }),\n [hasHrefTemplate, latest],\n )\n\n const { navigationLabel } = useLocalize({\n navigationLabel: {\n id: 'smarthr-ui/Pagination/navigationLabel',\n defaultText: 'ページネーション',\n },\n })\n\n return (\n <Nav {...rest} className={classNames.wrapper} aria-label={navigationLabel}>\n <Reel onClick={functions.handleDelegateClick}>\n <ItemButtons\n total={total}\n current={current}\n padding={padding}\n withoutNumbers={withoutNumbers}\n hrefTemplate={functions.actualHrefTemplate}\n classNames={classNames}\n linkAs={linkAs}\n />\n </Reel>\n </Nav>\n )\n}\n\nconst ItemButtons = memo<\n Pick<Props, 'total' | 'current' | 'padding' | 'withoutNumbers' | 'hrefTemplate' | 'linkAs'> & {\n classNames: {\n list: string\n firstListItem: string\n prevListItem: string\n nextListItem: string\n lastListItem: string\n }\n }\n>(({ total, current, padding, withoutNumbers, hrefTemplate, classNames, linkAs }) => {\n const pageNumbers = useMemo(() => {\n if (withoutNumbers) {\n return []\n }\n\n const actualPadding = padding ?? 4\n\n return range(Math.max(current - actualPadding, 1), Math.min(current + actualPadding, total) + 1)\n }, [current, total, padding, withoutNumbers])\n\n const prevAttrs = {\n disabled: current === 1,\n direction: 'prev' as const,\n hrefTemplate,\n linkAs,\n }\n const nextAttrs = {\n disabled: current === total,\n direction: 'next' as const,\n hrefTemplate,\n linkAs,\n }\n\n return (\n <Cluster as=\"ul\" className={classNames.list}>\n <DoubleIconItemButton {...prevAttrs} targetPage={1} className={classNames.firstListItem} />\n <li className={classNames.prevListItem}>\n <PaginationControllerItemButton {...prevAttrs} targetPage={current - 1} />\n </li>\n {pageNumbers.map((page) => (\n <NumberItemButton\n key={page}\n page={page}\n disabled={page === current}\n hrefTemplate={hrefTemplate}\n linkAs={linkAs}\n />\n ))}\n <li className={classNames.nextListItem}>\n <PaginationControllerItemButton {...nextAttrs} targetPage={current + 1} />\n </li>\n <DoubleIconItemButton {...nextAttrs} targetPage={total} className={classNames.lastListItem} />\n </Cluster>\n )\n})\n\nconst NumberItemButton = memo<\n Pick<Props, 'hrefTemplate' | 'linkAs'> & { page: number; disabled: boolean }\n>(({ disabled, ...rest }) => (\n <li className={`smarthr-ui-Pagination-${disabled ? 'current' : 'page'}`}>\n <PaginationItemButton {...rest} disabled={disabled} />\n </li>\n))\n\nconst DoubleIconItemButton = memo<\n Pick<Props, 'hrefTemplate' | 'linkAs'> & {\n disabled: boolean\n direction: 'prev' | 'next'\n targetPage: number\n className: string\n }\n>(({ className, ...rest }) => (\n <li className={className}>\n <PaginationControllerItemButton {...rest} double />\n </li>\n))\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAqBA;AACE;AACE;AACA;AACA;AACA;AACA;AACA;AACD;AACD;AACE;AACE;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACD;AACF;AACF;AACF;AAiCD;AACA;AAEA;AAGO;AAGP;AAWE;AACE;;;AAKE;;AAEA;AACA;AACA;AACA;;AAEJ;;AAGA;AAEA;AAEI;;AAEE;AACF;AACE;;;AAIA;;;;;AAOE;;AAGI;;;;;;AAMA;;;;AAOT;AAIH;AACE;AACE;AACA;AACD;AACF;;AAiBH;AAEA;AAWE;;AAEI;;AAGF;;;AAKF;;AAEE;;;;AAIF;;AAEE;;;;;AA0BJ;AAEA;AAQA;;"}
@@ -29,6 +29,7 @@ const classNameGenerator = index.tv({
29
29
  left: 'shr-rounded-l-l',
30
30
  },
31
31
  },
32
+ // TODO: tailwindの場合のみdefault値が設定される挙動はバグの原因になりかねないので整理する
32
33
  defaultVariants: {
33
34
  bgColor: 'COLUMN',
34
35
  rounded: false,
@@ -1 +1 @@
1
- {"version":3,"file":"Groupbox.cjs","sources":["../../../../src/components/Panel/Groupbox/Groupbox.tsx"],"sourcesContent":["import { type ComponentProps, type FC, useMemo } from 'react'\nimport { type VariantProps, tv } from 'tailwind-variants'\n\nimport { backgroundColor } from '../../../tailwind'\nimport { Panel } from '../Panel'\n\ntype BaseProps = Omit<ComponentProps<typeof Panel>, 'radius' | 'layer'> &\n VariantProps<typeof classNameGenerator>\ntype Props = BaseProps & Omit<ComponentProps<'div'>, keyof BaseProps>\n\nconst classNameGenerator = tv({\n base: 'shr-rounded-[unset]',\n variants: {\n bgColor: backgroundColor,\n rounded: {\n true: 'shr-rounded-l',\n all: 'shr-rounded-l',\n top: 'shr-rounded-t-l',\n right: 'shr-rounded-r-l',\n bottom: 'shr-rounded-b-l',\n left: 'shr-rounded-l-l',\n },\n },\n defaultVariants: {\n bgColor: 'COLUMN',\n rounded: false,\n },\n})\n\nexport const Groupbox: FC<Props> = ({ bgColor, rounded, padding = 1, className, ...rest }) => {\n const actualClassName = useMemo(\n () => classNameGenerator({ bgColor, rounded, className }),\n [bgColor, rounded, className],\n )\n\n return <Panel {...rest} padding={padding} layer={0} className={actualClassName} />\n}\n"],"names":["tv","backgroundColor","useMemo","_jsx","Panel"],"mappings":";;;;;;;;;;;;;;;;;;AAUA,MAAM,kBAAkB,GAAGA,QAAE,CAAC;AAC5B,IAAA,IAAI,EAAE,qBAAqB;AAC3B,IAAA,QAAQ,EAAE;AACR,QAAA,OAAO,EAAEC,wCAAe;AACxB,QAAA,OAAO,EAAE;AACP,YAAA,IAAI,EAAE,eAAe;AACrB,YAAA,GAAG,EAAE,eAAe;AACpB,YAAA,GAAG,EAAE,iBAAiB;AACtB,YAAA,KAAK,EAAE,iBAAiB;AACxB,YAAA,MAAM,EAAE,iBAAiB;AACzB,YAAA,IAAI,EAAE,iBAAiB;AACxB,SAAA;AACF,KAAA;AACD,IAAA,eAAe,EAAE;AACf,QAAA,OAAO,EAAE,QAAQ;AACjB,QAAA,OAAO,EAAE,KAAK;AACf,KAAA;AACF,CAAA,CAAC;MAEW,QAAQ,GAAc,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,KAAI;IAC3F,MAAM,eAAe,GAAGC,aAAO,CAC7B,MAAM,kBAAkB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EACzD,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAC9B;AAED,IAAA,OAAOC,eAACC,4BAAK,EAAA,EAAA,GAAK,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,eAAe,GAAI;AACpF;;;;"}
1
+ {"version":3,"file":"Groupbox.cjs","sources":["../../../../src/components/Panel/Groupbox/Groupbox.tsx"],"sourcesContent":["import { type ComponentProps, type FC, useMemo } from 'react'\nimport { type VariantProps, tv } from 'tailwind-variants'\n\nimport { backgroundColor } from '../../../tailwind'\nimport { Panel } from '../Panel'\n\ntype BaseProps = Omit<ComponentProps<typeof Panel>, 'radius' | 'layer'> &\n VariantProps<typeof classNameGenerator>\ntype Props = BaseProps & Omit<ComponentProps<'div'>, keyof BaseProps>\n\nconst classNameGenerator = tv({\n base: 'shr-rounded-[unset]',\n variants: {\n bgColor: backgroundColor,\n rounded: {\n true: 'shr-rounded-l',\n all: 'shr-rounded-l',\n top: 'shr-rounded-t-l',\n right: 'shr-rounded-r-l',\n bottom: 'shr-rounded-b-l',\n left: 'shr-rounded-l-l',\n },\n },\n // TODO: tailwindの場合のみdefault値が設定される挙動はバグの原因になりかねないので整理する\n defaultVariants: {\n bgColor: 'COLUMN',\n rounded: false,\n },\n})\n\nexport const Groupbox: FC<Props> = ({ bgColor, rounded, padding = 1, className, ...rest }) => {\n const actualClassName = useMemo(\n () => classNameGenerator({ bgColor, rounded, className }),\n [bgColor, rounded, className],\n )\n\n return <Panel {...rest} padding={padding} layer={0} className={actualClassName} />\n}\n"],"names":["tv","backgroundColor","useMemo","_jsx","Panel"],"mappings":";;;;;;;;;;;;;;;;;;AAUA,MAAM,kBAAkB,GAAGA,QAAE,CAAC;AAC5B,IAAA,IAAI,EAAE,qBAAqB;AAC3B,IAAA,QAAQ,EAAE;AACR,QAAA,OAAO,EAAEC,wCAAe;AACxB,QAAA,OAAO,EAAE;AACP,YAAA,IAAI,EAAE,eAAe;AACrB,YAAA,GAAG,EAAE,eAAe;AACpB,YAAA,GAAG,EAAE,iBAAiB;AACtB,YAAA,KAAK,EAAE,iBAAiB;AACxB,YAAA,MAAM,EAAE,iBAAiB;AACzB,YAAA,IAAI,EAAE,iBAAiB;AACxB,SAAA;AACF,KAAA;;AAED,IAAA,eAAe,EAAE;AACf,QAAA,OAAO,EAAE,QAAQ;AACjB,QAAA,OAAO,EAAE,KAAK;AACf,KAAA;AACF,CAAA,CAAC;MAEW,QAAQ,GAAc,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,KAAI;IAC3F,MAAM,eAAe,GAAGC,aAAO,CAC7B,MAAM,kBAAkB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EACzD,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAC9B;AAED,IAAA,OAAOC,eAACC,4BAAK,EAAA,EAAA,GAAK,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,eAAe,GAAI;AACpF;;;;"}
@@ -27,6 +27,7 @@ const classNameGenerator = ce({
27
27
  left: 'shr-rounded-l-l',
28
28
  },
29
29
  },
30
+ // TODO: tailwindの場合のみdefault値が設定される挙動はバグの原因になりかねないので整理する
30
31
  defaultVariants: {
31
32
  bgColor: 'COLUMN',
32
33
  rounded: false,
@@ -1 +1 @@
1
- {"version":3,"file":"Groupbox.js","sources":["../../../../src/components/Panel/Groupbox/Groupbox.tsx"],"sourcesContent":["import { type ComponentProps, type FC, useMemo } from 'react'\nimport { type VariantProps, tv } from 'tailwind-variants'\n\nimport { backgroundColor } from '../../../tailwind'\nimport { Panel } from '../Panel'\n\ntype BaseProps = Omit<ComponentProps<typeof Panel>, 'radius' | 'layer'> &\n VariantProps<typeof classNameGenerator>\ntype Props = BaseProps & Omit<ComponentProps<'div'>, keyof BaseProps>\n\nconst classNameGenerator = tv({\n base: 'shr-rounded-[unset]',\n variants: {\n bgColor: backgroundColor,\n rounded: {\n true: 'shr-rounded-l',\n all: 'shr-rounded-l',\n top: 'shr-rounded-t-l',\n right: 'shr-rounded-r-l',\n bottom: 'shr-rounded-b-l',\n left: 'shr-rounded-l-l',\n },\n },\n defaultVariants: {\n bgColor: 'COLUMN',\n rounded: false,\n },\n})\n\nexport const Groupbox: FC<Props> = ({ bgColor, rounded, padding = 1, className, ...rest }) => {\n const actualClassName = useMemo(\n () => classNameGenerator({ bgColor, rounded, className }),\n [bgColor, rounded, className],\n )\n\n return <Panel {...rest} padding={padding} layer={0} className={actualClassName} />\n}\n"],"names":["tv","_jsx"],"mappings":";;;;;;;;;;;;;;;;AAUA,MAAM,kBAAkB,GAAGA,EAAE,CAAC;AAC5B,IAAA,IAAI,EAAE,qBAAqB;AAC3B,IAAA,QAAQ,EAAE;AACR,QAAA,OAAO,EAAE,eAAe;AACxB,QAAA,OAAO,EAAE;AACP,YAAA,IAAI,EAAE,eAAe;AACrB,YAAA,GAAG,EAAE,eAAe;AACpB,YAAA,GAAG,EAAE,iBAAiB;AACtB,YAAA,KAAK,EAAE,iBAAiB;AACxB,YAAA,MAAM,EAAE,iBAAiB;AACzB,YAAA,IAAI,EAAE,iBAAiB;AACxB,SAAA;AACF,KAAA;AACD,IAAA,eAAe,EAAE;AACf,QAAA,OAAO,EAAE,QAAQ;AACjB,QAAA,OAAO,EAAE,KAAK;AACf,KAAA;AACF,CAAA,CAAC;MAEW,QAAQ,GAAc,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,KAAI;IAC3F,MAAM,eAAe,GAAG,OAAO,CAC7B,MAAM,kBAAkB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EACzD,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAC9B;AAED,IAAA,OAAOC,IAAC,KAAK,EAAA,EAAA,GAAK,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,eAAe,GAAI;AACpF;;;;"}
1
+ {"version":3,"file":"Groupbox.js","sources":["../../../../src/components/Panel/Groupbox/Groupbox.tsx"],"sourcesContent":["import { type ComponentProps, type FC, useMemo } from 'react'\nimport { type VariantProps, tv } from 'tailwind-variants'\n\nimport { backgroundColor } from '../../../tailwind'\nimport { Panel } from '../Panel'\n\ntype BaseProps = Omit<ComponentProps<typeof Panel>, 'radius' | 'layer'> &\n VariantProps<typeof classNameGenerator>\ntype Props = BaseProps & Omit<ComponentProps<'div'>, keyof BaseProps>\n\nconst classNameGenerator = tv({\n base: 'shr-rounded-[unset]',\n variants: {\n bgColor: backgroundColor,\n rounded: {\n true: 'shr-rounded-l',\n all: 'shr-rounded-l',\n top: 'shr-rounded-t-l',\n right: 'shr-rounded-r-l',\n bottom: 'shr-rounded-b-l',\n left: 'shr-rounded-l-l',\n },\n },\n // TODO: tailwindの場合のみdefault値が設定される挙動はバグの原因になりかねないので整理する\n defaultVariants: {\n bgColor: 'COLUMN',\n rounded: false,\n },\n})\n\nexport const Groupbox: FC<Props> = ({ bgColor, rounded, padding = 1, className, ...rest }) => {\n const actualClassName = useMemo(\n () => classNameGenerator({ bgColor, rounded, className }),\n [bgColor, rounded, className],\n )\n\n return <Panel {...rest} padding={padding} layer={0} className={actualClassName} />\n}\n"],"names":["tv","_jsx"],"mappings":";;;;;;;;;;;;;;;;AAUA,MAAM,kBAAkB,GAAGA,EAAE,CAAC;AAC5B,IAAA,IAAI,EAAE,qBAAqB;AAC3B,IAAA,QAAQ,EAAE;AACR,QAAA,OAAO,EAAE,eAAe;AACxB,QAAA,OAAO,EAAE;AACP,YAAA,IAAI,EAAE,eAAe;AACrB,YAAA,GAAG,EAAE,eAAe;AACpB,YAAA,GAAG,EAAE,iBAAiB;AACtB,YAAA,KAAK,EAAE,iBAAiB;AACxB,YAAA,MAAM,EAAE,iBAAiB;AACzB,YAAA,IAAI,EAAE,iBAAiB;AACxB,SAAA;AACF,KAAA;;AAED,IAAA,eAAe,EAAE;AACf,QAAA,OAAO,EAAE,QAAQ;AACjB,QAAA,OAAO,EAAE,KAAK;AACf,KAAA;AACF,CAAA,CAAC;MAEW,QAAQ,GAAc,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,KAAI;IAC3F,MAAM,eAAe,GAAG,OAAO,CAC7B,MAAM,kBAAkB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EACzD,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAC9B;AAED,IAAA,OAAOC,IAAC,KAAK,EAAA,EAAA,GAAK,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,eAAe,GAAI;AACpF;;;;"}
@@ -60,12 +60,17 @@ const ActualSelect = ({ options, onChange, onChangeValue, error, width, hasBlank
60
60
  iconWrap: iconWrap(sizeProps),
61
61
  blankOptGroup: blankOptgroup(),
62
62
  };
63
- }, [className, size]);
64
- const wrapperStyle = React.useMemo(() => ({
65
- width: typeof width === 'number' ? `${width}px` : width,
66
- }), [width]);
67
- const actualBlankLabel = blankLabel ?? '';
68
- return (jsxRuntime.jsxs("span", { className: classNames.wrapper, style: wrapperStyle, children: [jsxRuntime.jsxs("select", { ...rest, "data-smarthr-ui-input": "true", onChange: (e) => {
63
+ }, [size, className]);
64
+ return (jsxRuntime.jsxs("span", { className: classNames.wrapper, style: {
65
+ width: typeof width === 'number' ? `${width}px` : width,
66
+ }, children: [jsxRuntime.jsxs("select", { ...rest, ref: ref, disabled: disabled,
67
+ // HINT: required属性を設定すると、iOS端末で以下の問題が発生します
68
+ // - フォームのsubmit時にバリデーションは行われるが、ユーザーにフィードバックがない
69
+ // - エラーメッセージが表示されない
70
+ // - 問題のある入力フィールドまでスクロールしない
71
+ // 歴史的に一部の端末ではrequired属性が無視されることがあるため、HTMLのバリデーションのみとすることは少ないです
72
+ // そのため、iOS端末ではrequired属性を設定しない方がユーザーがsubmitできない理由をエラーメッセージなどで正しく理解できるようになります
73
+ required: libs_ua.isIOS ? undefined : required, "aria-invalid": error || undefined, "data-smarthr-ui-input": "true", onChange: (e) => {
69
74
  onChange?.(e);
70
75
  if (onChangeValue) {
71
76
  const selectedOption = options
@@ -75,14 +80,7 @@ const ActualSelect = ({ options, onChange, onChangeValue, error, width, hasBlank
75
80
  onChangeValue(selectedOption.value);
76
81
  }
77
82
  }
78
- }, "aria-invalid": error || undefined, disabled: disabled,
79
- // HINT: required属性を設定すると、iOS端末で以下の問題が発生します
80
- // - フォームのsubmit時にバリデーションは行われるが、ユーザーにフィードバックがない
81
- // - エラーメッセージが表示されない
82
- // - 問題のある入力フィールドまでスクロールしない
83
- // 歴史的に一部の端末ではrequired属性が無視されることがあるため、HTMLのバリデーションのみとすることは少ないです
84
- // そのため、iOS端末ではrequired属性を設定しない方がユーザーがsubmitできない理由をエラーメッセージなどで正しく理解できるようになります
85
- required: libs_ua.isIOS ? undefined : required, ref: ref, className: classNames.select, children: [jsxRuntime.jsx(BlankOption, { hasBlank: hasBlank, children: actualBlankLabel }), options.map((option, index) => (React.createElement(Option, { ...option, key: index }))), jsxRuntime.jsx(NotOmittingLabelsInMobileSafari, { className: classNames.blankOptGroup })] }), jsxRuntime.jsx("span", { className: classNames.iconWrap, children: jsxRuntime.jsx(components_Icon_FaIcon.FaAngleDownIcon, {}) })] }));
83
+ }, className: classNames.select, children: [jsxRuntime.jsx(BlankOption, { hasBlank: hasBlank, children: blankLabel ?? '' }), options.map((option, index) => (React.createElement(Option, { ...option, key: index }))), jsxRuntime.jsx(NotOmittingLabelsInMobileSafari, { className: classNames.blankOptGroup })] }), jsxRuntime.jsx("span", { className: classNames.iconWrap, children: jsxRuntime.jsx(components_Icon_FaIcon.FaAngleDownIcon, {}) })] }));
86
84
  };
87
85
  const BlankOption = React.memo(({ hasBlank, children }) => hasBlank && jsxRuntime.jsx("option", { value: "", children: children }));
88
86
  const Option = React.memo((option) => {
@@ -1 +1 @@
1
- {"version":3,"file":"Select.cjs","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n type ForwardedRef,\n type OptgroupHTMLAttributes,\n type OptionHTMLAttributes,\n type PropsWithChildren,\n memo,\n useMemo,\n} from 'react'\nimport { tv } from 'tailwind-variants'\n\nimport { isIOS, isMobileSafari } from '../../libs/ua'\nimport { genericsForwardRef } from '../../libs/util'\nimport { FaAngleDownIcon } from '../Icon'\n\ntype Option<T extends string> = {\n value: T\n} & Omit<OptionHTMLAttributes<HTMLOptionElement>, 'value'>\ntype Optgroup<T extends string> = {\n label: string\n options: Array<Option<T>>\n} & OptgroupHTMLAttributes<HTMLOptGroupElement>\n\ntype BaseProps<T extends string> = {\n /** 選択肢のデータの配列 */\n options: Array<Option<T> | Optgroup<T>>\n /** フォームの値が変わったときに発火するコールバック関数 */\n onChangeValue?: (value: T) => void\n /** フォームの値にエラーがあるかどうか */\n error?: boolean\n /** コンポーネントの幅 */\n width?: number | string\n /** コンポーネントの大きさ */\n size?: 'M' | 'S'\n /** 空の選択肢を表示するかどうか */\n hasBlank?: boolean\n /** 空の選択肢のラベル */\n blankLabel?: string\n}\n\ntype Props<T extends string> = BaseProps<T> &\n Omit<ComponentPropsWithoutRef<'select'>, keyof BaseProps<string> | 'children'>\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-Select shr-relative shr-inline-block',\n select: [\n 'shr-peer shr-border-shorthand shr-w-full shr-cursor-pointer shr-appearance-none shr-rounded-m shr-bg-white shr-text-base shr-leading-tight shr-text-black',\n 'hover:shr-bg-white-darken',\n 'focus-visible:shr-focus-indicator',\n 'disabled:shr-pointer-events-none disabled:shr-bg-white-darken disabled:shr-text-disabled disabled:shr-opacity-100',\n 'contrast-more:shr-border-high-contrast',\n /* padding に依る積み上げでは文字が見切れてしまうため */\n 'shr-min-h-[calc(theme(fontSize.base)_+_theme(spacing[0.75])_*_2_+_theme(spacing.px)_*_2)]',\n 'shr-border-default disabled:shr-border-disabled',\n 'aria-[invalid]:shr-border-danger',\n ],\n iconWrap: [\n 'shr-pointer-events-none shr-absolute shr-inset-y-0 shr-inline-flex shr-items-center shr-text-grey',\n 'peer-focus-visible:shr-text-black peer-disabled:shr-text-disabled',\n ],\n blankOptgroup: 'shr-hidden',\n },\n variants: {\n size: {\n M: {\n select: 'shr-py-0.5 shr-pe-2 shr-ps-0.5',\n // ((右 padding - アイコン幅) / 2) + 右 border\n iconWrap: 'shr-end-[calc(theme(spacing[0.5])_+_theme(spacing.px))]',\n },\n S: {\n select: [\n 'shr-px-0.5 shr-py-0.25 shr-pe-1.5 shr-text-sm',\n /* padding に依る積み上げでは文字が見切れてしまうため */\n 'shr-min-h-[calc(theme(fontSize.sm)_+_theme(spacing[0.5])_*_2_+_theme(spacing.px)_*_2)]',\n ],\n iconWrap: 'shr-end-0.5 shr-text-sm',\n },\n },\n },\n})\n\nconst ActualSelect = <T extends string>(\n {\n options,\n onChange,\n onChangeValue,\n error,\n width,\n hasBlank,\n blankLabel,\n size,\n className,\n disabled,\n required,\n ...rest\n }: Props<T>,\n ref: ForwardedRef<HTMLSelectElement>,\n) => {\n const classNames = useMemo(() => {\n const { wrapper, select, iconWrap, blankOptgroup } = classNameGenerator()\n const sizeProps = {\n size: size || 'M',\n }\n\n return {\n wrapper: wrapper({ className }),\n select: select(sizeProps),\n iconWrap: iconWrap(sizeProps),\n blankOptGroup: blankOptgroup(),\n }\n }, [className, size])\n const wrapperStyle = useMemo(\n () => ({\n width: typeof width === 'number' ? `${width}px` : width,\n }),\n [width],\n )\n\n const actualBlankLabel = blankLabel ?? ''\n\n return (\n <span className={classNames.wrapper} style={wrapperStyle}>\n <select\n {...rest}\n data-smarthr-ui-input=\"true\"\n onChange={(e: ChangeEvent<HTMLSelectElement>) => {\n onChange?.(e)\n\n if (onChangeValue) {\n const selectedOption = options\n .flatMap((option) => ('value' in option ? [option] : option.options))\n .find((option) => option.value === e.target.value)\n\n if (selectedOption) {\n onChangeValue(selectedOption.value)\n }\n }\n }}\n aria-invalid={error || undefined}\n disabled={disabled}\n // HINT: required属性を設定すると、iOS端末で以下の問題が発生します\n // - フォームのsubmit時にバリデーションは行われるが、ユーザーにフィードバックがない\n // - エラーメッセージが表示されない\n // - 問題のある入力フィールドまでスクロールしない\n // 歴史的に一部の端末ではrequired属性が無視されることがあるため、HTMLのバリデーションのみとすることは少ないです\n // そのため、iOS端末ではrequired属性を設定しない方がユーザーがsubmitできない理由をエラーメッセージなどで正しく理解できるようになります\n required={isIOS ? undefined : required}\n ref={ref}\n className={classNames.select}\n >\n <BlankOption hasBlank={hasBlank}>{actualBlankLabel}</BlankOption>\n {options.map((option, index) => (\n <Option {...option} key={index} />\n ))}\n <NotOmittingLabelsInMobileSafari className={classNames.blankOptGroup} />\n </select>\n <span className={classNames.iconWrap}>\n <FaAngleDownIcon />\n </span>\n </span>\n )\n}\n\nconst BlankOption = memo<\n PropsWithChildren<{\n hasBlank: boolean | undefined\n }>\n>(({ hasBlank, children }) => hasBlank && <option value=\"\">{children}</option>)\n\nconst Option = memo<Props<string>['options'][number]>((option) => {\n if ('value' in option) {\n return <option {...option}>{option.label}</option>\n }\n\n const { options: groupedOptions, label, ...rest } = option\n\n return (\n <optgroup {...rest} key={label} label={label}>\n {groupedOptions.map((groupedOption) => (\n <option {...groupedOption} key={groupedOption.value}>\n {groupedOption.label}\n </option>\n ))}\n </optgroup>\n )\n})\n\n// Support for not omitting labels in Mobile Safari\nconst NotOmittingLabelsInMobileSafari = memo<{ className: string }>(\n ({ className }) => isMobileSafari && <optgroup className={className} />,\n)\n\nexport const Select = genericsForwardRef(ActualSelect)\n"],"names":[],"mappings":";;;;;;;;;;;;AA8CA;AACE;AACE;AACA;;;;;;;;;;AAUC;AACD;;;AAGC;AACD;AACD;AACD;AACE;AACE;AACE;;AAEA;AACD;AACD;AACE;;;;AAIC;AACD;AACD;AACF;AACF;AACF;AAED;AAiBE;AACE;AACA;;;;AAKE;AACA;AACA;;;AAGJ;AACA;AAEI;AACD;AAIH;;AAQQ;;;;AAKK;;AAGD;;;AAGN;;;;;;;AASA;AAeR;AAEA;AAMA;AACE;AACE;;AAGF;AAEA;AASF;AAEA;AACA;;;"}
1
+ {"version":3,"file":"Select.cjs","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n type ForwardedRef,\n type OptgroupHTMLAttributes,\n type OptionHTMLAttributes,\n type PropsWithChildren,\n memo,\n useMemo,\n} from 'react'\nimport { tv } from 'tailwind-variants'\n\nimport { isIOS, isMobileSafari } from '../../libs/ua'\nimport { genericsForwardRef } from '../../libs/util'\nimport { FaAngleDownIcon } from '../Icon'\n\ntype Option<T extends string> = {\n value: T\n} & Omit<OptionHTMLAttributes<HTMLOptionElement>, 'value'>\ntype Optgroup<T extends string> = {\n label: string\n options: Array<Option<T>>\n} & OptgroupHTMLAttributes<HTMLOptGroupElement>\n\ntype BaseProps<T extends string> = {\n /** 選択肢のデータの配列 */\n options: Array<Option<T> | Optgroup<T>>\n /** フォームの値が変わったときに発火するコールバック関数 */\n onChangeValue?: (value: T) => void\n /** フォームの値にエラーがあるかどうか */\n error?: boolean\n /** コンポーネントの幅 */\n width?: number | string\n /** コンポーネントの大きさ */\n size?: 'M' | 'S'\n /** 空の選択肢を表示するかどうか */\n hasBlank?: boolean\n /** 空の選択肢のラベル */\n blankLabel?: string\n}\n\ntype Props<T extends string> = BaseProps<T> &\n Omit<ComponentPropsWithoutRef<'select'>, keyof BaseProps<string> | 'children'>\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-Select shr-relative shr-inline-block',\n select: [\n 'shr-peer shr-border-shorthand shr-w-full shr-cursor-pointer shr-appearance-none shr-rounded-m shr-bg-white shr-text-base shr-leading-tight shr-text-black',\n 'hover:shr-bg-white-darken',\n 'focus-visible:shr-focus-indicator',\n 'disabled:shr-pointer-events-none disabled:shr-bg-white-darken disabled:shr-text-disabled disabled:shr-opacity-100',\n 'contrast-more:shr-border-high-contrast',\n /* padding に依る積み上げでは文字が見切れてしまうため */\n 'shr-min-h-[calc(theme(fontSize.base)_+_theme(spacing[0.75])_*_2_+_theme(spacing.px)_*_2)]',\n 'shr-border-default disabled:shr-border-disabled',\n 'aria-[invalid]:shr-border-danger',\n ],\n iconWrap: [\n 'shr-pointer-events-none shr-absolute shr-inset-y-0 shr-inline-flex shr-items-center shr-text-grey',\n 'peer-focus-visible:shr-text-black peer-disabled:shr-text-disabled',\n ],\n blankOptgroup: 'shr-hidden',\n },\n variants: {\n size: {\n M: {\n select: 'shr-py-0.5 shr-pe-2 shr-ps-0.5',\n // ((右 padding - アイコン幅) / 2) + 右 border\n iconWrap: 'shr-end-[calc(theme(spacing[0.5])_+_theme(spacing.px))]',\n },\n S: {\n select: [\n 'shr-px-0.5 shr-py-0.25 shr-pe-1.5 shr-text-sm',\n /* padding に依る積み上げでは文字が見切れてしまうため */\n 'shr-min-h-[calc(theme(fontSize.sm)_+_theme(spacing[0.5])_*_2_+_theme(spacing.px)_*_2)]',\n ],\n iconWrap: 'shr-end-0.5 shr-text-sm',\n },\n },\n },\n})\n\nconst ActualSelect = <T extends string>(\n {\n options,\n onChange,\n onChangeValue,\n error,\n width,\n hasBlank,\n blankLabel,\n size,\n className,\n disabled,\n required,\n ...rest\n }: Props<T>,\n ref: ForwardedRef<HTMLSelectElement>,\n) => {\n const classNames = useMemo(() => {\n const { wrapper, select, iconWrap, blankOptgroup } = classNameGenerator()\n const sizeProps = {\n size: size || 'M',\n }\n\n return {\n wrapper: wrapper({ className }),\n select: select(sizeProps),\n iconWrap: iconWrap(sizeProps),\n blankOptGroup: blankOptgroup(),\n }\n }, [size, className])\n\n return (\n <span\n className={classNames.wrapper}\n style={{\n width: typeof width === 'number' ? `${width}px` : width,\n }}\n >\n <select\n {...rest}\n ref={ref}\n disabled={disabled}\n // HINT: required属性を設定すると、iOS端末で以下の問題が発生します\n // - フォームのsubmit時にバリデーションは行われるが、ユーザーにフィードバックがない\n // - エラーメッセージが表示されない\n // - 問題のある入力フィールドまでスクロールしない\n // 歴史的に一部の端末ではrequired属性が無視されることがあるため、HTMLのバリデーションのみとすることは少ないです\n // そのため、iOS端末ではrequired属性を設定しない方がユーザーがsubmitできない理由をエラーメッセージなどで正しく理解できるようになります\n required={isIOS ? undefined : required}\n aria-invalid={error || undefined}\n data-smarthr-ui-input=\"true\"\n onChange={(e: ChangeEvent<HTMLSelectElement>) => {\n onChange?.(e)\n\n if (onChangeValue) {\n const selectedOption = options\n .flatMap((option) => ('value' in option ? [option] : option.options))\n .find((option) => option.value === e.target.value)\n\n if (selectedOption) {\n onChangeValue(selectedOption.value)\n }\n }\n }}\n className={classNames.select}\n >\n <BlankOption hasBlank={hasBlank}>{blankLabel ?? ''}</BlankOption>\n {options.map((option, index) => (\n <Option {...option} key={index} />\n ))}\n <NotOmittingLabelsInMobileSafari className={classNames.blankOptGroup} />\n </select>\n <span className={classNames.iconWrap}>\n <FaAngleDownIcon />\n </span>\n </span>\n )\n}\n\nconst BlankOption = memo<\n PropsWithChildren<{\n hasBlank: boolean | undefined\n }>\n>(({ hasBlank, children }) => hasBlank && <option value=\"\">{children}</option>)\n\nconst Option = memo<Props<string>['options'][number]>((option) => {\n if ('value' in option) {\n return <option {...option}>{option.label}</option>\n }\n\n const { options: groupedOptions, label, ...rest } = option\n\n return (\n <optgroup {...rest} key={label} label={label}>\n {groupedOptions.map((groupedOption) => (\n <option {...groupedOption} key={groupedOption.value}>\n {groupedOption.label}\n </option>\n ))}\n </optgroup>\n )\n})\n\n// Support for not omitting labels in Mobile Safari\nconst NotOmittingLabelsInMobileSafari = memo<{ className: string }>(\n ({ className }) => isMobileSafari && <optgroup className={className} />,\n)\n\nexport const Select = genericsForwardRef(ActualSelect)\n"],"names":[],"mappings":";;;;;;;;;;;;AA8CA;AACE;AACE;AACA;;;;;;;;;;AAUC;AACD;;;AAGC;AACD;AACD;AACD;AACE;AACE;AACE;;AAEA;AACD;AACD;AACE;;;;AAIC;AACD;AACD;AACF;AACF;AACF;AAED;AAiBE;AACE;AACA;;;;AAKE;AACA;AACA;;;AAGJ;;AAMM;;;;;;;;;AAiBE;;;;AAKK;;AAGD;;;AAGN;AAcR;AAEA;AAMA;AACE;AACE;;AAGF;AAEA;AASF;AAEA;AACA;;;"}
@@ -58,12 +58,17 @@ const ActualSelect = ({ options, onChange, onChangeValue, error, width, hasBlank
58
58
  iconWrap: iconWrap(sizeProps),
59
59
  blankOptGroup: blankOptgroup(),
60
60
  };
61
- }, [className, size]);
62
- const wrapperStyle = useMemo(() => ({
63
- width: typeof width === 'number' ? `${width}px` : width,
64
- }), [width]);
65
- const actualBlankLabel = blankLabel ?? '';
66
- return (jsxs("span", { className: classNames.wrapper, style: wrapperStyle, children: [jsxs("select", { ...rest, "data-smarthr-ui-input": "true", onChange: (e) => {
61
+ }, [size, className]);
62
+ return (jsxs("span", { className: classNames.wrapper, style: {
63
+ width: typeof width === 'number' ? `${width}px` : width,
64
+ }, children: [jsxs("select", { ...rest, ref: ref, disabled: disabled,
65
+ // HINT: required属性を設定すると、iOS端末で以下の問題が発生します
66
+ // - フォームのsubmit時にバリデーションは行われるが、ユーザーにフィードバックがない
67
+ // - エラーメッセージが表示されない
68
+ // - 問題のある入力フィールドまでスクロールしない
69
+ // 歴史的に一部の端末ではrequired属性が無視されることがあるため、HTMLのバリデーションのみとすることは少ないです
70
+ // そのため、iOS端末ではrequired属性を設定しない方がユーザーがsubmitできない理由をエラーメッセージなどで正しく理解できるようになります
71
+ required: isIOS ? undefined : required, "aria-invalid": error || undefined, "data-smarthr-ui-input": "true", onChange: (e) => {
67
72
  onChange?.(e);
68
73
  if (onChangeValue) {
69
74
  const selectedOption = options
@@ -73,14 +78,7 @@ const ActualSelect = ({ options, onChange, onChangeValue, error, width, hasBlank
73
78
  onChangeValue(selectedOption.value);
74
79
  }
75
80
  }
76
- }, "aria-invalid": error || undefined, disabled: disabled,
77
- // HINT: required属性を設定すると、iOS端末で以下の問題が発生します
78
- // - フォームのsubmit時にバリデーションは行われるが、ユーザーにフィードバックがない
79
- // - エラーメッセージが表示されない
80
- // - 問題のある入力フィールドまでスクロールしない
81
- // 歴史的に一部の端末ではrequired属性が無視されることがあるため、HTMLのバリデーションのみとすることは少ないです
82
- // そのため、iOS端末ではrequired属性を設定しない方がユーザーがsubmitできない理由をエラーメッセージなどで正しく理解できるようになります
83
- required: isIOS ? undefined : required, ref: ref, className: classNames.select, children: [jsx(BlankOption, { hasBlank: hasBlank, children: actualBlankLabel }), options.map((option, index) => (createElement(Option, { ...option, key: index }))), jsx(NotOmittingLabelsInMobileSafari, { className: classNames.blankOptGroup })] }), jsx("span", { className: classNames.iconWrap, children: jsx(FaAngleDownIcon, {}) })] }));
81
+ }, className: classNames.select, children: [jsx(BlankOption, { hasBlank: hasBlank, children: blankLabel ?? '' }), options.map((option, index) => (createElement(Option, { ...option, key: index }))), jsx(NotOmittingLabelsInMobileSafari, { className: classNames.blankOptGroup })] }), jsx("span", { className: classNames.iconWrap, children: jsx(FaAngleDownIcon, {}) })] }));
84
82
  };
85
83
  const BlankOption = memo(({ hasBlank, children }) => hasBlank && jsx("option", { value: "", children: children }));
86
84
  const Option = memo((option) => {
@@ -1 +1 @@
1
- {"version":3,"file":"Select.js","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n type ForwardedRef,\n type OptgroupHTMLAttributes,\n type OptionHTMLAttributes,\n type PropsWithChildren,\n memo,\n useMemo,\n} from 'react'\nimport { tv } from 'tailwind-variants'\n\nimport { isIOS, isMobileSafari } from '../../libs/ua'\nimport { genericsForwardRef } from '../../libs/util'\nimport { FaAngleDownIcon } from '../Icon'\n\ntype Option<T extends string> = {\n value: T\n} & Omit<OptionHTMLAttributes<HTMLOptionElement>, 'value'>\ntype Optgroup<T extends string> = {\n label: string\n options: Array<Option<T>>\n} & OptgroupHTMLAttributes<HTMLOptGroupElement>\n\ntype BaseProps<T extends string> = {\n /** 選択肢のデータの配列 */\n options: Array<Option<T> | Optgroup<T>>\n /** フォームの値が変わったときに発火するコールバック関数 */\n onChangeValue?: (value: T) => void\n /** フォームの値にエラーがあるかどうか */\n error?: boolean\n /** コンポーネントの幅 */\n width?: number | string\n /** コンポーネントの大きさ */\n size?: 'M' | 'S'\n /** 空の選択肢を表示するかどうか */\n hasBlank?: boolean\n /** 空の選択肢のラベル */\n blankLabel?: string\n}\n\ntype Props<T extends string> = BaseProps<T> &\n Omit<ComponentPropsWithoutRef<'select'>, keyof BaseProps<string> | 'children'>\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-Select shr-relative shr-inline-block',\n select: [\n 'shr-peer shr-border-shorthand shr-w-full shr-cursor-pointer shr-appearance-none shr-rounded-m shr-bg-white shr-text-base shr-leading-tight shr-text-black',\n 'hover:shr-bg-white-darken',\n 'focus-visible:shr-focus-indicator',\n 'disabled:shr-pointer-events-none disabled:shr-bg-white-darken disabled:shr-text-disabled disabled:shr-opacity-100',\n 'contrast-more:shr-border-high-contrast',\n /* padding に依る積み上げでは文字が見切れてしまうため */\n 'shr-min-h-[calc(theme(fontSize.base)_+_theme(spacing[0.75])_*_2_+_theme(spacing.px)_*_2)]',\n 'shr-border-default disabled:shr-border-disabled',\n 'aria-[invalid]:shr-border-danger',\n ],\n iconWrap: [\n 'shr-pointer-events-none shr-absolute shr-inset-y-0 shr-inline-flex shr-items-center shr-text-grey',\n 'peer-focus-visible:shr-text-black peer-disabled:shr-text-disabled',\n ],\n blankOptgroup: 'shr-hidden',\n },\n variants: {\n size: {\n M: {\n select: 'shr-py-0.5 shr-pe-2 shr-ps-0.5',\n // ((右 padding - アイコン幅) / 2) + 右 border\n iconWrap: 'shr-end-[calc(theme(spacing[0.5])_+_theme(spacing.px))]',\n },\n S: {\n select: [\n 'shr-px-0.5 shr-py-0.25 shr-pe-1.5 shr-text-sm',\n /* padding に依る積み上げでは文字が見切れてしまうため */\n 'shr-min-h-[calc(theme(fontSize.sm)_+_theme(spacing[0.5])_*_2_+_theme(spacing.px)_*_2)]',\n ],\n iconWrap: 'shr-end-0.5 shr-text-sm',\n },\n },\n },\n})\n\nconst ActualSelect = <T extends string>(\n {\n options,\n onChange,\n onChangeValue,\n error,\n width,\n hasBlank,\n blankLabel,\n size,\n className,\n disabled,\n required,\n ...rest\n }: Props<T>,\n ref: ForwardedRef<HTMLSelectElement>,\n) => {\n const classNames = useMemo(() => {\n const { wrapper, select, iconWrap, blankOptgroup } = classNameGenerator()\n const sizeProps = {\n size: size || 'M',\n }\n\n return {\n wrapper: wrapper({ className }),\n select: select(sizeProps),\n iconWrap: iconWrap(sizeProps),\n blankOptGroup: blankOptgroup(),\n }\n }, [className, size])\n const wrapperStyle = useMemo(\n () => ({\n width: typeof width === 'number' ? `${width}px` : width,\n }),\n [width],\n )\n\n const actualBlankLabel = blankLabel ?? ''\n\n return (\n <span className={classNames.wrapper} style={wrapperStyle}>\n <select\n {...rest}\n data-smarthr-ui-input=\"true\"\n onChange={(e: ChangeEvent<HTMLSelectElement>) => {\n onChange?.(e)\n\n if (onChangeValue) {\n const selectedOption = options\n .flatMap((option) => ('value' in option ? [option] : option.options))\n .find((option) => option.value === e.target.value)\n\n if (selectedOption) {\n onChangeValue(selectedOption.value)\n }\n }\n }}\n aria-invalid={error || undefined}\n disabled={disabled}\n // HINT: required属性を設定すると、iOS端末で以下の問題が発生します\n // - フォームのsubmit時にバリデーションは行われるが、ユーザーにフィードバックがない\n // - エラーメッセージが表示されない\n // - 問題のある入力フィールドまでスクロールしない\n // 歴史的に一部の端末ではrequired属性が無視されることがあるため、HTMLのバリデーションのみとすることは少ないです\n // そのため、iOS端末ではrequired属性を設定しない方がユーザーがsubmitできない理由をエラーメッセージなどで正しく理解できるようになります\n required={isIOS ? undefined : required}\n ref={ref}\n className={classNames.select}\n >\n <BlankOption hasBlank={hasBlank}>{actualBlankLabel}</BlankOption>\n {options.map((option, index) => (\n <Option {...option} key={index} />\n ))}\n <NotOmittingLabelsInMobileSafari className={classNames.blankOptGroup} />\n </select>\n <span className={classNames.iconWrap}>\n <FaAngleDownIcon />\n </span>\n </span>\n )\n}\n\nconst BlankOption = memo<\n PropsWithChildren<{\n hasBlank: boolean | undefined\n }>\n>(({ hasBlank, children }) => hasBlank && <option value=\"\">{children}</option>)\n\nconst Option = memo<Props<string>['options'][number]>((option) => {\n if ('value' in option) {\n return <option {...option}>{option.label}</option>\n }\n\n const { options: groupedOptions, label, ...rest } = option\n\n return (\n <optgroup {...rest} key={label} label={label}>\n {groupedOptions.map((groupedOption) => (\n <option {...groupedOption} key={groupedOption.value}>\n {groupedOption.label}\n </option>\n ))}\n </optgroup>\n )\n})\n\n// Support for not omitting labels in Mobile Safari\nconst NotOmittingLabelsInMobileSafari = memo<{ className: string }>(\n ({ className }) => isMobileSafari && <optgroup className={className} />,\n)\n\nexport const Select = genericsForwardRef(ActualSelect)\n"],"names":[],"mappings":";;;;;;;;;;AA8CA;AACE;AACE;AACA;;;;;;;;;;AAUC;AACD;;;AAGC;AACD;AACD;AACD;AACE;AACE;AACE;;AAEA;AACD;AACD;AACE;;;;AAIC;AACD;AACD;AACF;AACF;AACF;AAED;AAiBE;AACE;AACA;;;;AAKE;AACA;AACA;;;AAGJ;AACA;AAEI;AACD;AAIH;;AAQQ;;;;AAKK;;AAGD;;;AAGN;;;;;;;AASA;AAeR;AAEA;AAMA;AACE;AACE;;AAGF;AAEA;AASF;AAEA;AACA;;;"}
1
+ {"version":3,"file":"Select.js","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n type ForwardedRef,\n type OptgroupHTMLAttributes,\n type OptionHTMLAttributes,\n type PropsWithChildren,\n memo,\n useMemo,\n} from 'react'\nimport { tv } from 'tailwind-variants'\n\nimport { isIOS, isMobileSafari } from '../../libs/ua'\nimport { genericsForwardRef } from '../../libs/util'\nimport { FaAngleDownIcon } from '../Icon'\n\ntype Option<T extends string> = {\n value: T\n} & Omit<OptionHTMLAttributes<HTMLOptionElement>, 'value'>\ntype Optgroup<T extends string> = {\n label: string\n options: Array<Option<T>>\n} & OptgroupHTMLAttributes<HTMLOptGroupElement>\n\ntype BaseProps<T extends string> = {\n /** 選択肢のデータの配列 */\n options: Array<Option<T> | Optgroup<T>>\n /** フォームの値が変わったときに発火するコールバック関数 */\n onChangeValue?: (value: T) => void\n /** フォームの値にエラーがあるかどうか */\n error?: boolean\n /** コンポーネントの幅 */\n width?: number | string\n /** コンポーネントの大きさ */\n size?: 'M' | 'S'\n /** 空の選択肢を表示するかどうか */\n hasBlank?: boolean\n /** 空の選択肢のラベル */\n blankLabel?: string\n}\n\ntype Props<T extends string> = BaseProps<T> &\n Omit<ComponentPropsWithoutRef<'select'>, keyof BaseProps<string> | 'children'>\n\nconst classNameGenerator = tv({\n slots: {\n wrapper: 'smarthr-ui-Select shr-relative shr-inline-block',\n select: [\n 'shr-peer shr-border-shorthand shr-w-full shr-cursor-pointer shr-appearance-none shr-rounded-m shr-bg-white shr-text-base shr-leading-tight shr-text-black',\n 'hover:shr-bg-white-darken',\n 'focus-visible:shr-focus-indicator',\n 'disabled:shr-pointer-events-none disabled:shr-bg-white-darken disabled:shr-text-disabled disabled:shr-opacity-100',\n 'contrast-more:shr-border-high-contrast',\n /* padding に依る積み上げでは文字が見切れてしまうため */\n 'shr-min-h-[calc(theme(fontSize.base)_+_theme(spacing[0.75])_*_2_+_theme(spacing.px)_*_2)]',\n 'shr-border-default disabled:shr-border-disabled',\n 'aria-[invalid]:shr-border-danger',\n ],\n iconWrap: [\n 'shr-pointer-events-none shr-absolute shr-inset-y-0 shr-inline-flex shr-items-center shr-text-grey',\n 'peer-focus-visible:shr-text-black peer-disabled:shr-text-disabled',\n ],\n blankOptgroup: 'shr-hidden',\n },\n variants: {\n size: {\n M: {\n select: 'shr-py-0.5 shr-pe-2 shr-ps-0.5',\n // ((右 padding - アイコン幅) / 2) + 右 border\n iconWrap: 'shr-end-[calc(theme(spacing[0.5])_+_theme(spacing.px))]',\n },\n S: {\n select: [\n 'shr-px-0.5 shr-py-0.25 shr-pe-1.5 shr-text-sm',\n /* padding に依る積み上げでは文字が見切れてしまうため */\n 'shr-min-h-[calc(theme(fontSize.sm)_+_theme(spacing[0.5])_*_2_+_theme(spacing.px)_*_2)]',\n ],\n iconWrap: 'shr-end-0.5 shr-text-sm',\n },\n },\n },\n})\n\nconst ActualSelect = <T extends string>(\n {\n options,\n onChange,\n onChangeValue,\n error,\n width,\n hasBlank,\n blankLabel,\n size,\n className,\n disabled,\n required,\n ...rest\n }: Props<T>,\n ref: ForwardedRef<HTMLSelectElement>,\n) => {\n const classNames = useMemo(() => {\n const { wrapper, select, iconWrap, blankOptgroup } = classNameGenerator()\n const sizeProps = {\n size: size || 'M',\n }\n\n return {\n wrapper: wrapper({ className }),\n select: select(sizeProps),\n iconWrap: iconWrap(sizeProps),\n blankOptGroup: blankOptgroup(),\n }\n }, [size, className])\n\n return (\n <span\n className={classNames.wrapper}\n style={{\n width: typeof width === 'number' ? `${width}px` : width,\n }}\n >\n <select\n {...rest}\n ref={ref}\n disabled={disabled}\n // HINT: required属性を設定すると、iOS端末で以下の問題が発生します\n // - フォームのsubmit時にバリデーションは行われるが、ユーザーにフィードバックがない\n // - エラーメッセージが表示されない\n // - 問題のある入力フィールドまでスクロールしない\n // 歴史的に一部の端末ではrequired属性が無視されることがあるため、HTMLのバリデーションのみとすることは少ないです\n // そのため、iOS端末ではrequired属性を設定しない方がユーザーがsubmitできない理由をエラーメッセージなどで正しく理解できるようになります\n required={isIOS ? undefined : required}\n aria-invalid={error || undefined}\n data-smarthr-ui-input=\"true\"\n onChange={(e: ChangeEvent<HTMLSelectElement>) => {\n onChange?.(e)\n\n if (onChangeValue) {\n const selectedOption = options\n .flatMap((option) => ('value' in option ? [option] : option.options))\n .find((option) => option.value === e.target.value)\n\n if (selectedOption) {\n onChangeValue(selectedOption.value)\n }\n }\n }}\n className={classNames.select}\n >\n <BlankOption hasBlank={hasBlank}>{blankLabel ?? ''}</BlankOption>\n {options.map((option, index) => (\n <Option {...option} key={index} />\n ))}\n <NotOmittingLabelsInMobileSafari className={classNames.blankOptGroup} />\n </select>\n <span className={classNames.iconWrap}>\n <FaAngleDownIcon />\n </span>\n </span>\n )\n}\n\nconst BlankOption = memo<\n PropsWithChildren<{\n hasBlank: boolean | undefined\n }>\n>(({ hasBlank, children }) => hasBlank && <option value=\"\">{children}</option>)\n\nconst Option = memo<Props<string>['options'][number]>((option) => {\n if ('value' in option) {\n return <option {...option}>{option.label}</option>\n }\n\n const { options: groupedOptions, label, ...rest } = option\n\n return (\n <optgroup {...rest} key={label} label={label}>\n {groupedOptions.map((groupedOption) => (\n <option {...groupedOption} key={groupedOption.value}>\n {groupedOption.label}\n </option>\n ))}\n </optgroup>\n )\n})\n\n// Support for not omitting labels in Mobile Safari\nconst NotOmittingLabelsInMobileSafari = memo<{ className: string }>(\n ({ className }) => isMobileSafari && <optgroup className={className} />,\n)\n\nexport const Select = genericsForwardRef(ActualSelect)\n"],"names":[],"mappings":";;;;;;;;;;AA8CA;AACE;AACE;AACA;;;;;;;;;;AAUC;AACD;;;AAGC;AACD;AACD;AACD;AACE;AACE;AACE;;AAEA;AACD;AACD;AACE;;;;AAIC;AACD;AACD;AACF;AACF;AACF;AAED;AAiBE;AACE;AACA;;;;AAKE;AACA;AACA;;;AAGJ;;AAMM;;;;;;;;;AAiBE;;;;AAKK;;AAGD;;;AAGN;AAcR;AAEA;AAMA;AACE;AACE;;AAGF;AAEA;AASF;AAEA;AACA;;;"}
@@ -21,13 +21,21 @@ const SCROLLER_PROPS = {
21
21
  // fixedHead のとき、スクロールインスタンスがTableからWrapperに変わるため、Wrapperに対して高さとoverflowを指定する
22
22
  className: 'shr-h-[inherit] shr-max-h-[inherit] shr-scroll-pb-0.5',
23
23
  };
24
- const TableScroller = React.forwardRef(({ children, fixedHead, ...rest }, forwardedRef) => fixedHead ? (jsxRuntime.jsx(FixedHeadTableScroller, { ...rest, ...SCROLLER_PROPS, forwardedRef: forwardedRef, children: children })) : (jsxRuntime.jsx(components_Scroller_Scroller.Scroller, { ...rest, ...SCROLLER_PROPS, ref: forwardedRef, children: children })));
24
+ const TableScroller = React.forwardRef(({ children, fixedHead, ...rest }, ref) => fixedHead ? (jsxRuntime.jsx(FixedHeadTableScroller, { ...rest, ...SCROLLER_PROPS, forwardedRef: ref, children: children })) : (jsxRuntime.jsx(components_Scroller_Scroller.Scroller, { ...rest, ...SCROLLER_PROPS, ref: ref, children: children })));
25
25
  const FixedHeadTableScroller = ({ children, forwardedRef, direction, ...rest }) => {
26
- const innerRef = React.useRef(null);
27
- const setRefs = React.useCallback((node) => {
28
- innerRef.current = node;
26
+ // TODO: useMergeRefsが作成されたら修正する
27
+ const callbackRef = React.useCallback((node) => {
28
+ // thead の高さ分だけ scroll-padding-top を設定
29
+ if (node) {
30
+ const thead = node.querySelector('thead');
31
+ if (thead) {
32
+ const { height } = thead.getBoundingClientRect();
33
+ node.style.scrollPaddingTop = `${height + themes_createFontSize.defaultHtmlFontSize}px`;
34
+ }
35
+ }
29
36
  if (forwardedRef) {
30
37
  if (typeof forwardedRef === 'function') {
38
+ // React 19 では callback ref の戻り値を cleanup として使うため、返却する
31
39
  forwardedRef(node);
32
40
  }
33
41
  else {
@@ -35,17 +43,7 @@ const FixedHeadTableScroller = ({ children, forwardedRef, direction, ...rest })
35
43
  }
36
44
  }
37
45
  }, [forwardedRef]);
38
- // thead の高さ分だけ scroll-padding-top を設定
39
- React.useLayoutEffect(() => {
40
- if (!innerRef.current)
41
- return;
42
- const thead = innerRef.current.querySelector('thead');
43
- if (thead) {
44
- const { height } = thead.getBoundingClientRect();
45
- innerRef.current.style.scrollPaddingTop = `${height + themes_createFontSize.defaultHtmlFontSize}px`;
46
- }
47
- }, []);
48
- return (jsxRuntime.jsx(components_Scroller_Scroller.Scroller, { ...rest, ref: setRefs, direction: direction, children: children }));
46
+ return (jsxRuntime.jsx(components_Scroller_Scroller.Scroller, { ...rest, ref: callbackRef, direction: direction, children: children }));
49
47
  };
50
48
 
51
49
  exports.TableScroller = TableScroller;
@@ -1 +1 @@
1
- {"version":3,"file":"TableScroller.cjs","sources":["../../../src/components/Table/TableScroller.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ComponentPropsWithRef,\n type ForwardedRef,\n type PropsWithChildren,\n forwardRef,\n useCallback,\n useLayoutEffect,\n useRef,\n} from 'react'\n\nimport { defaultHtmlFontSize } from '../../themes'\nimport { Scroller } from '../Scroller'\n\ntype Props = PropsWithChildren &\n Omit<ComponentPropsWithRef<'div'>, keyof PropsWithChildren> & {\n fixedHead?: boolean\n }\n\nconst SCROLLER_PROPS = {\n direction: 'both' as const,\n // fixedHead のとき、スクロールインスタンスがTableからWrapperに変わるため、Wrapperに対して高さとoverflowを指定する\n className: 'shr-h-[inherit] shr-max-h-[inherit] shr-scroll-pb-0.5',\n}\n\nexport const TableScroller = forwardRef<HTMLDivElement, Props>(\n ({ children, fixedHead, ...rest }, forwardedRef: ForwardedRef<HTMLDivElement>) =>\n fixedHead ? (\n <FixedHeadTableScroller {...rest} {...SCROLLER_PROPS} forwardedRef={forwardedRef}>\n {children}\n </FixedHeadTableScroller>\n ) : (\n <Scroller {...rest} {...SCROLLER_PROPS} ref={forwardedRef}>\n {children}\n </Scroller>\n ),\n)\n\ntype FixedHeadTableScrollerProps = PropsWithChildren &\n Omit<ComponentPropsWithRef<'div'>, keyof PropsWithChildren> & {\n forwardedRef: ForwardedRef<HTMLDivElement>\n direction: 'both'\n }\n\nconst FixedHeadTableScroller = ({\n children,\n forwardedRef,\n direction,\n ...rest\n}: FixedHeadTableScrollerProps) => {\n const innerRef = useRef<HTMLDivElement | null>(null)\n\n const setRefs = useCallback(\n (node: HTMLDivElement) => {\n innerRef.current = node\n if (forwardedRef) {\n if (typeof forwardedRef === 'function') {\n forwardedRef(node)\n } else {\n forwardedRef.current = node\n }\n }\n },\n [forwardedRef],\n )\n\n // thead の高さ分だけ scroll-padding-top を設定\n useLayoutEffect(() => {\n if (!innerRef.current) return\n const thead = innerRef.current.querySelector('thead')\n if (thead) {\n const { height } = thead.getBoundingClientRect()\n innerRef.current.style.scrollPaddingTop = `${height + defaultHtmlFontSize}px`\n }\n }, [])\n\n return (\n <Scroller {...rest} ref={setRefs} direction={direction}>\n {children}\n </Scroller>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAoBA;AACE;;AAEA;;AAGK;AAmBP;AAME;AAEA;AAEI;;AAEE;;;;AAGE;;;AAGN;;;;;;;;AAUE;;;AAIJ;AAKF;;"}
1
+ {"version":3,"file":"TableScroller.cjs","sources":["../../../src/components/Table/TableScroller.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ComponentPropsWithRef,\n type ForwardedRef,\n type PropsWithChildren,\n forwardRef,\n useCallback,\n} from 'react'\n\nimport { defaultHtmlFontSize } from '../../themes'\nimport { Scroller } from '../Scroller'\n\ntype Props = PropsWithChildren &\n Omit<ComponentPropsWithRef<'div'>, keyof PropsWithChildren> & {\n fixedHead?: boolean\n }\n\nconst SCROLLER_PROPS = {\n direction: 'both' as const,\n // fixedHead のとき、スクロールインスタンスがTableからWrapperに変わるため、Wrapperに対して高さとoverflowを指定する\n className: 'shr-h-[inherit] shr-max-h-[inherit] shr-scroll-pb-0.5',\n}\n\nexport const TableScroller = forwardRef<HTMLDivElement, Props>(\n ({ children, fixedHead, ...rest }, ref: ForwardedRef<HTMLDivElement>) =>\n fixedHead ? (\n <FixedHeadTableScroller {...rest} {...SCROLLER_PROPS} forwardedRef={ref}>\n {children}\n </FixedHeadTableScroller>\n ) : (\n <Scroller {...rest} {...SCROLLER_PROPS} ref={ref}>\n {children}\n </Scroller>\n ),\n)\n\ntype FixedHeadTableScrollerProps = PropsWithChildren &\n Omit<ComponentPropsWithRef<'div'>, keyof PropsWithChildren> & {\n forwardedRef: ForwardedRef<HTMLDivElement>\n direction: 'both'\n }\n\nconst FixedHeadTableScroller = ({\n children,\n forwardedRef,\n direction,\n ...rest\n}: FixedHeadTableScrollerProps) => {\n // TODO: useMergeRefsが作成されたら修正する\n const callbackRef = useCallback(\n (node: HTMLDivElement | null) => {\n // thead の高さ分だけ scroll-padding-top を設定\n if (node) {\n const thead = node.querySelector('thead')\n\n if (thead) {\n const { height } = thead.getBoundingClientRect()\n\n node.style.scrollPaddingTop = `${height + defaultHtmlFontSize}px`\n }\n }\n\n if (forwardedRef) {\n if (typeof forwardedRef === 'function') {\n // React 19 では callback ref の戻り値を cleanup として使うため、返却する\n forwardedRef(node)\n } else {\n forwardedRef.current = node\n }\n }\n },\n [forwardedRef],\n )\n\n return (\n <Scroller {...rest} ref={callbackRef} direction={direction}>\n {children}\n </Scroller>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAkBA;AACE;;AAEA;;AAGK;AAmBP;;AAOE;;;;;;;;;;AAcM;;;;;AAIE;;;AAGN;AAIF;AAKF;;"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx } from 'react/jsx-runtime';
3
- import { forwardRef, useRef, useCallback, useLayoutEffect } from 'react';
3
+ import { forwardRef, useCallback } from 'react';
4
4
  import '../../themes/createSpacing.js';
5
5
  import { defaultHtmlFontSize } from '../../themes/createFontSize.js';
6
6
  import '../../themes/createColor.js';
@@ -19,13 +19,21 @@ const SCROLLER_PROPS = {
19
19
  // fixedHead のとき、スクロールインスタンスがTableからWrapperに変わるため、Wrapperに対して高さとoverflowを指定する
20
20
  className: 'shr-h-[inherit] shr-max-h-[inherit] shr-scroll-pb-0.5',
21
21
  };
22
- const TableScroller = forwardRef(({ children, fixedHead, ...rest }, forwardedRef) => fixedHead ? (jsx(FixedHeadTableScroller, { ...rest, ...SCROLLER_PROPS, forwardedRef: forwardedRef, children: children })) : (jsx(Scroller, { ...rest, ...SCROLLER_PROPS, ref: forwardedRef, children: children })));
22
+ const TableScroller = forwardRef(({ children, fixedHead, ...rest }, ref) => fixedHead ? (jsx(FixedHeadTableScroller, { ...rest, ...SCROLLER_PROPS, forwardedRef: ref, children: children })) : (jsx(Scroller, { ...rest, ...SCROLLER_PROPS, ref: ref, children: children })));
23
23
  const FixedHeadTableScroller = ({ children, forwardedRef, direction, ...rest }) => {
24
- const innerRef = useRef(null);
25
- const setRefs = useCallback((node) => {
26
- innerRef.current = node;
24
+ // TODO: useMergeRefsが作成されたら修正する
25
+ const callbackRef = useCallback((node) => {
26
+ // thead の高さ分だけ scroll-padding-top を設定
27
+ if (node) {
28
+ const thead = node.querySelector('thead');
29
+ if (thead) {
30
+ const { height } = thead.getBoundingClientRect();
31
+ node.style.scrollPaddingTop = `${height + defaultHtmlFontSize}px`;
32
+ }
33
+ }
27
34
  if (forwardedRef) {
28
35
  if (typeof forwardedRef === 'function') {
36
+ // React 19 では callback ref の戻り値を cleanup として使うため、返却する
29
37
  forwardedRef(node);
30
38
  }
31
39
  else {
@@ -33,17 +41,7 @@ const FixedHeadTableScroller = ({ children, forwardedRef, direction, ...rest })
33
41
  }
34
42
  }
35
43
  }, [forwardedRef]);
36
- // thead の高さ分だけ scroll-padding-top を設定
37
- useLayoutEffect(() => {
38
- if (!innerRef.current)
39
- return;
40
- const thead = innerRef.current.querySelector('thead');
41
- if (thead) {
42
- const { height } = thead.getBoundingClientRect();
43
- innerRef.current.style.scrollPaddingTop = `${height + defaultHtmlFontSize}px`;
44
- }
45
- }, []);
46
- return (jsx(Scroller, { ...rest, ref: setRefs, direction: direction, children: children }));
44
+ return (jsx(Scroller, { ...rest, ref: callbackRef, direction: direction, children: children }));
47
45
  };
48
46
 
49
47
  export { TableScroller };
@@ -1 +1 @@
1
- {"version":3,"file":"TableScroller.js","sources":["../../../src/components/Table/TableScroller.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ComponentPropsWithRef,\n type ForwardedRef,\n type PropsWithChildren,\n forwardRef,\n useCallback,\n useLayoutEffect,\n useRef,\n} from 'react'\n\nimport { defaultHtmlFontSize } from '../../themes'\nimport { Scroller } from '../Scroller'\n\ntype Props = PropsWithChildren &\n Omit<ComponentPropsWithRef<'div'>, keyof PropsWithChildren> & {\n fixedHead?: boolean\n }\n\nconst SCROLLER_PROPS = {\n direction: 'both' as const,\n // fixedHead のとき、スクロールインスタンスがTableからWrapperに変わるため、Wrapperに対して高さとoverflowを指定する\n className: 'shr-h-[inherit] shr-max-h-[inherit] shr-scroll-pb-0.5',\n}\n\nexport const TableScroller = forwardRef<HTMLDivElement, Props>(\n ({ children, fixedHead, ...rest }, forwardedRef: ForwardedRef<HTMLDivElement>) =>\n fixedHead ? (\n <FixedHeadTableScroller {...rest} {...SCROLLER_PROPS} forwardedRef={forwardedRef}>\n {children}\n </FixedHeadTableScroller>\n ) : (\n <Scroller {...rest} {...SCROLLER_PROPS} ref={forwardedRef}>\n {children}\n </Scroller>\n ),\n)\n\ntype FixedHeadTableScrollerProps = PropsWithChildren &\n Omit<ComponentPropsWithRef<'div'>, keyof PropsWithChildren> & {\n forwardedRef: ForwardedRef<HTMLDivElement>\n direction: 'both'\n }\n\nconst FixedHeadTableScroller = ({\n children,\n forwardedRef,\n direction,\n ...rest\n}: FixedHeadTableScrollerProps) => {\n const innerRef = useRef<HTMLDivElement | null>(null)\n\n const setRefs = useCallback(\n (node: HTMLDivElement) => {\n innerRef.current = node\n if (forwardedRef) {\n if (typeof forwardedRef === 'function') {\n forwardedRef(node)\n } else {\n forwardedRef.current = node\n }\n }\n },\n [forwardedRef],\n )\n\n // thead の高さ分だけ scroll-padding-top を設定\n useLayoutEffect(() => {\n if (!innerRef.current) return\n const thead = innerRef.current.querySelector('thead')\n if (thead) {\n const { height } = thead.getBoundingClientRect()\n innerRef.current.style.scrollPaddingTop = `${height + defaultHtmlFontSize}px`\n }\n }, [])\n\n return (\n <Scroller {...rest} ref={setRefs} direction={direction}>\n {children}\n </Scroller>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAoBA;AACE;;AAEA;;AAGK;AAmBP;AAME;AAEA;AAEI;;AAEE;;;;AAGE;;;AAGN;;;;;;;;AAUE;;;AAIJ;AAKF;;"}
1
+ {"version":3,"file":"TableScroller.js","sources":["../../../src/components/Table/TableScroller.tsx"],"sourcesContent":["'use client'\n\nimport {\n type ComponentPropsWithRef,\n type ForwardedRef,\n type PropsWithChildren,\n forwardRef,\n useCallback,\n} from 'react'\n\nimport { defaultHtmlFontSize } from '../../themes'\nimport { Scroller } from '../Scroller'\n\ntype Props = PropsWithChildren &\n Omit<ComponentPropsWithRef<'div'>, keyof PropsWithChildren> & {\n fixedHead?: boolean\n }\n\nconst SCROLLER_PROPS = {\n direction: 'both' as const,\n // fixedHead のとき、スクロールインスタンスがTableからWrapperに変わるため、Wrapperに対して高さとoverflowを指定する\n className: 'shr-h-[inherit] shr-max-h-[inherit] shr-scroll-pb-0.5',\n}\n\nexport const TableScroller = forwardRef<HTMLDivElement, Props>(\n ({ children, fixedHead, ...rest }, ref: ForwardedRef<HTMLDivElement>) =>\n fixedHead ? (\n <FixedHeadTableScroller {...rest} {...SCROLLER_PROPS} forwardedRef={ref}>\n {children}\n </FixedHeadTableScroller>\n ) : (\n <Scroller {...rest} {...SCROLLER_PROPS} ref={ref}>\n {children}\n </Scroller>\n ),\n)\n\ntype FixedHeadTableScrollerProps = PropsWithChildren &\n Omit<ComponentPropsWithRef<'div'>, keyof PropsWithChildren> & {\n forwardedRef: ForwardedRef<HTMLDivElement>\n direction: 'both'\n }\n\nconst FixedHeadTableScroller = ({\n children,\n forwardedRef,\n direction,\n ...rest\n}: FixedHeadTableScrollerProps) => {\n // TODO: useMergeRefsが作成されたら修正する\n const callbackRef = useCallback(\n (node: HTMLDivElement | null) => {\n // thead の高さ分だけ scroll-padding-top を設定\n if (node) {\n const thead = node.querySelector('thead')\n\n if (thead) {\n const { height } = thead.getBoundingClientRect()\n\n node.style.scrollPaddingTop = `${height + defaultHtmlFontSize}px`\n }\n }\n\n if (forwardedRef) {\n if (typeof forwardedRef === 'function') {\n // React 19 では callback ref の戻り値を cleanup として使うため、返却する\n forwardedRef(node)\n } else {\n forwardedRef.current = node\n }\n }\n },\n [forwardedRef],\n )\n\n return (\n <Scroller {...rest} ref={callbackRef} direction={direction}>\n {children}\n </Scroller>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAkBA;AACE;;AAEA;;AAGK;AAmBP;;AAOE;;;;;;;;;;AAcM;;;;;AAIE;;;AAGN;AAIF;AAKF;;"}
@@ -46,12 +46,12 @@ const classNameGenerator = index.tv({
46
46
  'aria-[invalid]:shr-border-danger',
47
47
  ],
48
48
  });
49
- const calculateIdealRows = (element, maxRows, lineHeightNormal) => {
50
- if (!element) {
49
+ const calculateIdealRows = (node, maxRows, lineHeightNormal) => {
50
+ if (!node) {
51
51
  return 0;
52
52
  }
53
53
  // 現在の入力値に応じた行数
54
- const currentInputValueRows = Math.floor(element.scrollHeight / (themes_createFontSize.defaultHtmlFontSize * lineHeightNormal));
54
+ const currentInputValueRows = Math.floor(node.scrollHeight / (themes_createFontSize.defaultHtmlFontSize * lineHeightNormal));
55
55
  return currentInputValueRows < maxRows ? currentInputValueRows : maxRows;
56
56
  };
57
57
  const Textarea = React.forwardRef(({ maxLetters, ...rest }, ref) => maxLetters ? (jsxRuntime.jsx(MaxLettersTextarea, { ...rest, externalRef: ref, maxLetters: maxLetters })) : (jsxRuntime.jsx(ActualTextarea, { ...rest, externalRef: ref })));
@@ -98,6 +98,10 @@ const MaxLettersTextarea = ({ maxLetters, error, value, defaultValue, onChange,
98
98
  };
99
99
  return {
100
100
  updateCount,
101
+ cancelDebounce: () => {
102
+ updateSrMessage.cancel();
103
+ actualUpdateCount.cancel();
104
+ },
101
105
  handleChange: (e) => {
102
106
  updateCount(e.target.value);
103
107
  latest.onChange?.(e);
@@ -106,12 +110,13 @@ const MaxLettersTextarea = ({ maxLetters, error, value, defaultValue, onChange,
106
110
  }, [latest]);
107
111
  React.useEffect(() => {
108
112
  functions.updateCount(value ?? '');
113
+ return functions.cancelDebounce;
109
114
  }, [value, functions]);
110
- return (jsxRuntime.jsxs("span", { className: "shr-relative", children: [jsxRuntime.jsx(ActualTextarea, { ...rest, id: textareaId, value: value, defaultValue: defaultValue, onChange: functions.handleChange, "aria-describedby": `${maxLettersNoticeId} ${maxLettersId}`, error: error || countError }), jsxRuntime.jsx(components_VisuallyHiddenText_VisuallyHiddenText.VisuallyHiddenText, { id: maxLettersNoticeId, children: jsxRuntime.jsx(intl_Localizer.Localizer, { id: "smarthr-ui/Textarea/screenReaderMaxLettersDescription", defaultText: "\u6700\u5927{maxLetters}\u6587\u5B57\u5165\u529B\u3067\u304D\u307E\u3059", values: { maxLetters } }) }), jsxRuntime.jsx(components_VisuallyHiddenText_VisuallyHiddenText.VisuallyHiddenText, { as: "output", role: "status", htmlFor: textareaId, children: srCounterMessage }), jsxRuntime.jsx("span", { ref: counterSpanRef, id: maxLettersId, "aria-hidden": true, "data-error": countError || undefined, className: "smarthr-ui-Textarea-counter shr-block shr-text-sm shr-text-black data-[error]:shr-text-danger", children: count > maxLetters ? (jsxRuntime.jsx(intl_Localizer.Localizer, { id: "smarthr-ui/Textarea/maxLettersExceeded", defaultText: "{exceededLetters}\u6587\u5B57\u30AA\u30FC\u30D0\u30FC", values: { exceededLetters: count - maxLetters } })) : (jsxRuntime.jsx(intl_Localizer.Localizer, { id: "smarthr-ui/Textarea/availableLetters", defaultText: "\u3042\u3068{availableLetters}\u6587\u5B57", values: { availableLetters: maxLetters - count } })) })] }));
115
+ return (jsxRuntime.jsxs("span", { className: "shr-relative", children: [jsxRuntime.jsx(ActualTextarea, { ...rest, id: textareaId, value: value, defaultValue: defaultValue, "aria-describedby": `${maxLettersNoticeId} ${maxLettersId}`, error: error || countError, onChange: functions.handleChange }), jsxRuntime.jsx(components_VisuallyHiddenText_VisuallyHiddenText.VisuallyHiddenText, { id: maxLettersNoticeId, children: jsxRuntime.jsx(intl_Localizer.Localizer, { id: "smarthr-ui/Textarea/screenReaderMaxLettersDescription", defaultText: "\u6700\u5927{maxLetters}\u6587\u5B57\u5165\u529B\u3067\u304D\u307E\u3059", values: { maxLetters } }) }), jsxRuntime.jsx(components_VisuallyHiddenText_VisuallyHiddenText.VisuallyHiddenText, { as: "output", role: "status", htmlFor: textareaId, children: srCounterMessage }), jsxRuntime.jsx("span", { ref: counterSpanRef, id: maxLettersId, "aria-hidden": true, "data-error": countError || undefined, className: "smarthr-ui-Textarea-counter shr-block shr-text-sm shr-text-black data-[error]:shr-text-danger", children: count > maxLetters ? (jsxRuntime.jsx(intl_Localizer.Localizer, { id: "smarthr-ui/Textarea/maxLettersExceeded", defaultText: "{exceededLetters}\u6587\u5B57\u30AA\u30FC\u30D0\u30FC", values: { exceededLetters: count - maxLetters } })) : (jsxRuntime.jsx(intl_Localizer.Localizer, { id: "smarthr-ui/Textarea/availableLetters", defaultText: "\u3042\u3068{availableLetters}\u6587\u5B57", values: { availableLetters: maxLetters - count } })) })] }));
111
116
  };
112
117
  const ActualTextarea = ({ autoFocus, width, className, autoResize = false, maxRows = Infinity, rows = 2, error, onChange, externalRef, ...rest }) => {
113
118
  const theme = hooks_useTheme.useTheme();
114
- const textareaRef = React.useRef(null);
119
+ const innerRef = React.useRef(null);
115
120
  const [interimRows, setInterimRows] = React.useState(rows);
116
121
  const actualClassName = React.useMemo(() => classNameGenerator({ className }), [className]);
117
122
  const latest = hooks_useLatest.useLatest({
@@ -123,16 +128,17 @@ const ActualTextarea = ({ autoFocus, width, className, autoResize = false, maxRo
123
128
  rows,
124
129
  });
125
130
  const functions = React.useMemo(() => ({
126
- callbackRef: (element) => {
127
- textareaRef.current = element;
128
- if (element) {
131
+ callbackRef: (node) => {
132
+ // TODO: useMergeRefs, useOnceCallbackが実装されたら適用する
133
+ innerRef.current = node;
134
+ if (node) {
129
135
  // autoFocus時に、フォーカスを当てる
130
136
  if (latest.autoFocus) {
131
- element.focus();
137
+ node.focus();
132
138
  }
133
139
  // autoResize時に、初期値での高さを指定
134
140
  if (latest.autoResize) {
135
- setInterimRows(calculateIdealRows(element, latest.maxRows, latest.theme.leading.NORMAL));
141
+ setInterimRows(calculateIdealRows(node, latest.maxRows, latest.theme.leading.NORMAL));
136
142
  }
137
143
  }
138
144
  },
@@ -148,8 +154,8 @@ const ActualTextarea = ({ autoFocus, width, className, autoResize = false, maxRo
148
154
  latest.onChange?.(e);
149
155
  },
150
156
  }), [latest]);
151
- React.useImperativeHandle(externalRef, () => textareaRef.current, []);
152
- return (jsxRuntime.jsx("textarea", { ...rest, "data-smarthr-ui-input": "true", onChange: functions.handleChange, ref: functions.callbackRef, "aria-invalid": error || undefined, rows: interimRows, className: actualClassName, style: { width: typeof width === 'number' ? `${width}px` : width } }));
157
+ React.useImperativeHandle(externalRef, () => innerRef.current, []);
158
+ return (jsxRuntime.jsx("textarea", { ...rest, ref: functions.callbackRef, "aria-invalid": error || undefined, "data-smarthr-ui-input": "true", rows: interimRows, onChange: functions.handleChange, className: actualClassName, style: { width: typeof width === 'number' ? `${width}px` : width } }));
153
159
  };
154
160
 
155
161
  exports.Textarea = Textarea;