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.
- package/lib/_virtual/index.cjs +2 -2
- package/lib/_virtual/index.js +2 -2
- package/lib/_virtual/index2.cjs +2 -2
- package/lib/_virtual/index2.js +2 -2
- package/lib/components/Combobox/ItemButton.cjs +11 -2
- package/lib/components/Combobox/ItemButton.cjs.map +1 -1
- package/lib/components/Combobox/ItemButton.js +11 -2
- package/lib/components/Combobox/ItemButton.js.map +1 -1
- package/lib/components/Combobox/MultiCombobox/MultiCombobox.cjs +1 -1
- package/lib/components/Combobox/MultiCombobox/MultiCombobox.cjs.map +1 -1
- package/lib/components/Combobox/MultiCombobox/MultiCombobox.js +1 -1
- package/lib/components/Combobox/MultiCombobox/MultiCombobox.js.map +1 -1
- package/lib/components/Combobox/SingleCombobox/SingleCombobox.cjs +1 -1
- package/lib/components/Combobox/SingleCombobox/SingleCombobox.cjs.map +1 -1
- package/lib/components/Combobox/SingleCombobox/SingleCombobox.js +1 -1
- package/lib/components/Combobox/SingleCombobox/SingleCombobox.js.map +1 -1
- package/lib/components/DatePicker/DatePicker.cjs +1 -1
- package/lib/components/DatePicker/DatePicker.cjs.map +1 -1
- package/lib/components/DatePicker/DatePicker.js +1 -1
- package/lib/components/DatePicker/DatePicker.js.map +1 -1
- package/lib/components/Dialog/FocusTrap.cjs +8 -8
- package/lib/components/Dialog/FocusTrap.cjs.map +1 -1
- package/lib/components/Dialog/FocusTrap.js +9 -9
- package/lib/components/Dialog/FocusTrap.js.map +1 -1
- package/lib/components/Dialog/ModelessDialog/ModelessDialog.cjs +2 -1
- package/lib/components/Dialog/ModelessDialog/ModelessDialog.cjs.map +1 -1
- package/lib/components/Dialog/ModelessDialog/ModelessDialog.js +2 -1
- package/lib/components/Dialog/ModelessDialog/ModelessDialog.js.map +1 -1
- package/lib/components/Input/CurrencyInput/CurrencyInput.cjs +2 -2
- package/lib/components/Input/CurrencyInput/CurrencyInput.cjs.map +1 -1
- package/lib/components/Input/CurrencyInput/CurrencyInput.js +2 -2
- package/lib/components/Input/CurrencyInput/CurrencyInput.js.map +1 -1
- package/lib/components/Input/Input.cjs +14 -16
- package/lib/components/Input/Input.cjs.map +1 -1
- package/lib/components/Input/Input.js +14 -16
- package/lib/components/Input/Input.js.map +1 -1
- package/lib/components/InputFile/InputFileMultiplyAppendable.cjs +8 -7
- package/lib/components/InputFile/InputFileMultiplyAppendable.cjs.map +1 -1
- package/lib/components/InputFile/InputFileMultiplyAppendable.js +8 -7
- package/lib/components/InputFile/InputFileMultiplyAppendable.js.map +1 -1
- package/lib/components/InputFile/InputFileNative.cjs +6 -5
- package/lib/components/InputFile/InputFileNative.cjs.map +1 -1
- package/lib/components/InputFile/InputFileNative.js +6 -5
- package/lib/components/InputFile/InputFileNative.js.map +1 -1
- package/lib/components/Layout/Container/Container.cjs.map +1 -1
- package/lib/components/Layout/Container/Container.js.map +1 -1
- package/lib/components/Pagination/Pagination.cjs +3 -2
- package/lib/components/Pagination/Pagination.cjs.map +1 -1
- package/lib/components/Pagination/Pagination.js +2 -1
- package/lib/components/Pagination/Pagination.js.map +1 -1
- package/lib/components/Panel/Groupbox/Groupbox.cjs +1 -0
- package/lib/components/Panel/Groupbox/Groupbox.cjs.map +1 -1
- package/lib/components/Panel/Groupbox/Groupbox.js +1 -0
- package/lib/components/Panel/Groupbox/Groupbox.js.map +1 -1
- package/lib/components/Select/Select.cjs +12 -14
- package/lib/components/Select/Select.cjs.map +1 -1
- package/lib/components/Select/Select.js +12 -14
- package/lib/components/Select/Select.js.map +1 -1
- package/lib/components/Table/TableScroller.cjs +13 -15
- package/lib/components/Table/TableScroller.cjs.map +1 -1
- package/lib/components/Table/TableScroller.js +14 -16
- package/lib/components/Table/TableScroller.js.map +1 -1
- package/lib/components/Textarea/Textarea.cjs +18 -12
- package/lib/components/Textarea/Textarea.cjs.map +1 -1
- package/lib/components/Textarea/Textarea.js +19 -13
- package/lib/components/Textarea/Textarea.js.map +1 -1
- package/lib/components/Tooltip/TooltipPortal.cjs +1 -0
- package/lib/components/Tooltip/TooltipPortal.cjs.map +1 -1
- package/lib/components/Tooltip/TooltipPortal.js +1 -0
- package/lib/components/Tooltip/TooltipPortal.js.map +1 -1
- package/lib/hooks/useClick.cjs +7 -4
- package/lib/hooks/useClick.cjs.map +1 -1
- package/lib/hooks/useClick.js +7 -4
- package/lib/hooks/useClick.js.map +1 -1
- package/lib/hooks/useOuterClick.cjs +5 -6
- package/lib/hooks/useOuterClick.cjs.map +1 -1
- package/lib/hooks/useOuterClick.js +6 -7
- package/lib/hooks/useOuterClick.js.map +1 -1
- package/lib/hooks/usePortal.cjs +24 -17
- package/lib/hooks/usePortal.cjs.map +1 -1
- package/lib/hooks/usePortal.d.ts +1 -1
- package/lib/hooks/usePortal.js +25 -18
- package/lib/hooks/usePortal.js.map +1 -1
- package/lib/hooks/useResponseStatus.cjs +20 -23
- package/lib/hooks/useResponseStatus.cjs.map +1 -1
- package/lib/hooks/useResponseStatus.js +20 -23
- package/lib/hooks/useResponseStatus.js.map +1 -1
- package/lib/intl/locales/en_us.json.cjs +1 -0
- package/lib/intl/locales/en_us.json.cjs.map +1 -1
- package/lib/intl/locales/en_us.json.js +1 -0
- package/lib/intl/locales/en_us.json.js.map +1 -1
- package/lib/intl/locales/id_id.json.cjs +0 -8
- package/lib/intl/locales/id_id.json.cjs.map +1 -1
- package/lib/intl/locales/id_id.json.js +0 -8
- package/lib/intl/locales/id_id.json.js.map +1 -1
- package/lib/intl/locales/index.d.ts +6 -16
- package/lib/intl/locales/ja_easy.json.cjs +1 -0
- package/lib/intl/locales/ja_easy.json.cjs.map +1 -1
- package/lib/intl/locales/ja_easy.json.js +1 -0
- package/lib/intl/locales/ja_easy.json.js.map +1 -1
- package/lib/intl/locales/ko_kr.json.cjs +1 -0
- package/lib/intl/locales/ko_kr.json.cjs.map +1 -1
- package/lib/intl/locales/ko_kr.json.js +1 -0
- package/lib/intl/locales/ko_kr.json.js.map +1 -1
- package/lib/intl/locales/pt_br.json.cjs +0 -8
- package/lib/intl/locales/pt_br.json.cjs.map +1 -1
- package/lib/intl/locales/pt_br.json.js +0 -8
- package/lib/intl/locales/pt_br.json.js.map +1 -1
- package/lib/intl/locales/vi_vn.json.cjs +1 -0
- package/lib/intl/locales/vi_vn.json.cjs.map +1 -1
- package/lib/intl/locales/vi_vn.json.js +1 -0
- package/lib/intl/locales/vi_vn.json.js.map +1 -1
- package/lib/intl/locales/zh_hans_cn.json.cjs +1 -0
- package/lib/intl/locales/zh_hans_cn.json.cjs.map +1 -1
- package/lib/intl/locales/zh_hans_cn.json.js +1 -0
- package/lib/intl/locales/zh_hans_cn.json.js.map +1 -1
- package/lib/intl/locales/zh_hant_tw.json.cjs +1 -0
- package/lib/intl/locales/zh_hant_tw.json.cjs.map +1 -1
- package/lib/intl/locales/zh_hant_tw.json.js +1 -0
- package/lib/intl/locales/zh_hant_tw.json.js.map +1 -1
- package/lib/intl/useDateFormat.cjs +1 -2
- package/lib/intl/useDateFormat.cjs.map +1 -1
- package/lib/intl/useDateFormat.js +1 -2
- package/lib/intl/useDateFormat.js.map +1 -1
- package/lib/intl/useIntl.cjs +2 -4
- package/lib/intl/useIntl.cjs.map +1 -1
- package/lib/intl/useIntl.js +2 -4
- package/lib/intl/useIntl.js.map +1 -1
- package/lib/libs/debounce.cjs +10 -2
- package/lib/libs/debounce.cjs.map +1 -1
- package/lib/libs/debounce.d.ts +4 -2
- package/lib/libs/debounce.js +10 -2
- package/lib/libs/debounce.js.map +1 -1
- package/lib/libs/lodash.cjs +3 -4
- package/lib/libs/lodash.cjs.map +1 -1
- package/lib/libs/lodash.d.ts +2 -11
- package/lib/libs/lodash.js +2 -7
- package/lib/libs/lodash.js.map +1 -1
- package/lib/libs/map.cjs +1 -5
- package/lib/libs/map.cjs.map +1 -1
- package/lib/libs/map.js +1 -5
- package/lib/libs/map.js.map +1 -1
- package/lib/themes/createBackgroundColor.cjs +3 -2
- package/lib/themes/createBackgroundColor.cjs.map +1 -1
- package/lib/themes/createBackgroundColor.js +2 -1
- package/lib/themes/createBackgroundColor.js.map +1 -1
- package/lib/themes/createBorder.cjs +3 -2
- package/lib/themes/createBorder.cjs.map +1 -1
- package/lib/themes/createBorder.js +2 -1
- package/lib/themes/createBorder.js.map +1 -1
- package/lib/themes/createBreakpoint.cjs +3 -2
- package/lib/themes/createBreakpoint.cjs.map +1 -1
- package/lib/themes/createBreakpoint.js +2 -1
- package/lib/themes/createBreakpoint.js.map +1 -1
- package/lib/themes/createColor.cjs +3 -2
- package/lib/themes/createColor.cjs.map +1 -1
- package/lib/themes/createColor.js +2 -1
- package/lib/themes/createColor.js.map +1 -1
- package/lib/themes/createFontSize.cjs +3 -2
- package/lib/themes/createFontSize.cjs.map +1 -1
- package/lib/themes/createFontSize.js +2 -1
- package/lib/themes/createFontSize.js.map +1 -1
- package/lib/themes/createInteraction.cjs +3 -2
- package/lib/themes/createInteraction.cjs.map +1 -1
- package/lib/themes/createInteraction.js +2 -1
- package/lib/themes/createInteraction.js.map +1 -1
- package/lib/themes/createLeading.cjs +3 -2
- package/lib/themes/createLeading.cjs.map +1 -1
- package/lib/themes/createLeading.js +2 -1
- package/lib/themes/createLeading.js.map +1 -1
- package/lib/themes/createRadius.cjs +3 -2
- package/lib/themes/createRadius.cjs.map +1 -1
- package/lib/themes/createRadius.js +2 -1
- package/lib/themes/createRadius.js.map +1 -1
- package/lib/themes/createShadow/createShadow.cjs +3 -2
- package/lib/themes/createShadow/createShadow.cjs.map +1 -1
- package/lib/themes/createShadow/createShadow.js +2 -1
- package/lib/themes/createShadow/createShadow.js.map +1 -1
- package/lib/themes/createTextColor.cjs +3 -2
- package/lib/themes/createTextColor.cjs.map +1 -1
- package/lib/themes/createTextColor.js +2 -1
- package/lib/themes/createTextColor.js.map +1 -1
- package/lib/themes/createZIndex.cjs +3 -2
- package/lib/themes/createZIndex.cjs.map +1 -1
- package/lib/themes/createZIndex.js +2 -1
- package/lib/themes/createZIndex.js.map +1 -1
- package/metadata.json +1 -1
- package/package.json +1 -1
- 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":"
|
|
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
|
|
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":"
|
|
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 +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
|
|
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;;;;"}
|
|
@@ -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
|
|
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
|
-
}, [
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
}, "
|
|
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 }, [
|
|
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
|
-
}, [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
}, "
|
|
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 }, [
|
|
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 },
|
|
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
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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 },
|
|
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
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
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
|
-
|
|
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
|
|
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 = (
|
|
50
|
-
if (!
|
|
49
|
+
const calculateIdealRows = (node, maxRows, lineHeightNormal) => {
|
|
50
|
+
if (!node) {
|
|
51
51
|
return 0;
|
|
52
52
|
}
|
|
53
53
|
// 現在の入力値に応じた行数
|
|
54
|
-
const currentInputValueRows = Math.floor(
|
|
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,
|
|
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
|
|
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: (
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
callbackRef: (node) => {
|
|
132
|
+
// TODO: useMergeRefs, useOnceCallbackが実装されたら適用する
|
|
133
|
+
innerRef.current = node;
|
|
134
|
+
if (node) {
|
|
129
135
|
// autoFocus時に、フォーカスを当てる
|
|
130
136
|
if (latest.autoFocus) {
|
|
131
|
-
|
|
137
|
+
node.focus();
|
|
132
138
|
}
|
|
133
139
|
// autoResize時に、初期値での高さを指定
|
|
134
140
|
if (latest.autoResize) {
|
|
135
|
-
setInterimRows(calculateIdealRows(
|
|
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, () =>
|
|
152
|
-
return (jsxRuntime.jsx("textarea", { ...rest,
|
|
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;
|