@flipdish/portal-library 7.12.1 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -4
- package/dist/components/atoms/Tag/index.cjs.js +1 -1
- package/dist/components/atoms/Tag/index.cjs.js.map +1 -1
- package/dist/components/atoms/Tag/index.d.ts +3 -7
- package/dist/components/atoms/Tag/index.js +1 -1
- package/dist/components/atoms/Tag/index.js.map +1 -1
- package/dist/components/atoms/TextArea/index.cjs.js.map +1 -1
- package/dist/components/atoms/TextArea/index.d.ts +1 -1
- package/dist/components/atoms/TextArea/index.js.map +1 -1
- package/dist/components/atoms/TextField/index.cjs.js +1 -1
- package/dist/components/atoms/TextField/index.cjs.js.map +1 -1
- package/dist/components/atoms/TextField/index.d.ts +5 -22
- package/dist/components/atoms/TextField/index.js +1 -1
- package/dist/components/atoms/TextField/index.js.map +1 -1
- package/dist/components/molecules/AlertGlobal/index.cjs.js +1 -1
- package/dist/components/molecules/AlertGlobal/index.cjs.js.map +1 -1
- package/dist/components/molecules/AlertGlobal/index.d.ts +1 -8
- package/dist/components/molecules/AlertGlobal/index.js +1 -1
- package/dist/components/molecules/AlertGlobal/index.js.map +1 -1
- package/dist/components/molecules/Autocomplete/index.cjs.js +1 -1
- package/dist/components/molecules/Autocomplete/index.cjs.js.map +1 -1
- package/dist/components/molecules/Autocomplete/index.d.ts +1 -16
- package/dist/components/molecules/Autocomplete/index.js +1 -1
- package/dist/components/molecules/Autocomplete/index.js.map +1 -1
- package/dist/components/molecules/Pagination/index.cjs.js +1 -1
- package/dist/components/molecules/Pagination/index.cjs.js.map +1 -1
- package/dist/components/molecules/Pagination/index.d.ts +1 -12
- package/dist/components/molecules/Pagination/index.js +1 -1
- package/dist/components/molecules/Pagination/index.js.map +1 -1
- package/dist/components/molecules/QuantitySelector/index.cjs.js +1 -1
- package/dist/components/molecules/QuantitySelector/index.cjs.js.map +1 -1
- package/dist/components/molecules/QuantitySelector/index.d.ts +1 -7
- package/dist/components/molecules/QuantitySelector/index.js +1 -1
- package/dist/components/molecules/QuantitySelector/index.js.map +1 -1
- package/dist/components/molecules/Rating/index.cjs.js +1 -1
- package/dist/components/molecules/Rating/index.cjs.js.map +1 -1
- package/dist/components/molecules/Rating/index.d.ts +0 -15
- package/dist/components/molecules/Rating/index.js +1 -1
- package/dist/components/molecules/Rating/index.js.map +1 -1
- package/dist/components/molecules/SearchInput/index.cjs.js +1 -1
- package/dist/components/molecules/SearchInput/index.cjs.js.map +1 -1
- package/dist/components/molecules/SearchInput/index.d.ts +1 -5
- package/dist/components/molecules/SearchInput/index.js +1 -1
- package/dist/components/molecules/SearchInput/index.js.map +1 -1
- package/dist/components/organisms/FileUpload/components/FileDropZone.cjs.js +1 -1
- package/dist/components/organisms/FileUpload/components/FileDropZone.cjs.js.map +1 -1
- package/dist/components/organisms/FileUpload/components/FileDropZone.js +1 -1
- package/dist/components/organisms/FileUpload/components/FileDropZone.js.map +1 -1
- package/dist/components/organisms/Heading/Heading.cjs.js +1 -1
- package/dist/components/organisms/Heading/Heading.cjs.js.map +1 -1
- package/dist/components/organisms/Heading/Heading.d.ts +0 -1
- package/dist/components/organisms/Heading/Heading.js +1 -1
- package/dist/components/organisms/Heading/Heading.js.map +1 -1
- package/dist/localization/de.json.cjs.js +1 -1
- package/dist/localization/de.json.js +1 -1
- package/dist/localization/en-US.json.cjs.js +1 -1
- package/dist/localization/en-US.json.js +1 -1
- package/dist/localization/en.json.cjs.js +1 -1
- package/dist/localization/en.json.d.ts +116 -1
- package/dist/localization/en.json.js +1 -1
- package/dist/localization/es-MX.json.cjs.js +1 -1
- package/dist/localization/es-MX.json.js +1 -1
- package/dist/localization/es.json.cjs.js +1 -1
- package/dist/localization/es.json.js +1 -1
- package/dist/localization/fr.json.cjs.js +1 -1
- package/dist/localization/fr.json.js +1 -1
- package/dist/localization/it.json.cjs.js +1 -1
- package/dist/localization/it.json.js +1 -1
- package/dist/localization/nl.json.cjs.js +1 -1
- package/dist/localization/nl.json.js +1 -1
- package/dist/localization/pt.json.cjs.js +1 -1
- package/dist/localization/pt.json.js +1 -1
- package/dist/providers/TranslationProvider.cjs.js.map +1 -1
- package/dist/providers/TranslationProvider.d.ts +6 -2
- package/dist/providers/TranslationProvider.js +1 -1
- package/dist/providers/TranslationProvider.js.map +1 -1
- package/dist/utilities/renderUtilities.cjs.js +1 -1
- package/dist/utilities/renderUtilities.cjs.js.map +1 -1
- package/dist/utilities/renderUtilities.d.ts +14 -1
- package/dist/utilities/renderUtilities.js +1 -1
- package/dist/utilities/renderUtilities.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/components/molecules/AlertGlobal/index.tsx"],"sourcesContent":["import { memo, type ReactElement, type ReactNode } from 'react';\n\nimport MuiAlert from '@mui/material/Alert';\n\nimport Box from '@fd/components/atoms/Box';\nimport Button from '@fd/components/atoms/Button';\nimport type { ButtonType } from '@fd/components/atoms/Button/getButtonStyles';\nimport IconButton from '@fd/components/atoms/IconButton';\nimport type { AlertTones } from '@fd/components/molecules/Alert';\nimport ButtonGroup from '@fd/components/molecules/ButtonGroup';\nimport CancelIcon from '@fd/icons/Cancel';\nimport styled from '@fd/utilities/styledUtilities';\nimport useMediaQuery from '@fd/utilities/useMediaQuery';\nimport useTheme from '@fd/utilities/useTheme';\n\nimport {\n getAlertGlobalBackgroundColour,\n getAlertGlobalBorderColour,\n getAlertGlobalIcon,\n getAlertGlobalTextColour,\n} from './alertGlobalTokens';\n\n/**\n * Global alert component for prominent, page-level messages.\n *\n * - Renders an icon and description with optional actions and a close button\n * - `action` accepts a single action object or an array of action objects\n * (use an array to render multiple buttons side-by-side)\n * - Consumers are responsible for providing localized strings for any\n * user-visible text (e.g. `description`, action `label`, `closeAriaLabel`).\n */\nexport interface AlertGlobalProps {\n /**\n * Message content shown in the alert. Provide a localized string.\n */\n description: string;\n /**\n * Visual tone of the alert which controls icon and colors.\n * Defaults to `neutral`.\n */\n tone?: AlertTones;\n /**\n * Called when the close button is pressed. When omitted, no close button is rendered.\n */\n onClose?: () => void;\n /**\n * One or more actions to render as buttons. A single object renders one button;\n * an array renders multiple buttons. Provide localized `label` values.\n */\n action?: AlertAction | AlertAction[];\n /**\n * Accessible label for the close icon button. Provide a localized string.\n * Defaults to \"Close\".\n */\n closeAriaLabel?: string;\n /** Optional CSS class name for the root element. */\n className?: string;\n /** Optional test id for the root element. */\n 'data-fd'?: string;\n}\n\n/**\n * Describes a user action rendered as a button in the alert.\n */\nexport interface AlertAction {\n /** Optional unique identifier for this action. Recommended for stable React keys. */\n id?: string;\n /** Button text. Provide a localized string. */\n label: string;\n /** Visual variant of the button. Defaults to `secondary`. */\n type?: ButtonType;\n /** Click handler for the action. */\n onClick: () => void;\n /** Optional test id applied to the button. */\n 'data-fd'?: string;\n}\n\ninterface StyledAlertProps {\n tone: AlertTones;\n}\n\nconst StyledGlobalAlert = styled(MuiAlert, {\n shouldForwardProp: (prop: string): boolean => !['tone'].includes(prop),\n})<StyledAlertProps>(({ theme, tone }) => ({\n alignItems: 'center',\n backgroundColor: getAlertGlobalBackgroundColour(theme, tone),\n borderBottom: '1px solid',\n borderRadius: 0,\n borderColor: getAlertGlobalBorderColour(theme, tone),\n color: getAlertGlobalTextColour(theme, tone),\n padding: theme.spacing(3),\n paddingTop: theme.spacing(1.5),\n paddingBottom: theme.spacing(1.5),\n width: '100%',\n display: 'flex',\n position: 'relative',\n '& .MuiAlert-icon': {\n alignSelf: 'flex-start',\n },\n '& .MuiAlert-message': {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(2),\n flexGrow: 1,\n minWidth: 0,\n },\n '& .MuiAlert-action': {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(3),\n marginLeft: 'auto',\n },\n '& .MuiAlert-action .MuiIconButton-root': {\n outline: 'none',\n boxShadow: 'none',\n border: 'none',\n },\n '& .MuiAlert-action .MuiIconButton-root:focus, & .MuiAlert-action .MuiIconButton-root:focus-visible': {\n outline: 'none',\n boxShadow: 'none',\n },\n // Inline actions inside message container\n '& .fd-alert-message': {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(2),\n width: '100%',\n },\n '& .fd-alert-description': {\n flexGrow: 1,\n minWidth: 0,\n },\n '& .fd-alert-actions-inline': {\n marginLeft: 'auto',\n display: 'none',\n },\n '& .fd-alert-actions-action': {\n display: 'flex',\n },\n // Mobile layout: stack and right-align button group below description\n [theme.breakpoints.down('tablet')]: {\n '& .fd-alert-message': {\n flexDirection: 'column',\n alignItems: 'stretch',\n gap: theme.spacing(2),\n },\n '& .fd-alert-actions-inline': {\n marginLeft: 0,\n marginTop: theme.spacing(2),\n width: '100%',\n justifyContent: 'flex-end',\n display: 'flex',\n },\n '& .fd-alert-actions-action': {\n display: 'none',\n },\n '& .MuiAlert-action': {\n position: 'absolute',\n top: theme.spacing(3),\n right: theme.spacing(3),\n marginLeft: 0,\n },\n },\n}));\n\nconst ActionContainer = styled(Box)(\n ({ theme }): Record<string, unknown> => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(3),\n }),\n);\n\nconst AlertGlobalComponent = ({\n description,\n tone = 'neutral',\n onClose,\n action,\n className,\n closeAriaLabel = 'Close',\n 'data-fd': dataFd,\n}: AlertGlobalProps): ReactElement => {\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('tablet'));\n\n const actionsArray = action ? (Array.isArray(action) ? action : [action]) : [];\n const actionButtons = actionsArray.map((actionItem) => {\n const uniqueKey =\n actionItem.id ?? `${actionItem.label.replace(/\\s+/g, '-').toLowerCase()}-${actionItem.type ?? 'type'}`;\n return (\n <Button\n key={uniqueKey}\n fdKey={\n actionItem['data-fd'] ?? `action-button-${actionItem.label.replace(/\\s+/g, '-').toLowerCase()}`\n }\n onClick={actionItem.onClick}\n size=\"small\"\n tone=\"neutral\"\n variant={actionItem.type ?? 'secondary'}\n >\n {actionItem.label}\n </Button>\n );\n });\n\n const nodes: ReactNode[] = [];\n if (actionButtons.length && !isMobile) {\n nodes.push(\n <ButtonGroup\n key=\"action-group-action\"\n align=\"right\"\n className=\"fd-alert-actions-action\"\n layout=\"horizontal\"\n size=\"small\"\n >\n {actionButtons}\n </ButtonGroup>,\n );\n }\n if (onClose) {\n nodes.push(\n <IconButton\n key=\"close\"\n aria-label={closeAriaLabel}\n data-fd=\"close-button\"\n onClick={onClose}\n size=\"small\"\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <CancelIcon />\n </IconButton>,\n );\n }\n\n return (\n <StyledGlobalAlert\n action={nodes.length ? <ActionContainer>{nodes}</ActionContainer> : undefined}\n className={className}\n data-fd={dataFd}\n icon={getAlertGlobalIcon(theme, tone)}\n role=\"alert\"\n tone={tone}\n >\n <Box className=\"fd-alert-message\">\n <Box className=\"fd-alert-description\">{description}</Box>\n {isMobile && actionButtons.length ? (\n <ButtonGroup align=\"right\" className=\"fd-alert-actions-inline\" layout=\"horizontal\" size=\"small\">\n {actionButtons}\n </ButtonGroup>\n ) : null}\n </Box>\n </StyledGlobalAlert>\n );\n};\n\nconst AlertGlobal = memo(AlertGlobalComponent);\nAlertGlobal.displayName = 'AlertGlobal';\n\nexport default AlertGlobal;\n"],"names":["StyledGlobalAlert","styled","MuiAlert","shouldForwardProp","prop","includes","theme","tone","alignItems","backgroundColor","getAlertGlobalBackgroundColour","borderBottom","borderRadius","borderColor","getAlertGlobalBorderColour","color","getAlertGlobalTextColour","padding","spacing","paddingTop","paddingBottom","width","display","position","alignSelf","gap","flexGrow","minWidth","marginLeft","outline","boxShadow","border","breakpoints","down","flexDirection","marginTop","justifyContent","top","right","ActionContainer","Box","AlertGlobal","memo","description","onClose","action","className","closeAriaLabel","dataFd","useTheme","isMobile","useMediaQuery","actionButtons","Array","isArray","map","actionItem","uniqueKey","id","label","replace","toLowerCase","type","_jsx","Button","fdKey","onClick","size","variant","children","nodes","length","push","ButtonGroup","align","layout","IconButton","CancelIcon","undefined","icon","getAlertGlobalIcon","role","_jsxs","displayName"],"mappings":"8nBAiFA,MAAMA,EAAoBC,EAAOC,EAAU,CACzCC,kBAAoBC,IAA2B,CAAC,QAAQC,SAASD,IADzCH,EAEL,EAAGK,QAAOC,WAAM,CACnCC,WAAY,SACZC,gBAAiBC,EAA+BJ,EAAOC,GACvDI,aAAc,YACdC,aAAc,EACdC,YAAaC,EAA2BR,EAAOC,GAC/CQ,MAAOC,EAAyBV,EAAOC,GACvCU,QAASX,EAAMY,QAAQ,GACvBC,WAAYb,EAAMY,QAAQ,KAC1BE,cAAed,EAAMY,QAAQ,KAC7BG,MAAO,OACPC,QAAS,OACTC,SAAU,WACV,mBAAoB,CAClBC,UAAW,cAEb,sBAAuB,CACrBF,QAAS,OACTd,WAAY,SACZiB,IAAKnB,EAAMY,QAAQ,GACnBQ,SAAU,EACVC,SAAU,GAEZ,qBAAsB,CACpBL,QAAS,OACTd,WAAY,SACZiB,IAAKnB,EAAMY,QAAQ,GACnBU,WAAY,QAEd,yCAA0C,CACxCC,QAAS,OACTC,UAAW,OACXC,OAAQ,QAEV,qGAAsG,CACpGF,QAAS,OACTC,UAAW,QAGb,sBAAuB,CACrBR,QAAS,OACTd,WAAY,SACZiB,IAAKnB,EAAMY,QAAQ,GACnBG,MAAO,QAET,0BAA2B,CACzBK,SAAU,EACVC,SAAU,GAEZ,6BAA8B,CAC5BC,WAAY,OACZN,QAAS,QAEX,6BAA8B,CAC5BA,QAAS,QAGX,CAAChB,EAAM0B,YAAYC,KAAK,WAAY,CAClC,sBAAuB,CACrBC,cAAe,SACf1B,WAAY,UACZiB,IAAKnB,EAAMY,QAAQ,IAErB,6BAA8B,CAC5BU,WAAY,EACZO,UAAW7B,EAAMY,QAAQ,GACzBG,MAAO,OACPe,eAAgB,WAChBd,QAAS,QAEX,6BAA8B,CAC5BA,QAAS,QAEX,qBAAsB,CACpBC,SAAU,WACVc,IAAK/B,EAAMY,QAAQ,GACnBoB,MAAOhC,EAAMY,QAAQ,GACrBU,WAAY,QAKZW,EAAkBtC,EAAOuC,EAAPvC,EACtB,EAAGK,YAAO,CACRgB,QAAS,OACTd,WAAY,SACZiB,IAAKnB,EAAMY,QAAQ,OAuFjBuB,EAAcC,GAnFS,EAC3BC,cACApC,OAAO,UACPqC,UACAC,SACAC,YACAC,iBAAiB,QACjB,UAAWC,MAEX,MAAM1C,EAAQ2C,IACRC,EAAWC,EAAc7C,EAAM0B,YAAYC,KAAK,WAGhDmB,GADeP,EAAUQ,MAAMC,QAAQT,GAAUA,EAAS,CAACA,GAAW,IACzCU,KAAKC,IACtC,MAAMC,EACJD,EAAWE,IAAM,GAAGF,EAAWG,MAAMC,QAAQ,OAAQ,KAAKC,iBAAiBL,EAAWM,MAAQ,SAChG,OACEC,EAACC,EAAM,CAELC,MACET,EAAW,YAAc,iBAAiBA,EAAWG,MAAMC,QAAQ,OAAQ,KAAKC,gBAElFK,QAASV,EAAWU,QACpBC,KAAK,QACL5D,KAAK,UACL6D,QAASZ,EAAWM,MAAQ,YAAWO,SAEtCb,EAAWG,OATPF,MAcLa,EAAqB,GA8B3B,OA7BIlB,EAAcmB,SAAWrB,GAC3BoB,EAAME,KACJT,EAACU,EAAW,CAEVC,MAAM,QACN5B,UAAU,0BACV6B,OAAO,aACPR,KAAK,QAAOE,SAEXjB,GANG,wBAUNR,GACF0B,EAAME,KACJT,EAACa,EAAU,CAAA,aAEG7B,EAAc,UAClB,eACRmB,QAAStB,EACTuB,KAAK,QACL5D,KAAK,UACL6D,QAAQ,WAAUC,SAElBN,EAACc,EAAU,CAAA,IARP,UAcRd,EAAC/D,EAAiB,CAChB6C,OAAQyB,EAAMC,OAASR,EAACxB,YAAiB+B,SAA2BQ,EACpEhC,UAAWA,EAAS,UACXE,EACT+B,KAAMC,EAAmB1E,EAAOC,GAChC0E,KAAK,QACL1E,KAAMA,EAAI8D,SAEVa,EAAC1C,EAAG,CAACM,UAAU,mBAAkBuB,SAAA,CAC/BN,EAACvB,EAAG,CAACM,UAAU,uBAAsBuB,SAAE1B,IACtCO,GAAYE,EAAcmB,OACzBR,EAACU,EAAW,CAACC,MAAM,QAAQ5B,UAAU,0BAA0B6B,OAAO,aAAaR,KAAK,iBACrFf,IAED,aAOZX,EAAY0C,YAAc"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/molecules/AlertGlobal/index.tsx"],"sourcesContent":["import { memo, type ReactElement, type ReactNode } from 'react';\n\nimport MuiAlert from '@mui/material/Alert';\n\nimport Box from '@fd/components/atoms/Box';\nimport Button from '@fd/components/atoms/Button';\nimport type { ButtonType } from '@fd/components/atoms/Button/getButtonStyles';\nimport IconButton from '@fd/components/atoms/IconButton';\nimport type { AlertTones } from '@fd/components/molecules/Alert';\nimport ButtonGroup from '@fd/components/molecules/ButtonGroup';\nimport CancelIcon from '@fd/icons/Cancel';\nimport { useTranslation } from '@fd/providers/TranslationProvider';\nimport styled from '@fd/utilities/styledUtilities';\nimport useMediaQuery from '@fd/utilities/useMediaQuery';\nimport useTheme from '@fd/utilities/useTheme';\n\nimport {\n getAlertGlobalBackgroundColour,\n getAlertGlobalBorderColour,\n getAlertGlobalIcon,\n getAlertGlobalTextColour,\n} from './alertGlobalTokens';\n\n/**\n * Global alert component for prominent, page-level messages.\n *\n * - Renders an icon and description with optional actions and a close button\n * - `action` accepts a single action object or an array of action objects\n * (use an array to render multiple buttons side-by-side)\n */\nexport interface AlertGlobalProps {\n /**\n * Message content shown in the alert. Provide a localized string.\n */\n description: string;\n /**\n * Visual tone of the alert which controls icon and colors.\n * Defaults to `neutral`.\n */\n tone?: AlertTones;\n /**\n * Called when the close button is pressed. When omitted, no close button is rendered.\n */\n onClose?: () => void;\n /**\n * One or more actions to render as buttons. A single object renders one button;\n * an array renders multiple buttons. Provide localized `label` values.\n */\n action?: AlertAction | AlertAction[];\n /** Optional CSS class name for the root element. */\n className?: string;\n /** Optional test id for the root element. */\n 'data-fd'?: string;\n}\n\n/**\n * Describes a user action rendered as a button in the alert.\n */\nexport interface AlertAction {\n /** Optional unique identifier for this action. Recommended for stable React keys. */\n id?: string;\n /** Button text. Provide a localized string. */\n label: string;\n /** Visual variant of the button. Defaults to `secondary`. */\n type?: ButtonType;\n /** Click handler for the action. */\n onClick: () => void;\n /** Optional test id applied to the button. */\n 'data-fd'?: string;\n}\n\ninterface StyledAlertProps {\n tone: AlertTones;\n}\n\nconst StyledGlobalAlert = styled(MuiAlert, {\n shouldForwardProp: (prop: string): boolean => !['tone'].includes(prop),\n})<StyledAlertProps>(({ theme, tone }) => ({\n alignItems: 'center',\n backgroundColor: getAlertGlobalBackgroundColour(theme, tone),\n borderBottom: '1px solid',\n borderRadius: 0,\n borderColor: getAlertGlobalBorderColour(theme, tone),\n color: getAlertGlobalTextColour(theme, tone),\n padding: theme.spacing(3),\n paddingTop: theme.spacing(1.5),\n paddingBottom: theme.spacing(1.5),\n width: '100%',\n display: 'flex',\n position: 'relative',\n '& .MuiAlert-icon': {\n alignSelf: 'flex-start',\n },\n '& .MuiAlert-message': {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(2),\n flexGrow: 1,\n minWidth: 0,\n },\n '& .MuiAlert-action': {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(3),\n marginLeft: 'auto',\n },\n '& .MuiAlert-action .MuiIconButton-root': {\n outline: 'none',\n boxShadow: 'none',\n border: 'none',\n },\n '& .MuiAlert-action .MuiIconButton-root:focus, & .MuiAlert-action .MuiIconButton-root:focus-visible': {\n outline: 'none',\n boxShadow: 'none',\n },\n // Inline actions inside message container\n '& .fd-alert-message': {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(2),\n width: '100%',\n },\n '& .fd-alert-description': {\n flexGrow: 1,\n minWidth: 0,\n },\n '& .fd-alert-actions-inline': {\n marginLeft: 'auto',\n display: 'none',\n },\n '& .fd-alert-actions-action': {\n display: 'flex',\n },\n // Mobile layout: stack and right-align button group below description\n [theme.breakpoints.down('tablet')]: {\n '& .fd-alert-message': {\n flexDirection: 'column',\n alignItems: 'stretch',\n gap: theme.spacing(2),\n },\n '& .fd-alert-actions-inline': {\n marginLeft: 0,\n marginTop: theme.spacing(2),\n width: '100%',\n justifyContent: 'flex-end',\n display: 'flex',\n },\n '& .fd-alert-actions-action': {\n display: 'none',\n },\n '& .MuiAlert-action': {\n position: 'absolute',\n top: theme.spacing(3),\n right: theme.spacing(3),\n marginLeft: 0,\n },\n },\n}));\n\nconst ActionContainer = styled(Box)(\n ({ theme }): Record<string, unknown> => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(3),\n }),\n);\n\nconst AlertGlobalComponent = ({\n description,\n tone = 'neutral',\n onClose,\n action,\n className,\n 'data-fd': dataFd,\n}: AlertGlobalProps): ReactElement => {\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('tablet'));\n const { translate } = useTranslation();\n\n const actionsArray = action ? (Array.isArray(action) ? action : [action]) : [];\n const actionButtons = actionsArray.map((actionItem) => {\n const uniqueKey =\n actionItem.id ?? `${actionItem.label.replace(/\\s+/g, '-').toLowerCase()}-${actionItem.type ?? 'type'}`;\n return (\n <Button\n key={uniqueKey}\n fdKey={\n actionItem['data-fd'] ?? `action-button-${actionItem.label.replace(/\\s+/g, '-').toLowerCase()}`\n }\n onClick={actionItem.onClick}\n size=\"small\"\n tone=\"neutral\"\n variant={actionItem.type ?? 'secondary'}\n >\n {actionItem.label}\n </Button>\n );\n });\n\n const nodes: ReactNode[] = [];\n if (actionButtons.length && !isMobile) {\n nodes.push(\n <ButtonGroup\n key=\"action-group-action\"\n align=\"right\"\n className=\"fd-alert-actions-action\"\n layout=\"horizontal\"\n size=\"small\"\n >\n {actionButtons}\n </ButtonGroup>,\n );\n }\n if (onClose) {\n nodes.push(\n <IconButton\n key=\"close\"\n aria-label={translate('Close')}\n data-fd=\"close-button\"\n onClick={onClose}\n size=\"small\"\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <CancelIcon />\n </IconButton>,\n );\n }\n\n return (\n <StyledGlobalAlert\n action={nodes.length ? <ActionContainer>{nodes}</ActionContainer> : undefined}\n className={className}\n data-fd={dataFd}\n icon={getAlertGlobalIcon(theme, tone)}\n role=\"alert\"\n tone={tone}\n >\n <Box className=\"fd-alert-message\">\n <Box className=\"fd-alert-description\">{description}</Box>\n {isMobile && actionButtons.length ? (\n <ButtonGroup align=\"right\" className=\"fd-alert-actions-inline\" layout=\"horizontal\" size=\"small\">\n {actionButtons}\n </ButtonGroup>\n ) : null}\n </Box>\n </StyledGlobalAlert>\n );\n};\n\nconst AlertGlobal = memo(AlertGlobalComponent);\nAlertGlobal.displayName = 'AlertGlobal';\n\nexport default AlertGlobal;\n"],"names":["StyledGlobalAlert","styled","MuiAlert","shouldForwardProp","prop","includes","theme","tone","alignItems","backgroundColor","getAlertGlobalBackgroundColour","borderBottom","borderRadius","borderColor","getAlertGlobalBorderColour","color","getAlertGlobalTextColour","padding","spacing","paddingTop","paddingBottom","width","display","position","alignSelf","gap","flexGrow","minWidth","marginLeft","outline","boxShadow","border","breakpoints","down","flexDirection","marginTop","justifyContent","top","right","ActionContainer","Box","AlertGlobal","memo","description","onClose","action","className","dataFd","useTheme","isMobile","useMediaQuery","translate","useTranslation","actionButtons","Array","isArray","map","actionItem","uniqueKey","id","label","replace","toLowerCase","type","_jsx","Button","fdKey","onClick","size","variant","children","nodes","length","push","ButtonGroup","align","layout","IconButton","CancelIcon","undefined","icon","getAlertGlobalIcon","role","_jsxs","displayName"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),i=require("react/jsx-runtime"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),i=require("react/jsx-runtime"),t=require("@mui/material/Autocomplete"),s=require("@mui/material/Box"),r=require("@mui/material/InputAdornment"),n=require("@mui/material/styles"),l=require("../../atoms/Badge/index.cjs.js"),o=require("../../atoms/CircularProgress/index.cjs.js"),a=require("../../atoms/MenuItem/index.cjs.js"),d=require("../../atoms/Tag/index.cjs.js"),u=require("../../atoms/TextField/index.cjs.js"),c=require("../../atoms/VisuallyHidden/index.cjs.js"),p=require("../Tooltip/index.cjs.js"),h=require("../../../icons/ArrowDown01/index.cjs.js"),m=require("../../../icons/ArrowUp01/index.cjs.js"),x=require("../../../icons/Cancel/index.cjs.js"),j=require("../../../icons/Search/index.cjs.js"),g=require("../../../providers/TranslationProvider.cjs.js"),y=require("../../../utilities/stringUtilities.cjs.js"),b=require("./hooks/useDynamicLimitTags.cjs.js"),f=require("./hooks/useShortcutHotkey.cjs.js");const T=t,q=n.styled(T,{shouldForwardProp:e=>"fullWidth"!==e})((({fullWidth:e=!1})=>({width:e?"100%":"min(364px, 100%)"}))),v=n.styled(r,{shouldForwardProp:e=>"disabled"!==e})((({theme:e,disabled:i=!1})=>({"&.MuiInputAdornment-positionEnd":{margin:0},"& svg":{color:i?e.palette.semantic.icon["icon-disabled"]:e.palette.semantic.icon["icon-strong"]}}))),k=n.styled(s)((({theme:e})=>({alignItems:"center",display:"flex",gap:e.spacing(1)}))),I=n.styled("span")((()=>({display:"inline-flex",".Mui-focused &":{display:"none"}}))),P=({ariaLabel:t,className:s,disabled:r=!1,errorText:n,fdKey:T,fullWidth:P=!1,helperText:C,label:A,loading:O=!1,multiple:S=!1,onChange:_,onInputChange:E,options:F=[],placeholder:M,required:W=!1,shortcutHotkey:w=!1,type:B="search",value:D})=>{const H=e.useRef(null),[L,V]=e.useState(""),[z,K]=e.useState(!1),{translate:N}=g.useTranslation(),R=S?Array.isArray(D)?D:null==D?[]:[D]:Array.isArray(D)?D.length>0?D[0]:null:D??null,U="search"===B,$="combobox"===B,G=(Boolean(L)||Boolean(R))&&!r,J=U&&w&&!R&&!r,Q=c.useVisuallyHiddenId(),X=e.useCallback((()=>{H.current?.focus()}),[]),{hotkeyText:Y}=f.useShortcutHotkey({enabled:J,onTrigger:X}),{rootRef:Z,limitTags:ee}=b.useDynamicLimitTags({chipMax:130,gap:4,horizontalPadding:32,reservedPx:U?120:90});e.useEffect((()=>{z&&(r&&K(!1),U&&0===F.length&&K(!1))}),[z,r,U,F.length]);const ie=e=>{r||U&&0===F.length||K(void 0===e?e=>!e:e)};return i.jsxs(i.Fragment,{children:[i.jsx(q,{ref:Z,className:s,clearIcon:i.jsx(x,{size:"md"}),clearText:N("Clear_selection"),disableClearable:!G,disableCloseOnSelect:S,disabled:r,filterOptions:U?e=>e:void 0,forcePopupIcon:$,freeSolo:U,fullWidth:P,getOptionKey:e=>"string"==typeof e?e:String(e.value),getOptionLabel:e=>"string"==typeof e?e:e.label,inputValue:L,isOptionEqualToValue:(e,i)=>null!=i&&("string"==typeof i?e.label===i||String(e.value)===i:e.value===i.value),limitTags:ee,loading:O,loadingText:`${N("Loading")}...`,multiple:S,noOptionsText:N("No_options"),onChange:(e,i,t,s)=>{_&&_(e,i,t,s)},onClose:()=>ie(!1),onInputChange:(e,i,t)=>{V(i),E&&E(e,i,t)},onOpen:()=>ie(!0),open:z,openText:N("Open_popup"),options:F,popupIcon:$?i.jsx(v,{disabled:r,position:"end",children:z?i.jsx(m,{}):i.jsx(h,{})}):null,renderInput:e=>{const s=Array.isArray(F)&&F.length>0,a=$||U&&s,d=[e.inputProps["aria-describedby"],J?Q:void 0].filter(Boolean).join(" ")||void 0;return i.jsx(u.TextField,{disabled:r,errorText:n,fdKey:T,fullWidth:P,helperText:C,inputRef:H,label:A,placeholder:M,required:W,slotProps:{input:{...e.InputProps,endAdornment:i.jsxs(i.Fragment,{children:[i.jsxs(k,{children:[O?i.jsx(o.CircularProgress,{size:"small"}):null,J?i.jsx(I,{children:i.jsx(l.Badge,{label:Y,size:"small",tone:"neutral"})}):null]}),e.InputProps.endAdornment]}),startAdornment:i.jsxs(i.Fragment,{children:[U?i.jsx(v,{disabled:r,position:"start",children:i.jsx(j,{"aria-hidden":"true","data-testid":"search-icon"})}):null,e.InputProps.startAdornment]})},htmlInput:{...e.inputProps,id:T,"aria-label":U&&!A?t:void 0,"aria-describedby":d,...!a&&{role:"searchbox","aria-autocomplete":"none","aria-invalid":n||W?e.inputProps["aria-invalid"]:void 0}}}})},renderOption:(i,t,s)=>{const{key:r,onClick:n,...l}=i;return S?e.createElement(a.MenuItem,{...l,key:r,checked:s.selected,label:t.label,onCheckedChange:(e,i)=>{n?.(i)},type:"checkbox"}):e.createElement(a.MenuItem,{...l,key:r,label:t.label,onClick:n,selected:s.selected,type:"text"})},renderTags:(e,t)=>e.map(((e,s)=>{const{key:r,onDelete:n,...l}=t({index:s}),o="string"==typeof e?e:e.label,a=y.truncateWithEllipsis(o,13,{includeEllipsisInLimit:!0}),u=a.endsWith("..."),c=r??`tag-${"string"==typeof e?e:e.value}`;return u?i.jsx(p.Tooltip,{title:o,children:i.jsx("span",{...l,children:i.jsx(d.Tag,{label:a,onDismiss:n})})},c):i.jsx("span",{...l,children:i.jsx(d.Tag,{label:a,onDismiss:n})},c)})),slotProps:{popupIndicator:{onClick:e=>{r||(e.stopPropagation(),ie())}}},value:R}),J&&i.jsx(c.VisuallyHidden,{fdKey:"autocomplete-shortcut-hotkey",id:Q,children:N("Press_hotkey_to_focus_search",{hotkey:Y})})]})};exports.Autocomplete=P,exports.default=P;
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/molecules/Autocomplete/index.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport MuiAutocomplete, {\n type AutocompleteChangeDetails,\n type AutocompleteChangeReason,\n type AutocompleteInputChangeReason,\n type AutocompleteProps as MuiAutocompleteProps,\n type AutocompleteRenderGetTagProps,\n type AutocompleteRenderInputParams,\n type AutocompleteRenderOptionState,\n type AutocompleteValue,\n} from '@mui/material/Autocomplete';\nimport Box from '@mui/material/Box';\nimport MuiInputAdornment from '@mui/material/InputAdornment';\nimport { styled } from '@mui/material/styles';\n\nimport Badge from '@fd/components/atoms/Badge';\nimport CircularProgress from '@fd/components/atoms/CircularProgress';\nimport MenuItem from '@fd/components/atoms/MenuItem';\nimport Tag from '@fd/components/atoms/Tag';\nimport TextField, { type TextFieldProps } from '@fd/components/atoms/TextField';\nimport VisuallyHidden, { useVisuallyHiddenId } from '@fd/components/atoms/VisuallyHidden';\nimport Tooltip from '@fd/components/molecules/Tooltip';\nimport ArrowDown01Icon from '@fd/icons/ArrowDown01';\nimport ArrowUp01Icon from '@fd/icons/ArrowUp01';\nimport CancelIcon from '@fd/icons/Cancel';\nimport SearchIcon from '@fd/icons/Search';\nimport { truncateWithEllipsis } from '@fd/utilities/stringUtilities';\n\nimport { useDynamicLimitTags } from './hooks/useDynamicLimitTags';\nimport { useShortcutHotkey } from './hooks/useShortcutHotkey';\n\n// Bind flags to MuiAutocomplete\ntype MuiCustomAutocompleteProps<\n M extends boolean = boolean, // Multiple\n DC extends boolean = boolean, // DisableClearable\n FS extends boolean = boolean, // FreeSolo\n> = MuiAutocompleteProps<AutocompleteOption, M, DC, FS>;\n\n/**\n * Represents an option in the Autocomplete dropdown.\n */\nexport interface AutocompleteOption {\n /** The label to display in the dropdown option. */\n label: string;\n /** The value to store in the dropdown option. */\n value: number | string;\n}\n\n/**\n * Props for the Autocomplete component.\n * Supports both single and multiple selection modes with optional search functionality.\n */\nexport interface AutocompleteProps extends Omit<\n TextFieldProps,\n 'endAdornment' | 'multiline' | 'onChange' | 'options' | 'startAdornment'\n> {\n /** Aria-label for the input when no label is provided. */\n ariaLabel?: string;\n /** Shows a loading indicator inside the input (e.g., while fetching). */\n loading?: boolean;\n /** Enables selection of multiple options and shows checkboxes and tags for selected values. */\n multiple?: MuiCustomAutocompleteProps['multiple'];\n /** Called when the selected value(s) change. */\n onChange: MuiCustomAutocompleteProps['onChange'];\n /** Called when the input text changes (typing or programmatic updates). */\n onInputChange?: MuiCustomAutocompleteProps['onInputChange'];\n /** Options to display in the dropdown list. */\n options: AutocompleteOption[];\n /** Shows the keyboard shortcut badge (Cmd/Ctrl + K) and enables focusing via the shortcut when in search mode. */\n shortcutHotkey?: boolean;\n /** UI and accessibility labels used by the component. */\n translations: {\n /** Aria-label for the clear button. */\n clearTextAriaLabel: string;\n /** Aria-label for the dismiss tag button. */\n dismissTagAriaLabel: string;\n /** Text shown while loading options. */\n loadingText: string;\n /** Text shown when there are no options to display. */\n noOptionsText: string;\n /** Aria-label for the popup indicator button. */\n openPopupAriaLabel: string;\n /** Screen reader hint describing the shortcut, e.g., \"Press ⌘+K to focus search\". */\n shortcutHotkeyAriaDescription: string;\n };\n /** Visual behavior: 'search' shows a leading search icon; 'combobox' shows a popup button. */\n type?: 'combobox' | 'search';\n /** Controlled value (single option, array for multiple, or null). */\n value: MuiCustomAutocompleteProps['value'];\n}\n\n// Bind flags to MuiAutocomplete, see MuiCustomAutocompleteProps for more details\nconst MuiCustomAutocomplete = MuiAutocomplete<AutocompleteOption, boolean, boolean, boolean>;\nconst StyledAutocomplete = styled(MuiCustomAutocomplete, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ fullWidth = false }) => ({\n width: fullWidth ? '100%' : 'min(364px, 100%)',\n}));\n\nconst StyledInputAdornment = styled(MuiInputAdornment, {\n shouldForwardProp: (prop) => prop !== 'disabled',\n})<{ disabled?: boolean }>(({ theme, disabled = false }) => ({\n '&.MuiInputAdornment-positionEnd': {\n margin: 0,\n },\n\n '& svg': {\n color: disabled\n ? theme.palette.semantic.icon['icon-disabled']\n : theme.palette.semantic.icon['icon-strong'],\n },\n}));\n\nconst StyledEndAdornmentContainer = styled(Box)(({ theme }) => ({\n alignItems: 'center',\n display: 'flex',\n gap: theme.spacing(1),\n}));\n\nconst ShortcutBadgeWrapper = styled('span')(() => ({\n display: 'inline-flex',\n\n // hide when input root is focused\n '.Mui-focused &': {\n display: 'none',\n },\n}));\n\n/**\n * A customizable Autocomplete component supporting search and combobox modes.\n * Supports single and multiple selection with dynamic tag rendering and optional loading states.\n *\n * @param props - The component props\n * @returns The rendered Autocomplete component\n */\nexport const Autocomplete = ({\n ariaLabel,\n className,\n disabled = false,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n label,\n loading = false,\n multiple = false,\n onChange,\n onInputChange,\n options = [],\n placeholder,\n required = false,\n shortcutHotkey = false,\n translations,\n type = 'search',\n value,\n}: AutocompleteProps): JSX.Element => {\n const inputRef = useRef<HTMLInputElement>(null);\n const [inputText, setInputText] = useState<string>('');\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n /**\n * Normalizes the value prop for MUI Autocomplete.\n * Handles both single and multiple selection modes, ensuring the value\n * format matches the mode (array for multiple, single value/null for single).\n *\n * @returns Normalized value compatible with MUI Autocomplete\n */\n const getValue = (): AutocompleteProps['value'] => {\n // Multiple value selection\n if (multiple) {\n if (Array.isArray(value)) return value;\n if (value === null || value === undefined) return [];\n return [value as AutocompleteOption];\n }\n\n // Single value selection\n if (Array.isArray(value)) return value.length > 0 ? value[0] : null;\n return value ?? null;\n };\n\n const normalizedValue = getValue();\n const isSearch = type === 'search';\n const isCombobox = type === 'combobox';\n const isClearable = (Boolean(inputText) || Boolean(normalizedValue)) && !disabled;\n const isShortcutHotkeyEnabled = isSearch && shortcutHotkey && !normalizedValue && !disabled;\n const screenReaderOnlyId = useVisuallyHiddenId();\n\n const handleShortcutHotkeyFocus = useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n // Hotkey handling and display for Cmd/Ctrl + K\n const { hotkeyText } = useShortcutHotkey({\n enabled: isShortcutHotkeyEnabled,\n onTrigger: handleShortcutHotkeyFocus,\n });\n\n // Dynamic limit tags calculation\n const { rootRef, limitTags } = useDynamicLimitTags({\n chipMax: 130,\n gap: 4,\n horizontalPadding: 32,\n reservedPx: isSearch ? 120 : 90,\n });\n\n /**\n * Close the dropdown (if open) when:\n * - the component is dynamically disabled.\n * - if search mode and no options are provided.\n */\n useEffect(() => {\n if (!isOpen) return;\n if (disabled) setIsOpen(false);\n if (isSearch && options.length === 0) setIsOpen(false);\n }, [isOpen, disabled, isSearch, options.length]);\n\n /**\n * Toggles or sets the dropdown open state.\n * Does nothing when:\n * - the component is disabled.\n * - if search mode and no options are provided.\n *\n * @param open - Optional boolean to explicitly set open state; if undefined, toggles current state\n */\n const toggleOpen = (open?: boolean): void => {\n if (disabled) return;\n if (isSearch && options.length === 0) return;\n\n if (open !== undefined) {\n setIsOpen(open);\n return;\n }\n\n setIsOpen((prevOpen) => !prevOpen);\n };\n\n const renderSearchIcon = (): JSX.Element => {\n return (\n <StyledInputAdornment disabled={disabled} position=\"start\">\n <SearchIcon aria-hidden=\"true\" />\n </StyledInputAdornment>\n );\n };\n\n const renderPopupIcon = (): JSX.Element => {\n return (\n <StyledInputAdornment disabled={disabled} position=\"end\">\n {isOpen ? <ArrowUp01Icon /> : <ArrowDown01Icon />}\n </StyledInputAdornment>\n );\n };\n\n const renderShortcutHotkey = (): JSX.Element => {\n return (\n <ShortcutBadgeWrapper>\n <Badge label={hotkeyText} size=\"small\" tone=\"neutral\" />\n </ShortcutBadgeWrapper>\n );\n };\n\n const renderEndAdornment = (): React.ReactNode => {\n return (\n <StyledEndAdornmentContainer>\n {loading ? <CircularProgress size=\"small\" /> : null}\n {isShortcutHotkeyEnabled ? renderShortcutHotkey() : null}\n </StyledEndAdornmentContainer>\n );\n };\n\n const renderInputField = (params: AutocompleteRenderInputParams): JSX.Element => {\n const hasOptions = Array.isArray(options) && options.length > 0;\n const showPopup = isCombobox || (isSearch && hasOptions);\n const ariaDescribedBy =\n [params.inputProps['aria-describedby'], isShortcutHotkeyEnabled ? screenReaderOnlyId : undefined]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <TextField\n disabled={disabled}\n errorText={errorText}\n fdKey={fdKey}\n fullWidth={fullWidth}\n helperText={helperText}\n inputRef={inputRef}\n label={label}\n placeholder={placeholder}\n required={required}\n slotProps={{\n input: {\n ...params.InputProps,\n endAdornment: (\n <>\n {renderEndAdornment()}\n {params.InputProps.endAdornment}\n </>\n ),\n startAdornment: (\n <>\n {isSearch ? renderSearchIcon() : null}\n {params.InputProps.startAdornment}\n </>\n ),\n },\n htmlInput: {\n ...params.inputProps,\n id: fdKey,\n 'aria-label': isSearch && !label ? ariaLabel : undefined,\n 'aria-describedby': ariaDescribedBy,\n // If the popup is not shown, hide the autocomplete listbox functionality from screen readers\n ...(!showPopup && {\n role: 'searchbox',\n 'aria-autocomplete': 'none',\n 'aria-invalid': !errorText && !required ? undefined : params.inputProps['aria-invalid'],\n }),\n },\n }}\n />\n );\n };\n\n const renderMenuOption = (\n optionProps: React.HTMLAttributes<HTMLLIElement> & { key: React.Key },\n option: AutocompleteOption,\n state: AutocompleteRenderOptionState,\n ): JSX.Element => {\n const { key, onClick, ...rest } = optionProps;\n\n if (multiple) {\n return (\n <MenuItem\n {...rest}\n key={key}\n checked={state.selected}\n label={option.label}\n onCheckedChange={(_checked, e) => {\n onClick?.(e as React.MouseEvent<HTMLLIElement, MouseEvent>);\n }}\n type=\"checkbox\"\n />\n );\n }\n\n return (\n <MenuItem\n {...rest}\n key={key}\n label={option.label}\n onClick={onClick}\n selected={state.selected}\n type=\"text\"\n />\n );\n };\n\n const renderSelectedTags = (\n selected: AutocompleteOption[],\n getTagProps: AutocompleteRenderGetTagProps,\n ): React.ReactNode =>\n selected.map((tag, index) => {\n const { key, onDelete, ...tagProps } = getTagProps({ index });\n const rawLabel = typeof tag === 'string' ? tag : tag.label;\n const label = truncateWithEllipsis(rawLabel, 13, { includeEllipsisInLimit: true });\n const isTruncated = label.endsWith('...');\n const tagKey = key ?? `tag-${typeof tag === 'string' ? tag : tag.value}`;\n\n if (isTruncated) {\n return (\n <Tooltip key={tagKey} title={rawLabel}>\n <span {...tagProps}>\n <Tag dismissAriaLabel={translations.dismissTagAriaLabel} label={label} onDismiss={onDelete} />\n </span>\n </Tooltip>\n );\n }\n\n return (\n <span key={tagKey} {...tagProps}>\n <Tag dismissAriaLabel={translations.dismissTagAriaLabel} label={label} onDismiss={onDelete} />\n </span>\n );\n });\n\n const handlePopupIndicatorClick = (event: React.MouseEvent): void => {\n if (disabled) {\n return;\n }\n\n event.stopPropagation();\n toggleOpen();\n };\n\n const handleChange = (\n event: React.SyntheticEvent,\n value: AutocompleteValue<AutocompleteOption, boolean, boolean, boolean>,\n reason: AutocompleteChangeReason,\n details?: AutocompleteChangeDetails<AutocompleteOption>,\n ): void => {\n if (!onChange) {\n return;\n }\n onChange(event, value, reason, details);\n };\n\n const handleInputChange = (\n event: React.SyntheticEvent,\n value: string,\n reason: AutocompleteInputChangeReason,\n ): void => {\n setInputText(value);\n if (!onInputChange) {\n return;\n }\n onInputChange(event, value, reason);\n };\n\n /**\n * Returns all options without filtering for search mode.\n * Disables MUI's built-in client-side filtering when type is 'search'.\n */\n const disableClientFilter = (opts: AutocompleteOption[]): AutocompleteOption[] => opts;\n\n /**\n * Extracts the display label from an option.\n * Supports both object options and freeSolo string values.\n */\n const getOptionLabel = (option: AutocompleteOption | string): string => {\n return typeof option === 'string' ? option : option.label;\n };\n\n /**\n * Provides a stable unique key for each option to optimize DOM reconciliation.\n */\n const getOptionKey = (option: AutocompleteOption | string): string => {\n return typeof option === 'string' ? option : String(option.value);\n };\n\n /**\n * Determines equality between an option and the current value.\n * Handles both freeSolo string values and object options to prevent selection glitches.\n */\n const getIsOptionEqualToValue = (a: AutocompleteOption, b: AutocompleteOption): boolean => {\n if (b === null || b === undefined) {\n return false;\n }\n return typeof b === 'string' ? a.label === b || String(a.value) === b : a.value === b.value;\n };\n\n return (\n <>\n <StyledAutocomplete\n ref={rootRef}\n className={className}\n clearIcon={<CancelIcon size=\"md\" />}\n clearText={translations.clearTextAriaLabel}\n disableClearable={!isClearable}\n disableCloseOnSelect={multiple}\n disabled={disabled}\n filterOptions={isSearch ? disableClientFilter : undefined}\n forcePopupIcon={isCombobox}\n freeSolo={isSearch}\n fullWidth={fullWidth}\n getOptionKey={getOptionKey}\n getOptionLabel={getOptionLabel}\n inputValue={inputText}\n isOptionEqualToValue={getIsOptionEqualToValue}\n limitTags={limitTags}\n loading={loading}\n loadingText={translations.loadingText}\n multiple={multiple}\n noOptionsText={translations.noOptionsText}\n onChange={handleChange}\n onClose={() => toggleOpen(false)}\n onInputChange={handleInputChange}\n onOpen={() => toggleOpen(true)}\n open={isOpen}\n openText={translations.openPopupAriaLabel}\n options={options}\n popupIcon={isCombobox ? renderPopupIcon() : null}\n renderInput={renderInputField}\n renderOption={renderMenuOption}\n renderTags={renderSelectedTags}\n slotProps={{\n popupIndicator: {\n onClick: handlePopupIndicatorClick,\n },\n }}\n value={normalizedValue}\n />\n\n {isShortcutHotkeyEnabled && (\n <VisuallyHidden fdKey=\"autocomplete-shortcut-hotkey\" id={screenReaderOnlyId}>\n {translations.shortcutHotkeyAriaDescription}\n </VisuallyHidden>\n )}\n </>\n );\n};\n\nexport default Autocomplete;\n"],"names":["MuiCustomAutocomplete","StyledAutocomplete","styled","shouldForwardProp","prop","fullWidth","width","StyledInputAdornment","MuiInputAdornment","theme","disabled","margin","color","palette","semantic","icon","StyledEndAdornmentContainer","Box","alignItems","display","gap","spacing","ShortcutBadgeWrapper","Autocomplete","ariaLabel","className","errorText","fdKey","helperText","label","loading","multiple","onChange","onInputChange","options","placeholder","required","shortcutHotkey","translations","type","value","inputRef","useRef","inputText","setInputText","useState","isOpen","setIsOpen","normalizedValue","Array","isArray","length","isSearch","isCombobox","isClearable","Boolean","isShortcutHotkeyEnabled","screenReaderOnlyId","useVisuallyHiddenId","handleShortcutHotkeyFocus","useCallback","current","focus","hotkeyText","useShortcutHotkey","enabled","onTrigger","rootRef","limitTags","useDynamicLimitTags","chipMax","horizontalPadding","reservedPx","useEffect","toggleOpen","open","undefined","prevOpen","_jsxs","_Fragment","children","_jsx","ref","clearIcon","CancelIcon","size","clearText","clearTextAriaLabel","disableClearable","disableCloseOnSelect","filterOptions","opts","forcePopupIcon","freeSolo","getOptionKey","option","String","getOptionLabel","inputValue","isOptionEqualToValue","a","b","loadingText","noOptionsText","event","reason","details","onClose","onOpen","openText","openPopupAriaLabel","popupIcon","position","ArrowUp01Icon","ArrowDown01Icon","renderInput","params","hasOptions","showPopup","ariaDescribedBy","inputProps","filter","join","TextField","slotProps","input","InputProps","endAdornment","CircularProgress","Badge","tone","startAdornment","SearchIcon","htmlInput","id","role","renderOption","optionProps","state","key","onClick","rest","_createElement","MenuItem","checked","selected","onCheckedChange","_checked","e","renderTags","getTagProps","map","tag","index","onDelete","tagProps","rawLabel","truncateWithEllipsis","includeEllipsisInLimit","isTruncated","endsWith","tagKey","Tooltip","title","Tag","dismissAriaLabel","dismissTagAriaLabel","onDismiss","popupIndicator","stopPropagation","VisuallyHidden","shortcutHotkeyAriaDescription"],"mappings":"g7BA6FA,MAAMA,EAAqB,EACrBC,EAAqBC,EAAAA,OAAOF,EAAuB,CACvDG,kBAAoBC,GAAkB,cAATA,GADJF,EAEC,EAAGG,aAAY,MAAO,CAChDC,MAAOD,EAAY,OAAS,uBAGxBE,EAAuBL,EAAAA,OAAOM,EAAmB,CACrDL,kBAAoBC,GAAkB,aAATA,GADFF,EAEF,EAAGO,QAAOC,YAAW,MAAO,CACrD,kCAAmC,CACjCC,OAAQ,GAGV,QAAS,CACPC,MAAOF,EACHD,EAAMI,QAAQC,SAASC,KAAK,iBAC5BN,EAAMI,QAAQC,SAASC,KAAK,oBAI9BC,EAA8Bd,EAAAA,OAAOe,EAAPf,EAAY,EAAGO,YAAO,CACxDS,WAAY,SACZC,QAAS,OACTC,IAAKX,EAAMY,QAAQ,OAGfC,EAAuBpB,EAAAA,OAAO,OAAPA,EAAe,KAAA,CAC1CiB,QAAS,cAGT,iBAAkB,CAChBA,QAAS,YAWAI,EAAe,EAC1BC,YACAC,YACAf,YAAW,EACXgB,YACAC,QACAtB,aAAY,EACZuB,aACAC,QACAC,WAAU,EACVC,YAAW,EACXC,WACAC,gBACAC,UAAU,GACVC,cACAC,YAAW,EACXC,kBAAiB,EACjBC,eACAC,OAAO,SACPC,YAEA,MAAMC,EAAWC,EAAAA,OAAyB,OACnCC,EAAWC,GAAgBC,EAAAA,SAAiB,KAC5CC,EAAQC,GAAaF,EAAAA,UAAkB,GAsBxCG,EAXAjB,EACEkB,MAAMC,QAAQV,GAAeA,EAC7BA,QAA8C,GAC3C,CAACA,GAINS,MAAMC,QAAQV,GAAeA,EAAMW,OAAS,EAAIX,EAAM,GAAK,KACxDA,GAAS,KAIZY,EAAoB,WAATb,EACXc,EAAsB,aAATd,EACbe,GAAeC,QAAQZ,IAAcY,QAAQP,MAAsBtC,EACnE8C,EAA0BJ,GAAYf,IAAmBW,IAAoBtC,EAC7E+C,EAAqBC,EAAAA,sBAErBC,EAA4BC,EAAAA,aAAY,KAC5CnB,EAASoB,SAASC,UACjB,KAGGC,WAAEA,GAAeC,oBAAkB,CACvCC,QAAST,EACTU,UAAWP,KAIPQ,QAAEA,EAAOC,UAAEA,GAAcC,sBAAoB,CACjDC,QAAS,IACTlD,IAAK,EACLmD,kBAAmB,GACnBC,WAAYpB,EAAW,IAAM,KAQ/BqB,EAAAA,WAAU,KACH3B,IACDpC,GAAUqC,GAAU,GACpBK,GAA+B,IAAnBlB,EAAQiB,QAAcJ,GAAU,MAC/C,CAACD,EAAQpC,EAAU0C,EAAUlB,EAAQiB,SAUxC,MAAMuB,GAAcC,IACdjE,GACA0C,GAA+B,IAAnBlB,EAAQiB,QAOxBJ,OALa6B,IAATD,EAKOE,IAAcA,EAJbF,IA2Nd,OACEG,EAAAA,KAAAC,WAAA,CAAAC,SAAA,CACEC,EAAAA,IAAChF,EAAkB,CACjBiF,IAAKf,EACL1C,UAAWA,EACX0D,UAAWF,EAAAA,IAACG,GAAWC,KAAK,OAC5BC,UAAWhD,EAAaiD,mBACxBC,kBAAmBlC,EACnBmC,qBAAsB1D,EACtBrB,SAAUA,EACVgF,cAAetC,EAtCQuC,GAAqDA,OAsC5Bf,EAChDgB,eAAgBvC,EAChBwC,SAAUzC,EACV/C,UAAWA,EACXyF,aA7BgBC,GACK,iBAAXA,EAAsBA,EAASC,OAAOD,EAAOvD,OA6BvDyD,eArCkBF,GACG,iBAAXA,EAAsBA,EAASA,EAAOlE,MAqChDqE,WAAYvD,EACZwD,qBAxB0B,CAACC,EAAuBC,IAClDA,UAGgB,iBAANA,EAAiBD,EAAEvE,QAAUwE,GAAKL,OAAOI,EAAE5D,SAAW6D,EAAID,EAAE5D,QAAU6D,EAAE7D,OAqBlF4B,UAAWA,EACXtC,QAASA,EACTwE,YAAahE,EAAagE,YAC1BvE,SAAUA,EACVwE,cAAejE,EAAaiE,cAC5BvE,SA/Ee,CACnBwE,EACAhE,EACAiE,EACAC,KAEK1E,GAGLA,EAASwE,EAAOhE,EAAOiE,EAAQC,IAuE3BC,QAAS,IAAMjC,IAAW,GAC1BzC,cArEoB,CACxBuE,EACAhE,EACAiE,KAEA7D,EAAaJ,GACRP,GAGLA,EAAcuE,EAAOhE,EAAOiE,IA6DxBG,OAAQ,IAAMlC,IAAW,GACzBC,KAAM7B,EACN+D,SAAUvE,EAAawE,mBACvB5E,QAASA,EACT6E,UAAW1D,EAxOb4B,EAAAA,IAAC1E,EAAoB,CAACG,SAAUA,EAAUsG,SAAS,MAAKhC,SACrDlC,EAASmC,EAAAA,IAACgC,EAAa,IAAMhC,EAAAA,IAACiC,EAAe,CAAA,KAuOF,KAC5CC,YAlNoBC,IACxB,MAAMC,EAAapE,MAAMC,QAAQhB,IAAYA,EAAQiB,OAAS,EACxDmE,EAAYjE,GAAeD,GAAYiE,EACvCE,EACJ,CAACH,EAAOI,WAAW,oBAAqBhE,EAA0BC,OAAqBmB,GACpF6C,OAAOlE,SACPmE,KAAK,WAAQ9C,EAElB,OACEK,EAAAA,IAAC0C,aACCjH,SAAUA,EACVgB,UAAWA,EACXC,MAAOA,EACPtB,UAAWA,EACXuB,WAAYA,EACZa,SAAUA,EACVZ,MAAOA,EACPM,YAAaA,EACbC,SAAUA,EACVwF,UAAW,CACTC,MAAO,IACFT,EAAOU,WACVC,aACEjD,EAAAA,KAAAC,WAAA,CAAAC,SAAA,CA9BRF,EAAAA,KAAC9D,EAA2B,CAAAgE,SAAA,CACzBlD,EAAUmD,EAAAA,IAAC+C,mBAAgB,CAAC3C,KAAK,UAAa,KAC9C7B,EAVHyB,EAAAA,IAAC3D,EAAoB,CAAA0D,SACnBC,EAAAA,IAACgD,EAAAA,MAAK,CAACpG,MAAOkC,EAAYsB,KAAK,QAAQ6C,KAAK,cASQ,QA8B3Cd,EAAOU,WAAWC,gBAGvBI,eACErD,EAAAA,KAAAC,EAAAA,SAAA,CAAAC,SAAA,CACG5B,EA7DX6B,EAAAA,IAAC1E,GAAqBG,SAAUA,EAAUsG,SAAS,QAAOhC,SACxDC,EAAAA,IAACmD,EAAU,CAAA,cAAa,WA4DiB,KAChChB,EAAOU,WAAWK,mBAIzBE,UAAW,IACNjB,EAAOI,WACVc,GAAI3G,EACJ,aAAcyB,IAAavB,EAAQL,OAAYoD,EAC/C,mBAAoB2C,MAEfD,GAAa,CAChBiB,KAAM,YACN,oBAAqB,OACrB,eAAiB7G,GAAcU,EAAuBgF,EAAOI,WAAW,qBAA9B5C,QAuKhD4D,aA/JmB,CACvBC,EACA1C,EACA2C,KAEA,MAAMC,IAAEA,EAAGC,QAAEA,KAAYC,GAASJ,EAElC,OAAI1G,EAEA+G,EAAAA,cAACC,EAAAA,SAAQ,IACHF,EACJF,IAAKA,EACLK,QAASN,EAAMO,SACfpH,MAAOkE,EAAOlE,MACdqH,gBAAiB,CAACC,EAAUC,KAC1BR,IAAUQ,IAEZ7G,KAAK,aAMTuG,EAAAA,cAACC,EAAAA,SAAQ,IACHF,EACJF,IAAKA,EACL9G,MAAOkE,EAAOlE,MACd+G,QAASA,EACTK,SAAUP,EAAMO,SAChB1G,KAAK,UAmIL8G,WA9HqB,CACzBJ,EACAK,IAEAL,EAASM,KAAI,CAACC,EAAKC,KACjB,MAAMd,IAAEA,EAAGe,SAAEA,KAAaC,GAAaL,EAAY,CAAEG,UAC/CG,EAA0B,iBAARJ,EAAmBA,EAAMA,EAAI3H,MAC/CA,EAAQgI,EAAAA,qBAAqBD,EAAU,GAAI,CAAEE,wBAAwB,IACrEC,EAAclI,EAAMmI,SAAS,OAC7BC,EAAStB,GAAO,OAAsB,iBAARa,EAAmBA,EAAMA,EAAIhH,QAEjE,OAAIuH,EAEA9E,MAACiF,EAAAA,QAAO,CAAcC,MAAOP,EAAQ5E,SACnCC,EAAAA,IAAA,OAAA,IAAU0E,EAAQ3E,SAChBC,EAAAA,IAACmF,EAAAA,KAAIC,iBAAkB/H,EAAagI,oBAAqBzI,MAAOA,EAAO0I,UAAWb,OAFxEO,GAShBhF,EAAAA,IAAA,OAAA,IAAuB0E,EAAQ3E,SAC7BC,EAAAA,IAACmF,EAAAA,IAAG,CAACC,iBAAkB/H,EAAagI,oBAAqBzI,MAAOA,EAAO0I,UAAWb,KADzEO,MAyGXrC,UAAW,CACT4C,eAAgB,CACd5B,QArGyBpC,IAC7B9F,IAIJ8F,EAAMiE,kBACN/F,SAkGIlC,MAAOQ,IAGRQ,GACCyB,EAAAA,IAACyF,EAAAA,eAAc,CAAC/I,MAAM,+BAA+B2G,GAAI7E,EAAkBuB,SACxE1C,EAAaqI"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/molecules/Autocomplete/index.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport MuiAutocomplete, {\n type AutocompleteChangeDetails,\n type AutocompleteChangeReason,\n type AutocompleteInputChangeReason,\n type AutocompleteProps as MuiAutocompleteProps,\n type AutocompleteRenderGetTagProps,\n type AutocompleteRenderInputParams,\n type AutocompleteRenderOptionState,\n type AutocompleteValue,\n} from '@mui/material/Autocomplete';\nimport Box from '@mui/material/Box';\nimport MuiInputAdornment from '@mui/material/InputAdornment';\nimport { styled } from '@mui/material/styles';\n\nimport Badge from '@fd/components/atoms/Badge';\nimport CircularProgress from '@fd/components/atoms/CircularProgress';\nimport MenuItem from '@fd/components/atoms/MenuItem';\nimport Tag from '@fd/components/atoms/Tag';\nimport TextField, { type TextFieldProps } from '@fd/components/atoms/TextField';\nimport VisuallyHidden, { useVisuallyHiddenId } from '@fd/components/atoms/VisuallyHidden';\nimport Tooltip from '@fd/components/molecules/Tooltip';\nimport ArrowDown01Icon from '@fd/icons/ArrowDown01';\nimport ArrowUp01Icon from '@fd/icons/ArrowUp01';\nimport CancelIcon from '@fd/icons/Cancel';\nimport SearchIcon from '@fd/icons/Search';\nimport { useTranslation } from '@fd/providers/TranslationProvider';\nimport { truncateWithEllipsis } from '@fd/utilities/stringUtilities';\n\nimport { useDynamicLimitTags } from './hooks/useDynamicLimitTags';\nimport { useShortcutHotkey } from './hooks/useShortcutHotkey';\n\n// Bind flags to MuiAutocomplete\ntype MuiCustomAutocompleteProps<\n M extends boolean = boolean, // Multiple\n DC extends boolean = boolean, // DisableClearable\n FS extends boolean = boolean, // FreeSolo\n> = MuiAutocompleteProps<AutocompleteOption, M, DC, FS>;\n\n/**\n * Represents an option in the Autocomplete dropdown.\n */\nexport interface AutocompleteOption {\n /** The label to display in the dropdown option. */\n label: string;\n /** The value to store in the dropdown option. */\n value: number | string;\n}\n\n/**\n * Props for the Autocomplete component.\n * Supports both single and multiple selection modes with optional search functionality.\n */\nexport interface AutocompleteProps extends Omit<\n TextFieldProps,\n 'endAdornment' | 'multiline' | 'onChange' | 'options' | 'startAdornment'\n> {\n /** Aria-label for the input when no label is provided. */\n ariaLabel?: string;\n /** Shows a loading indicator inside the input (e.g., while fetching). */\n loading?: boolean;\n /** Enables selection of multiple options and shows checkboxes and tags for selected values. */\n multiple?: MuiCustomAutocompleteProps['multiple'];\n /** Called when the selected value(s) change. */\n onChange: MuiCustomAutocompleteProps['onChange'];\n /** Called when the input text changes (typing or programmatic updates). */\n onInputChange?: MuiCustomAutocompleteProps['onInputChange'];\n /** Options to display in the dropdown list. */\n options: AutocompleteOption[];\n /** Shows the keyboard shortcut badge (Cmd/Ctrl + K) and enables focusing via the shortcut when in search mode. */\n shortcutHotkey?: boolean;\n /** Visual behavior: 'search' shows a leading search icon; 'combobox' shows a popup button. */\n type?: 'combobox' | 'search';\n /** Controlled value (single option, array for multiple, or null). */\n value: MuiCustomAutocompleteProps['value'];\n}\n\n// Bind flags to MuiAutocomplete, see MuiCustomAutocompleteProps for more details\nconst MuiCustomAutocomplete = MuiAutocomplete<AutocompleteOption, boolean, boolean, boolean>;\nconst StyledAutocomplete = styled(MuiCustomAutocomplete, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ fullWidth = false }) => ({\n width: fullWidth ? '100%' : 'min(364px, 100%)',\n}));\n\nconst StyledInputAdornment = styled(MuiInputAdornment, {\n shouldForwardProp: (prop) => prop !== 'disabled',\n})<{ disabled?: boolean }>(({ theme, disabled = false }) => ({\n '&.MuiInputAdornment-positionEnd': {\n margin: 0,\n },\n\n '& svg': {\n color: disabled\n ? theme.palette.semantic.icon['icon-disabled']\n : theme.palette.semantic.icon['icon-strong'],\n },\n}));\n\nconst StyledEndAdornmentContainer = styled(Box)(({ theme }) => ({\n alignItems: 'center',\n display: 'flex',\n gap: theme.spacing(1),\n}));\n\nconst ShortcutBadgeWrapper = styled('span')(() => ({\n display: 'inline-flex',\n\n // hide when input root is focused\n '.Mui-focused &': {\n display: 'none',\n },\n}));\n\n/**\n * A customizable Autocomplete component supporting search and combobox modes.\n * Supports single and multiple selection with dynamic tag rendering and optional loading states.\n *\n * @param props - The component props\n * @returns The rendered Autocomplete component\n */\nexport const Autocomplete = ({\n ariaLabel,\n className,\n disabled = false,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n label,\n loading = false,\n multiple = false,\n onChange,\n onInputChange,\n options = [],\n placeholder,\n required = false,\n shortcutHotkey = false,\n type = 'search',\n value,\n}: AutocompleteProps): JSX.Element => {\n const inputRef = useRef<HTMLInputElement>(null);\n const [inputText, setInputText] = useState<string>('');\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const { translate } = useTranslation();\n\n /**\n * Normalizes the value prop for MUI Autocomplete.\n * Handles both single and multiple selection modes, ensuring the value\n * format matches the mode (array for multiple, single value/null for single).\n *\n * @returns Normalized value compatible with MUI Autocomplete\n */\n const getValue = (): AutocompleteProps['value'] => {\n // Multiple value selection\n if (multiple) {\n if (Array.isArray(value)) return value;\n if (value === null || value === undefined) return [];\n return [value as AutocompleteOption];\n }\n\n // Single value selection\n if (Array.isArray(value)) return value.length > 0 ? value[0] : null;\n return value ?? null;\n };\n\n const normalizedValue = getValue();\n const isSearch = type === 'search';\n const isCombobox = type === 'combobox';\n const isClearable = (Boolean(inputText) || Boolean(normalizedValue)) && !disabled;\n const isShortcutHotkeyEnabled = isSearch && shortcutHotkey && !normalizedValue && !disabled;\n const screenReaderOnlyId = useVisuallyHiddenId();\n\n const handleShortcutHotkeyFocus = useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n // Hotkey handling and display for Cmd/Ctrl + K\n const { hotkeyText } = useShortcutHotkey({\n enabled: isShortcutHotkeyEnabled,\n onTrigger: handleShortcutHotkeyFocus,\n });\n\n // Dynamic limit tags calculation\n const { rootRef, limitTags } = useDynamicLimitTags({\n chipMax: 130,\n gap: 4,\n horizontalPadding: 32,\n reservedPx: isSearch ? 120 : 90,\n });\n\n /**\n * Close the dropdown (if open) when:\n * - the component is dynamically disabled.\n * - if search mode and no options are provided.\n */\n useEffect(() => {\n if (!isOpen) return;\n if (disabled) setIsOpen(false);\n if (isSearch && options.length === 0) setIsOpen(false);\n }, [isOpen, disabled, isSearch, options.length]);\n\n /**\n * Toggles or sets the dropdown open state.\n * Does nothing when:\n * - the component is disabled.\n * - if search mode and no options are provided.\n *\n * @param open - Optional boolean to explicitly set open state; if undefined, toggles current state\n */\n const toggleOpen = (open?: boolean): void => {\n if (disabled) return;\n if (isSearch && options.length === 0) return;\n\n if (open !== undefined) {\n setIsOpen(open);\n return;\n }\n\n setIsOpen((prevOpen) => !prevOpen);\n };\n\n const renderSearchIcon = (): JSX.Element => {\n return (\n <StyledInputAdornment disabled={disabled} position=\"start\">\n <SearchIcon aria-hidden=\"true\" data-testid=\"search-icon\" />\n </StyledInputAdornment>\n );\n };\n\n const renderPopupIcon = (): JSX.Element => {\n return (\n <StyledInputAdornment disabled={disabled} position=\"end\">\n {isOpen ? <ArrowUp01Icon /> : <ArrowDown01Icon />}\n </StyledInputAdornment>\n );\n };\n\n const renderShortcutHotkey = (): JSX.Element => {\n return (\n <ShortcutBadgeWrapper>\n <Badge label={hotkeyText} size=\"small\" tone=\"neutral\" />\n </ShortcutBadgeWrapper>\n );\n };\n\n const renderEndAdornment = (): React.ReactNode => {\n return (\n <StyledEndAdornmentContainer>\n {loading ? <CircularProgress size=\"small\" /> : null}\n {isShortcutHotkeyEnabled ? renderShortcutHotkey() : null}\n </StyledEndAdornmentContainer>\n );\n };\n\n const renderInputField = (params: AutocompleteRenderInputParams): JSX.Element => {\n const hasOptions = Array.isArray(options) && options.length > 0;\n const showPopup = isCombobox || (isSearch && hasOptions);\n const ariaDescribedBy =\n [params.inputProps['aria-describedby'], isShortcutHotkeyEnabled ? screenReaderOnlyId : undefined]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <TextField\n disabled={disabled}\n errorText={errorText}\n fdKey={fdKey}\n fullWidth={fullWidth}\n helperText={helperText}\n inputRef={inputRef}\n label={label}\n placeholder={placeholder}\n required={required}\n slotProps={{\n input: {\n ...params.InputProps,\n endAdornment: (\n <>\n {renderEndAdornment()}\n {params.InputProps.endAdornment}\n </>\n ),\n startAdornment: (\n <>\n {isSearch ? renderSearchIcon() : null}\n {params.InputProps.startAdornment}\n </>\n ),\n },\n htmlInput: {\n ...params.inputProps,\n id: fdKey,\n 'aria-label': isSearch && !label ? ariaLabel : undefined,\n 'aria-describedby': ariaDescribedBy,\n // If the popup is not shown, hide the autocomplete listbox functionality from screen readers\n ...(!showPopup && {\n role: 'searchbox',\n 'aria-autocomplete': 'none',\n 'aria-invalid': !errorText && !required ? undefined : params.inputProps['aria-invalid'],\n }),\n },\n }}\n />\n );\n };\n\n const renderMenuOption = (\n optionProps: React.HTMLAttributes<HTMLLIElement> & { key: React.Key },\n option: AutocompleteOption,\n state: AutocompleteRenderOptionState,\n ): JSX.Element => {\n const { key, onClick, ...rest } = optionProps;\n\n if (multiple) {\n return (\n <MenuItem\n {...rest}\n key={key}\n checked={state.selected}\n label={option.label}\n onCheckedChange={(_checked, e) => {\n onClick?.(e as React.MouseEvent<HTMLLIElement, MouseEvent>);\n }}\n type=\"checkbox\"\n />\n );\n }\n\n return (\n <MenuItem\n {...rest}\n key={key}\n label={option.label}\n onClick={onClick}\n selected={state.selected}\n type=\"text\"\n />\n );\n };\n\n const renderSelectedTags = (\n selected: AutocompleteOption[],\n getTagProps: AutocompleteRenderGetTagProps,\n ): React.ReactNode =>\n selected.map((tag, index) => {\n const { key, onDelete, ...tagProps } = getTagProps({ index });\n const rawLabel = typeof tag === 'string' ? tag : tag.label;\n const label = truncateWithEllipsis(rawLabel, 13, { includeEllipsisInLimit: true });\n const isTruncated = label.endsWith('...');\n const tagKey = key ?? `tag-${typeof tag === 'string' ? tag : tag.value}`;\n\n if (isTruncated) {\n return (\n <Tooltip key={tagKey} title={rawLabel}>\n <span {...tagProps}>\n <Tag label={label} onDismiss={onDelete} />\n </span>\n </Tooltip>\n );\n }\n\n return (\n <span key={tagKey} {...tagProps}>\n <Tag label={label} onDismiss={onDelete} />\n </span>\n );\n });\n\n const handlePopupIndicatorClick = (event: React.MouseEvent): void => {\n if (disabled) {\n return;\n }\n\n event.stopPropagation();\n toggleOpen();\n };\n\n const handleChange = (\n event: React.SyntheticEvent,\n value: AutocompleteValue<AutocompleteOption, boolean, boolean, boolean>,\n reason: AutocompleteChangeReason,\n details?: AutocompleteChangeDetails<AutocompleteOption>,\n ): void => {\n if (!onChange) {\n return;\n }\n onChange(event, value, reason, details);\n };\n\n const handleInputChange = (\n event: React.SyntheticEvent,\n value: string,\n reason: AutocompleteInputChangeReason,\n ): void => {\n setInputText(value);\n if (!onInputChange) {\n return;\n }\n onInputChange(event, value, reason);\n };\n\n /**\n * Returns all options without filtering for search mode.\n * Disables MUI's built-in client-side filtering when type is 'search'.\n */\n const disableClientFilter = (opts: AutocompleteOption[]): AutocompleteOption[] => opts;\n\n /**\n * Extracts the display label from an option.\n * Supports both object options and freeSolo string values.\n */\n const getOptionLabel = (option: AutocompleteOption | string): string => {\n return typeof option === 'string' ? option : option.label;\n };\n\n /**\n * Provides a stable unique key for each option to optimize DOM reconciliation.\n */\n const getOptionKey = (option: AutocompleteOption | string): string => {\n return typeof option === 'string' ? option : String(option.value);\n };\n\n /**\n * Determines equality between an option and the current value.\n * Handles both freeSolo string values and object options to prevent selection glitches.\n */\n const getIsOptionEqualToValue = (a: AutocompleteOption, b: AutocompleteOption): boolean => {\n if (b === null || b === undefined) {\n return false;\n }\n return typeof b === 'string' ? a.label === b || String(a.value) === b : a.value === b.value;\n };\n\n return (\n <>\n <StyledAutocomplete\n ref={rootRef}\n className={className}\n clearIcon={<CancelIcon size=\"md\" />}\n clearText={translate('Clear_selection')}\n disableClearable={!isClearable}\n disableCloseOnSelect={multiple}\n disabled={disabled}\n filterOptions={isSearch ? disableClientFilter : undefined}\n forcePopupIcon={isCombobox}\n freeSolo={isSearch}\n fullWidth={fullWidth}\n getOptionKey={getOptionKey}\n getOptionLabel={getOptionLabel}\n inputValue={inputText}\n isOptionEqualToValue={getIsOptionEqualToValue}\n limitTags={limitTags}\n loading={loading}\n loadingText={`${translate('Loading')}...`}\n multiple={multiple}\n noOptionsText={translate('No_options')}\n onChange={handleChange}\n onClose={() => toggleOpen(false)}\n onInputChange={handleInputChange}\n onOpen={() => toggleOpen(true)}\n open={isOpen}\n openText={translate('Open_popup')}\n options={options}\n popupIcon={isCombobox ? renderPopupIcon() : null}\n renderInput={renderInputField}\n renderOption={renderMenuOption}\n renderTags={renderSelectedTags}\n slotProps={{\n popupIndicator: {\n onClick: handlePopupIndicatorClick,\n },\n }}\n value={normalizedValue}\n />\n\n {isShortcutHotkeyEnabled && (\n <VisuallyHidden fdKey=\"autocomplete-shortcut-hotkey\" id={screenReaderOnlyId}>\n {translate('Press_hotkey_to_focus_search', { hotkey: hotkeyText })}\n </VisuallyHidden>\n )}\n </>\n );\n};\n\nexport default Autocomplete;\n"],"names":["MuiCustomAutocomplete","StyledAutocomplete","styled","shouldForwardProp","prop","fullWidth","width","StyledInputAdornment","MuiInputAdornment","theme","disabled","margin","color","palette","semantic","icon","StyledEndAdornmentContainer","Box","alignItems","display","gap","spacing","ShortcutBadgeWrapper","Autocomplete","ariaLabel","className","errorText","fdKey","helperText","label","loading","multiple","onChange","onInputChange","options","placeholder","required","shortcutHotkey","type","value","inputRef","useRef","inputText","setInputText","useState","isOpen","setIsOpen","translate","useTranslation","normalizedValue","Array","isArray","length","isSearch","isCombobox","isClearable","Boolean","isShortcutHotkeyEnabled","screenReaderOnlyId","useVisuallyHiddenId","handleShortcutHotkeyFocus","useCallback","current","focus","hotkeyText","useShortcutHotkey","enabled","onTrigger","rootRef","limitTags","useDynamicLimitTags","chipMax","horizontalPadding","reservedPx","useEffect","toggleOpen","open","undefined","prevOpen","_jsxs","_Fragment","children","_jsx","ref","clearIcon","CancelIcon","size","clearText","disableClearable","disableCloseOnSelect","filterOptions","opts","forcePopupIcon","freeSolo","getOptionKey","option","String","getOptionLabel","inputValue","isOptionEqualToValue","a","b","loadingText","noOptionsText","event","reason","details","onClose","onOpen","openText","popupIcon","position","ArrowUp01Icon","ArrowDown01Icon","renderInput","params","hasOptions","showPopup","ariaDescribedBy","inputProps","filter","join","TextField","slotProps","input","InputProps","endAdornment","CircularProgress","Badge","tone","startAdornment","SearchIcon","htmlInput","id","role","renderOption","optionProps","state","key","onClick","rest","_createElement","MenuItem","checked","selected","onCheckedChange","_checked","e","renderTags","getTagProps","map","tag","index","onDelete","tagProps","rawLabel","truncateWithEllipsis","includeEllipsisInLimit","isTruncated","endsWith","tagKey","Tooltip","title","Tag","onDismiss","popupIndicator","stopPropagation","VisuallyHidden","hotkey"],"mappings":"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"}
|
|
@@ -32,21 +32,6 @@ interface AutocompleteProps extends Omit<TextFieldProps, 'endAdornment' | 'multi
|
|
|
32
32
|
options: AutocompleteOption[];
|
|
33
33
|
/** Shows the keyboard shortcut badge (Cmd/Ctrl + K) and enables focusing via the shortcut when in search mode. */
|
|
34
34
|
shortcutHotkey?: boolean;
|
|
35
|
-
/** UI and accessibility labels used by the component. */
|
|
36
|
-
translations: {
|
|
37
|
-
/** Aria-label for the clear button. */
|
|
38
|
-
clearTextAriaLabel: string;
|
|
39
|
-
/** Aria-label for the dismiss tag button. */
|
|
40
|
-
dismissTagAriaLabel: string;
|
|
41
|
-
/** Text shown while loading options. */
|
|
42
|
-
loadingText: string;
|
|
43
|
-
/** Text shown when there are no options to display. */
|
|
44
|
-
noOptionsText: string;
|
|
45
|
-
/** Aria-label for the popup indicator button. */
|
|
46
|
-
openPopupAriaLabel: string;
|
|
47
|
-
/** Screen reader hint describing the shortcut, e.g., "Press ⌘+K to focus search". */
|
|
48
|
-
shortcutHotkeyAriaDescription: string;
|
|
49
|
-
};
|
|
50
35
|
/** Visual behavior: 'search' shows a leading search icon; 'combobox' shows a popup button. */
|
|
51
36
|
type?: 'combobox' | 'search';
|
|
52
37
|
/** Controlled value (single option, array for multiple, or null). */
|
|
@@ -59,7 +44,7 @@ interface AutocompleteProps extends Omit<TextFieldProps, 'endAdornment' | 'multi
|
|
|
59
44
|
* @param props - The component props
|
|
60
45
|
* @returns The rendered Autocomplete component
|
|
61
46
|
*/
|
|
62
|
-
declare const Autocomplete: ({ ariaLabel, className, disabled, errorText, fdKey, fullWidth, helperText, label, loading, multiple, onChange, onInputChange, options, placeholder, required, shortcutHotkey,
|
|
47
|
+
declare const Autocomplete: ({ ariaLabel, className, disabled, errorText, fdKey, fullWidth, helperText, label, loading, multiple, onChange, onInputChange, options, placeholder, required, shortcutHotkey, type, value, }: AutocompleteProps) => JSX.Element;
|
|
63
48
|
|
|
64
49
|
export { Autocomplete, Autocomplete as default };
|
|
65
50
|
export type { AutocompleteOption, AutocompleteProps };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useRef as e,useState as
|
|
1
|
+
import{useRef as e,useState as o,useCallback as i,useEffect as t,createElement as r}from"react";import{jsxs as n,Fragment as l,jsx as a}from"react/jsx-runtime";import s from"@mui/material/Autocomplete";import d from"@mui/material/Box";import p from"@mui/material/InputAdornment";import{styled as m}from"@mui/material/styles";import{Badge as c}from"../../atoms/Badge/index.js";import{CircularProgress as u}from"../../atoms/CircularProgress/index.js";import{MenuItem as h}from"../../atoms/MenuItem/index.js";import{Tag as f}from"../../atoms/Tag/index.js";import{TextField as g}from"../../atoms/TextField/index.js";import{useVisuallyHiddenId as y,VisuallyHidden as b}from"../../atoms/VisuallyHidden/index.js";import{Tooltip as x}from"../Tooltip/index.js";import v from"../../../icons/ArrowDown01/index.js";import T from"../../../icons/ArrowUp01/index.js";import k from"../../../icons/Cancel/index.js";import j from"../../../icons/Search/index.js";import{useTranslation as P}from"../../../providers/TranslationProvider.js";import{truncateWithEllipsis as I}from"../../../utilities/stringUtilities.js";import{useDynamicLimitTags as A}from"./hooks/useDynamicLimitTags.js";import{useShortcutHotkey as C}from"./hooks/useShortcutHotkey.js";const O=m(s,{shouldForwardProp:e=>"fullWidth"!==e})((({fullWidth:e=!1})=>({width:e?"100%":"min(364px, 100%)"}))),_=m(p,{shouldForwardProp:e=>"disabled"!==e})((({theme:e,disabled:o=!1})=>({"&.MuiInputAdornment-positionEnd":{margin:0},"& svg":{color:o?e.palette.semantic.icon["icon-disabled"]:e.palette.semantic.icon["icon-strong"]}}))),w=m(d)((({theme:e})=>({alignItems:"center",display:"flex",gap:e.spacing(1)}))),S=m("span")((()=>({display:"inline-flex",".Mui-focused &":{display:"none"}}))),W=({ariaLabel:s,className:d,disabled:p=!1,errorText:m,fdKey:W,fullWidth:B=!1,helperText:D,label:L,loading:z=!1,multiple:K=!1,onChange:M,onInputChange:q,options:E=[],placeholder:F,required:H=!1,shortcutHotkey:N=!1,type:V="search",value:R})=>{const U=e(null),[$,G]=o(""),[J,Q]=o(!1),{translate:X}=P(),Y=K?Array.isArray(R)?R:null==R?[]:[R]:Array.isArray(R)?R.length>0?R[0]:null:R??null,Z="search"===V,ee="combobox"===V,oe=(Boolean($)||Boolean(Y))&&!p,ie=Z&&N&&!Y&&!p,te=y(),re=i((()=>{U.current?.focus()}),[]),{hotkeyText:ne}=C({enabled:ie,onTrigger:re}),{rootRef:le,limitTags:ae}=A({chipMax:130,gap:4,horizontalPadding:32,reservedPx:Z?120:90});t((()=>{J&&(p&&Q(!1),Z&&0===E.length&&Q(!1))}),[J,p,Z,E.length]);const se=e=>{p||Z&&0===E.length||Q(void 0===e?e=>!e:e)};return n(l,{children:[a(O,{ref:le,className:d,clearIcon:a(k,{size:"md"}),clearText:X("Clear_selection"),disableClearable:!oe,disableCloseOnSelect:K,disabled:p,filterOptions:Z?e=>e:void 0,forcePopupIcon:ee,freeSolo:Z,fullWidth:B,getOptionKey:e=>"string"==typeof e?e:String(e.value),getOptionLabel:e=>"string"==typeof e?e:e.label,inputValue:$,isOptionEqualToValue:(e,o)=>null!=o&&("string"==typeof o?e.label===o||String(e.value)===o:e.value===o.value),limitTags:ae,loading:z,loadingText:`${X("Loading")}...`,multiple:K,noOptionsText:X("No_options"),onChange:(e,o,i,t)=>{M&&M(e,o,i,t)},onClose:()=>se(!1),onInputChange:(e,o,i)=>{G(o),q&&q(e,o,i)},onOpen:()=>se(!0),open:J,openText:X("Open_popup"),options:E,popupIcon:ee?a(_,{disabled:p,position:"end",children:a(J?T:v,{})}):null,renderInput:e=>{const o=Array.isArray(E)&&E.length>0,i=ee||Z&&o,t=[e.inputProps["aria-describedby"],ie?te:void 0].filter(Boolean).join(" ")||void 0;return a(g,{disabled:p,errorText:m,fdKey:W,fullWidth:B,helperText:D,inputRef:U,label:L,placeholder:F,required:H,slotProps:{input:{...e.InputProps,endAdornment:n(l,{children:[n(w,{children:[z?a(u,{size:"small"}):null,ie?a(S,{children:a(c,{label:ne,size:"small",tone:"neutral"})}):null]}),e.InputProps.endAdornment]}),startAdornment:n(l,{children:[Z?a(_,{disabled:p,position:"start",children:a(j,{"aria-hidden":"true","data-testid":"search-icon"})}):null,e.InputProps.startAdornment]})},htmlInput:{...e.inputProps,id:W,"aria-label":Z&&!L?s:void 0,"aria-describedby":t,...!i&&{role:"searchbox","aria-autocomplete":"none","aria-invalid":m||H?e.inputProps["aria-invalid"]:void 0}}}})},renderOption:(e,o,i)=>{const{key:t,onClick:n,...l}=e;return r(h,K?{...l,key:t,checked:i.selected,label:o.label,onCheckedChange:(e,o)=>{n?.(o)},type:"checkbox"}:{...l,key:t,label:o.label,onClick:n,selected:i.selected,type:"text"})},renderTags:(e,o)=>e.map(((e,i)=>{const{key:t,onDelete:r,...n}=o({index:i}),l="string"==typeof e?e:e.label,s=I(l,13,{includeEllipsisInLimit:!0}),d=s.endsWith("..."),p=t??`tag-${"string"==typeof e?e:e.value}`;return d?a(x,{title:l,children:a("span",{...n,children:a(f,{label:s,onDismiss:r})})},p):a("span",{...n,children:a(f,{label:s,onDismiss:r})},p)})),slotProps:{popupIndicator:{onClick:e=>{p||(e.stopPropagation(),se())}}},value:Y}),ie&&a(b,{fdKey:"autocomplete-shortcut-hotkey",id:te,children:X("Press_hotkey_to_focus_search",{hotkey:ne})})]})};export{W as Autocomplete,W as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/components/molecules/Autocomplete/index.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport MuiAutocomplete, {\n type AutocompleteChangeDetails,\n type AutocompleteChangeReason,\n type AutocompleteInputChangeReason,\n type AutocompleteProps as MuiAutocompleteProps,\n type AutocompleteRenderGetTagProps,\n type AutocompleteRenderInputParams,\n type AutocompleteRenderOptionState,\n type AutocompleteValue,\n} from '@mui/material/Autocomplete';\nimport Box from '@mui/material/Box';\nimport MuiInputAdornment from '@mui/material/InputAdornment';\nimport { styled } from '@mui/material/styles';\n\nimport Badge from '@fd/components/atoms/Badge';\nimport CircularProgress from '@fd/components/atoms/CircularProgress';\nimport MenuItem from '@fd/components/atoms/MenuItem';\nimport Tag from '@fd/components/atoms/Tag';\nimport TextField, { type TextFieldProps } from '@fd/components/atoms/TextField';\nimport VisuallyHidden, { useVisuallyHiddenId } from '@fd/components/atoms/VisuallyHidden';\nimport Tooltip from '@fd/components/molecules/Tooltip';\nimport ArrowDown01Icon from '@fd/icons/ArrowDown01';\nimport ArrowUp01Icon from '@fd/icons/ArrowUp01';\nimport CancelIcon from '@fd/icons/Cancel';\nimport SearchIcon from '@fd/icons/Search';\nimport { truncateWithEllipsis } from '@fd/utilities/stringUtilities';\n\nimport { useDynamicLimitTags } from './hooks/useDynamicLimitTags';\nimport { useShortcutHotkey } from './hooks/useShortcutHotkey';\n\n// Bind flags to MuiAutocomplete\ntype MuiCustomAutocompleteProps<\n M extends boolean = boolean, // Multiple\n DC extends boolean = boolean, // DisableClearable\n FS extends boolean = boolean, // FreeSolo\n> = MuiAutocompleteProps<AutocompleteOption, M, DC, FS>;\n\n/**\n * Represents an option in the Autocomplete dropdown.\n */\nexport interface AutocompleteOption {\n /** The label to display in the dropdown option. */\n label: string;\n /** The value to store in the dropdown option. */\n value: number | string;\n}\n\n/**\n * Props for the Autocomplete component.\n * Supports both single and multiple selection modes with optional search functionality.\n */\nexport interface AutocompleteProps extends Omit<\n TextFieldProps,\n 'endAdornment' | 'multiline' | 'onChange' | 'options' | 'startAdornment'\n> {\n /** Aria-label for the input when no label is provided. */\n ariaLabel?: string;\n /** Shows a loading indicator inside the input (e.g., while fetching). */\n loading?: boolean;\n /** Enables selection of multiple options and shows checkboxes and tags for selected values. */\n multiple?: MuiCustomAutocompleteProps['multiple'];\n /** Called when the selected value(s) change. */\n onChange: MuiCustomAutocompleteProps['onChange'];\n /** Called when the input text changes (typing or programmatic updates). */\n onInputChange?: MuiCustomAutocompleteProps['onInputChange'];\n /** Options to display in the dropdown list. */\n options: AutocompleteOption[];\n /** Shows the keyboard shortcut badge (Cmd/Ctrl + K) and enables focusing via the shortcut when in search mode. */\n shortcutHotkey?: boolean;\n /** UI and accessibility labels used by the component. */\n translations: {\n /** Aria-label for the clear button. */\n clearTextAriaLabel: string;\n /** Aria-label for the dismiss tag button. */\n dismissTagAriaLabel: string;\n /** Text shown while loading options. */\n loadingText: string;\n /** Text shown when there are no options to display. */\n noOptionsText: string;\n /** Aria-label for the popup indicator button. */\n openPopupAriaLabel: string;\n /** Screen reader hint describing the shortcut, e.g., \"Press ⌘+K to focus search\". */\n shortcutHotkeyAriaDescription: string;\n };\n /** Visual behavior: 'search' shows a leading search icon; 'combobox' shows a popup button. */\n type?: 'combobox' | 'search';\n /** Controlled value (single option, array for multiple, or null). */\n value: MuiCustomAutocompleteProps['value'];\n}\n\n// Bind flags to MuiAutocomplete, see MuiCustomAutocompleteProps for more details\nconst MuiCustomAutocomplete = MuiAutocomplete<AutocompleteOption, boolean, boolean, boolean>;\nconst StyledAutocomplete = styled(MuiCustomAutocomplete, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ fullWidth = false }) => ({\n width: fullWidth ? '100%' : 'min(364px, 100%)',\n}));\n\nconst StyledInputAdornment = styled(MuiInputAdornment, {\n shouldForwardProp: (prop) => prop !== 'disabled',\n})<{ disabled?: boolean }>(({ theme, disabled = false }) => ({\n '&.MuiInputAdornment-positionEnd': {\n margin: 0,\n },\n\n '& svg': {\n color: disabled\n ? theme.palette.semantic.icon['icon-disabled']\n : theme.palette.semantic.icon['icon-strong'],\n },\n}));\n\nconst StyledEndAdornmentContainer = styled(Box)(({ theme }) => ({\n alignItems: 'center',\n display: 'flex',\n gap: theme.spacing(1),\n}));\n\nconst ShortcutBadgeWrapper = styled('span')(() => ({\n display: 'inline-flex',\n\n // hide when input root is focused\n '.Mui-focused &': {\n display: 'none',\n },\n}));\n\n/**\n * A customizable Autocomplete component supporting search and combobox modes.\n * Supports single and multiple selection with dynamic tag rendering and optional loading states.\n *\n * @param props - The component props\n * @returns The rendered Autocomplete component\n */\nexport const Autocomplete = ({\n ariaLabel,\n className,\n disabled = false,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n label,\n loading = false,\n multiple = false,\n onChange,\n onInputChange,\n options = [],\n placeholder,\n required = false,\n shortcutHotkey = false,\n translations,\n type = 'search',\n value,\n}: AutocompleteProps): JSX.Element => {\n const inputRef = useRef<HTMLInputElement>(null);\n const [inputText, setInputText] = useState<string>('');\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n /**\n * Normalizes the value prop for MUI Autocomplete.\n * Handles both single and multiple selection modes, ensuring the value\n * format matches the mode (array for multiple, single value/null for single).\n *\n * @returns Normalized value compatible with MUI Autocomplete\n */\n const getValue = (): AutocompleteProps['value'] => {\n // Multiple value selection\n if (multiple) {\n if (Array.isArray(value)) return value;\n if (value === null || value === undefined) return [];\n return [value as AutocompleteOption];\n }\n\n // Single value selection\n if (Array.isArray(value)) return value.length > 0 ? value[0] : null;\n return value ?? null;\n };\n\n const normalizedValue = getValue();\n const isSearch = type === 'search';\n const isCombobox = type === 'combobox';\n const isClearable = (Boolean(inputText) || Boolean(normalizedValue)) && !disabled;\n const isShortcutHotkeyEnabled = isSearch && shortcutHotkey && !normalizedValue && !disabled;\n const screenReaderOnlyId = useVisuallyHiddenId();\n\n const handleShortcutHotkeyFocus = useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n // Hotkey handling and display for Cmd/Ctrl + K\n const { hotkeyText } = useShortcutHotkey({\n enabled: isShortcutHotkeyEnabled,\n onTrigger: handleShortcutHotkeyFocus,\n });\n\n // Dynamic limit tags calculation\n const { rootRef, limitTags } = useDynamicLimitTags({\n chipMax: 130,\n gap: 4,\n horizontalPadding: 32,\n reservedPx: isSearch ? 120 : 90,\n });\n\n /**\n * Close the dropdown (if open) when:\n * - the component is dynamically disabled.\n * - if search mode and no options are provided.\n */\n useEffect(() => {\n if (!isOpen) return;\n if (disabled) setIsOpen(false);\n if (isSearch && options.length === 0) setIsOpen(false);\n }, [isOpen, disabled, isSearch, options.length]);\n\n /**\n * Toggles or sets the dropdown open state.\n * Does nothing when:\n * - the component is disabled.\n * - if search mode and no options are provided.\n *\n * @param open - Optional boolean to explicitly set open state; if undefined, toggles current state\n */\n const toggleOpen = (open?: boolean): void => {\n if (disabled) return;\n if (isSearch && options.length === 0) return;\n\n if (open !== undefined) {\n setIsOpen(open);\n return;\n }\n\n setIsOpen((prevOpen) => !prevOpen);\n };\n\n const renderSearchIcon = (): JSX.Element => {\n return (\n <StyledInputAdornment disabled={disabled} position=\"start\">\n <SearchIcon aria-hidden=\"true\" />\n </StyledInputAdornment>\n );\n };\n\n const renderPopupIcon = (): JSX.Element => {\n return (\n <StyledInputAdornment disabled={disabled} position=\"end\">\n {isOpen ? <ArrowUp01Icon /> : <ArrowDown01Icon />}\n </StyledInputAdornment>\n );\n };\n\n const renderShortcutHotkey = (): JSX.Element => {\n return (\n <ShortcutBadgeWrapper>\n <Badge label={hotkeyText} size=\"small\" tone=\"neutral\" />\n </ShortcutBadgeWrapper>\n );\n };\n\n const renderEndAdornment = (): React.ReactNode => {\n return (\n <StyledEndAdornmentContainer>\n {loading ? <CircularProgress size=\"small\" /> : null}\n {isShortcutHotkeyEnabled ? renderShortcutHotkey() : null}\n </StyledEndAdornmentContainer>\n );\n };\n\n const renderInputField = (params: AutocompleteRenderInputParams): JSX.Element => {\n const hasOptions = Array.isArray(options) && options.length > 0;\n const showPopup = isCombobox || (isSearch && hasOptions);\n const ariaDescribedBy =\n [params.inputProps['aria-describedby'], isShortcutHotkeyEnabled ? screenReaderOnlyId : undefined]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <TextField\n disabled={disabled}\n errorText={errorText}\n fdKey={fdKey}\n fullWidth={fullWidth}\n helperText={helperText}\n inputRef={inputRef}\n label={label}\n placeholder={placeholder}\n required={required}\n slotProps={{\n input: {\n ...params.InputProps,\n endAdornment: (\n <>\n {renderEndAdornment()}\n {params.InputProps.endAdornment}\n </>\n ),\n startAdornment: (\n <>\n {isSearch ? renderSearchIcon() : null}\n {params.InputProps.startAdornment}\n </>\n ),\n },\n htmlInput: {\n ...params.inputProps,\n id: fdKey,\n 'aria-label': isSearch && !label ? ariaLabel : undefined,\n 'aria-describedby': ariaDescribedBy,\n // If the popup is not shown, hide the autocomplete listbox functionality from screen readers\n ...(!showPopup && {\n role: 'searchbox',\n 'aria-autocomplete': 'none',\n 'aria-invalid': !errorText && !required ? undefined : params.inputProps['aria-invalid'],\n }),\n },\n }}\n />\n );\n };\n\n const renderMenuOption = (\n optionProps: React.HTMLAttributes<HTMLLIElement> & { key: React.Key },\n option: AutocompleteOption,\n state: AutocompleteRenderOptionState,\n ): JSX.Element => {\n const { key, onClick, ...rest } = optionProps;\n\n if (multiple) {\n return (\n <MenuItem\n {...rest}\n key={key}\n checked={state.selected}\n label={option.label}\n onCheckedChange={(_checked, e) => {\n onClick?.(e as React.MouseEvent<HTMLLIElement, MouseEvent>);\n }}\n type=\"checkbox\"\n />\n );\n }\n\n return (\n <MenuItem\n {...rest}\n key={key}\n label={option.label}\n onClick={onClick}\n selected={state.selected}\n type=\"text\"\n />\n );\n };\n\n const renderSelectedTags = (\n selected: AutocompleteOption[],\n getTagProps: AutocompleteRenderGetTagProps,\n ): React.ReactNode =>\n selected.map((tag, index) => {\n const { key, onDelete, ...tagProps } = getTagProps({ index });\n const rawLabel = typeof tag === 'string' ? tag : tag.label;\n const label = truncateWithEllipsis(rawLabel, 13, { includeEllipsisInLimit: true });\n const isTruncated = label.endsWith('...');\n const tagKey = key ?? `tag-${typeof tag === 'string' ? tag : tag.value}`;\n\n if (isTruncated) {\n return (\n <Tooltip key={tagKey} title={rawLabel}>\n <span {...tagProps}>\n <Tag dismissAriaLabel={translations.dismissTagAriaLabel} label={label} onDismiss={onDelete} />\n </span>\n </Tooltip>\n );\n }\n\n return (\n <span key={tagKey} {...tagProps}>\n <Tag dismissAriaLabel={translations.dismissTagAriaLabel} label={label} onDismiss={onDelete} />\n </span>\n );\n });\n\n const handlePopupIndicatorClick = (event: React.MouseEvent): void => {\n if (disabled) {\n return;\n }\n\n event.stopPropagation();\n toggleOpen();\n };\n\n const handleChange = (\n event: React.SyntheticEvent,\n value: AutocompleteValue<AutocompleteOption, boolean, boolean, boolean>,\n reason: AutocompleteChangeReason,\n details?: AutocompleteChangeDetails<AutocompleteOption>,\n ): void => {\n if (!onChange) {\n return;\n }\n onChange(event, value, reason, details);\n };\n\n const handleInputChange = (\n event: React.SyntheticEvent,\n value: string,\n reason: AutocompleteInputChangeReason,\n ): void => {\n setInputText(value);\n if (!onInputChange) {\n return;\n }\n onInputChange(event, value, reason);\n };\n\n /**\n * Returns all options without filtering for search mode.\n * Disables MUI's built-in client-side filtering when type is 'search'.\n */\n const disableClientFilter = (opts: AutocompleteOption[]): AutocompleteOption[] => opts;\n\n /**\n * Extracts the display label from an option.\n * Supports both object options and freeSolo string values.\n */\n const getOptionLabel = (option: AutocompleteOption | string): string => {\n return typeof option === 'string' ? option : option.label;\n };\n\n /**\n * Provides a stable unique key for each option to optimize DOM reconciliation.\n */\n const getOptionKey = (option: AutocompleteOption | string): string => {\n return typeof option === 'string' ? option : String(option.value);\n };\n\n /**\n * Determines equality between an option and the current value.\n * Handles both freeSolo string values and object options to prevent selection glitches.\n */\n const getIsOptionEqualToValue = (a: AutocompleteOption, b: AutocompleteOption): boolean => {\n if (b === null || b === undefined) {\n return false;\n }\n return typeof b === 'string' ? a.label === b || String(a.value) === b : a.value === b.value;\n };\n\n return (\n <>\n <StyledAutocomplete\n ref={rootRef}\n className={className}\n clearIcon={<CancelIcon size=\"md\" />}\n clearText={translations.clearTextAriaLabel}\n disableClearable={!isClearable}\n disableCloseOnSelect={multiple}\n disabled={disabled}\n filterOptions={isSearch ? disableClientFilter : undefined}\n forcePopupIcon={isCombobox}\n freeSolo={isSearch}\n fullWidth={fullWidth}\n getOptionKey={getOptionKey}\n getOptionLabel={getOptionLabel}\n inputValue={inputText}\n isOptionEqualToValue={getIsOptionEqualToValue}\n limitTags={limitTags}\n loading={loading}\n loadingText={translations.loadingText}\n multiple={multiple}\n noOptionsText={translations.noOptionsText}\n onChange={handleChange}\n onClose={() => toggleOpen(false)}\n onInputChange={handleInputChange}\n onOpen={() => toggleOpen(true)}\n open={isOpen}\n openText={translations.openPopupAriaLabel}\n options={options}\n popupIcon={isCombobox ? renderPopupIcon() : null}\n renderInput={renderInputField}\n renderOption={renderMenuOption}\n renderTags={renderSelectedTags}\n slotProps={{\n popupIndicator: {\n onClick: handlePopupIndicatorClick,\n },\n }}\n value={normalizedValue}\n />\n\n {isShortcutHotkeyEnabled && (\n <VisuallyHidden fdKey=\"autocomplete-shortcut-hotkey\" id={screenReaderOnlyId}>\n {translations.shortcutHotkeyAriaDescription}\n </VisuallyHidden>\n )}\n </>\n );\n};\n\nexport default Autocomplete;\n"],"names":["StyledAutocomplete","styled","shouldForwardProp","prop","fullWidth","width","StyledInputAdornment","MuiInputAdornment","theme","disabled","margin","color","palette","semantic","icon","StyledEndAdornmentContainer","Box","alignItems","display","gap","spacing","ShortcutBadgeWrapper","Autocomplete","ariaLabel","className","errorText","fdKey","helperText","label","loading","multiple","onChange","onInputChange","options","placeholder","required","shortcutHotkey","translations","type","value","inputRef","useRef","inputText","setInputText","useState","isOpen","setIsOpen","normalizedValue","Array","isArray","length","isSearch","isCombobox","isClearable","Boolean","isShortcutHotkeyEnabled","screenReaderOnlyId","useVisuallyHiddenId","handleShortcutHotkeyFocus","useCallback","current","focus","hotkeyText","useShortcutHotkey","enabled","onTrigger","rootRef","limitTags","useDynamicLimitTags","chipMax","horizontalPadding","reservedPx","useEffect","toggleOpen","open","undefined","prevOpen","_jsxs","_Fragment","children","_jsx","ref","clearIcon","CancelIcon","size","clearText","clearTextAriaLabel","disableClearable","disableCloseOnSelect","filterOptions","opts","forcePopupIcon","freeSolo","getOptionKey","option","String","getOptionLabel","inputValue","isOptionEqualToValue","a","b","loadingText","noOptionsText","event","reason","details","onClose","onOpen","openText","openPopupAriaLabel","popupIcon","position","ArrowUp01Icon","ArrowDown01Icon","renderInput","params","hasOptions","showPopup","ariaDescribedBy","inputProps","filter","join","TextField","slotProps","input","InputProps","endAdornment","CircularProgress","Badge","tone","startAdornment","SearchIcon","htmlInput","id","role","renderOption","optionProps","state","key","onClick","rest","_createElement","MenuItem","checked","selected","onCheckedChange","_checked","e","renderTags","getTagProps","map","tag","index","onDelete","tagProps","rawLabel","truncateWithEllipsis","includeEllipsisInLimit","isTruncated","endsWith","tagKey","Tooltip","title","Tag","dismissAriaLabel","dismissTagAriaLabel","onDismiss","popupIndicator","stopPropagation","VisuallyHidden","shortcutHotkeyAriaDescription"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/molecules/Autocomplete/index.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport MuiAutocomplete, {\n type AutocompleteChangeDetails,\n type AutocompleteChangeReason,\n type AutocompleteInputChangeReason,\n type AutocompleteProps as MuiAutocompleteProps,\n type AutocompleteRenderGetTagProps,\n type AutocompleteRenderInputParams,\n type AutocompleteRenderOptionState,\n type AutocompleteValue,\n} from '@mui/material/Autocomplete';\nimport Box from '@mui/material/Box';\nimport MuiInputAdornment from '@mui/material/InputAdornment';\nimport { styled } from '@mui/material/styles';\n\nimport Badge from '@fd/components/atoms/Badge';\nimport CircularProgress from '@fd/components/atoms/CircularProgress';\nimport MenuItem from '@fd/components/atoms/MenuItem';\nimport Tag from '@fd/components/atoms/Tag';\nimport TextField, { type TextFieldProps } from '@fd/components/atoms/TextField';\nimport VisuallyHidden, { useVisuallyHiddenId } from '@fd/components/atoms/VisuallyHidden';\nimport Tooltip from '@fd/components/molecules/Tooltip';\nimport ArrowDown01Icon from '@fd/icons/ArrowDown01';\nimport ArrowUp01Icon from '@fd/icons/ArrowUp01';\nimport CancelIcon from '@fd/icons/Cancel';\nimport SearchIcon from '@fd/icons/Search';\nimport { useTranslation } from '@fd/providers/TranslationProvider';\nimport { truncateWithEllipsis } from '@fd/utilities/stringUtilities';\n\nimport { useDynamicLimitTags } from './hooks/useDynamicLimitTags';\nimport { useShortcutHotkey } from './hooks/useShortcutHotkey';\n\n// Bind flags to MuiAutocomplete\ntype MuiCustomAutocompleteProps<\n M extends boolean = boolean, // Multiple\n DC extends boolean = boolean, // DisableClearable\n FS extends boolean = boolean, // FreeSolo\n> = MuiAutocompleteProps<AutocompleteOption, M, DC, FS>;\n\n/**\n * Represents an option in the Autocomplete dropdown.\n */\nexport interface AutocompleteOption {\n /** The label to display in the dropdown option. */\n label: string;\n /** The value to store in the dropdown option. */\n value: number | string;\n}\n\n/**\n * Props for the Autocomplete component.\n * Supports both single and multiple selection modes with optional search functionality.\n */\nexport interface AutocompleteProps extends Omit<\n TextFieldProps,\n 'endAdornment' | 'multiline' | 'onChange' | 'options' | 'startAdornment'\n> {\n /** Aria-label for the input when no label is provided. */\n ariaLabel?: string;\n /** Shows a loading indicator inside the input (e.g., while fetching). */\n loading?: boolean;\n /** Enables selection of multiple options and shows checkboxes and tags for selected values. */\n multiple?: MuiCustomAutocompleteProps['multiple'];\n /** Called when the selected value(s) change. */\n onChange: MuiCustomAutocompleteProps['onChange'];\n /** Called when the input text changes (typing or programmatic updates). */\n onInputChange?: MuiCustomAutocompleteProps['onInputChange'];\n /** Options to display in the dropdown list. */\n options: AutocompleteOption[];\n /** Shows the keyboard shortcut badge (Cmd/Ctrl + K) and enables focusing via the shortcut when in search mode. */\n shortcutHotkey?: boolean;\n /** Visual behavior: 'search' shows a leading search icon; 'combobox' shows a popup button. */\n type?: 'combobox' | 'search';\n /** Controlled value (single option, array for multiple, or null). */\n value: MuiCustomAutocompleteProps['value'];\n}\n\n// Bind flags to MuiAutocomplete, see MuiCustomAutocompleteProps for more details\nconst MuiCustomAutocomplete = MuiAutocomplete<AutocompleteOption, boolean, boolean, boolean>;\nconst StyledAutocomplete = styled(MuiCustomAutocomplete, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ fullWidth = false }) => ({\n width: fullWidth ? '100%' : 'min(364px, 100%)',\n}));\n\nconst StyledInputAdornment = styled(MuiInputAdornment, {\n shouldForwardProp: (prop) => prop !== 'disabled',\n})<{ disabled?: boolean }>(({ theme, disabled = false }) => ({\n '&.MuiInputAdornment-positionEnd': {\n margin: 0,\n },\n\n '& svg': {\n color: disabled\n ? theme.palette.semantic.icon['icon-disabled']\n : theme.palette.semantic.icon['icon-strong'],\n },\n}));\n\nconst StyledEndAdornmentContainer = styled(Box)(({ theme }) => ({\n alignItems: 'center',\n display: 'flex',\n gap: theme.spacing(1),\n}));\n\nconst ShortcutBadgeWrapper = styled('span')(() => ({\n display: 'inline-flex',\n\n // hide when input root is focused\n '.Mui-focused &': {\n display: 'none',\n },\n}));\n\n/**\n * A customizable Autocomplete component supporting search and combobox modes.\n * Supports single and multiple selection with dynamic tag rendering and optional loading states.\n *\n * @param props - The component props\n * @returns The rendered Autocomplete component\n */\nexport const Autocomplete = ({\n ariaLabel,\n className,\n disabled = false,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n label,\n loading = false,\n multiple = false,\n onChange,\n onInputChange,\n options = [],\n placeholder,\n required = false,\n shortcutHotkey = false,\n type = 'search',\n value,\n}: AutocompleteProps): JSX.Element => {\n const inputRef = useRef<HTMLInputElement>(null);\n const [inputText, setInputText] = useState<string>('');\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const { translate } = useTranslation();\n\n /**\n * Normalizes the value prop for MUI Autocomplete.\n * Handles both single and multiple selection modes, ensuring the value\n * format matches the mode (array for multiple, single value/null for single).\n *\n * @returns Normalized value compatible with MUI Autocomplete\n */\n const getValue = (): AutocompleteProps['value'] => {\n // Multiple value selection\n if (multiple) {\n if (Array.isArray(value)) return value;\n if (value === null || value === undefined) return [];\n return [value as AutocompleteOption];\n }\n\n // Single value selection\n if (Array.isArray(value)) return value.length > 0 ? value[0] : null;\n return value ?? null;\n };\n\n const normalizedValue = getValue();\n const isSearch = type === 'search';\n const isCombobox = type === 'combobox';\n const isClearable = (Boolean(inputText) || Boolean(normalizedValue)) && !disabled;\n const isShortcutHotkeyEnabled = isSearch && shortcutHotkey && !normalizedValue && !disabled;\n const screenReaderOnlyId = useVisuallyHiddenId();\n\n const handleShortcutHotkeyFocus = useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n // Hotkey handling and display for Cmd/Ctrl + K\n const { hotkeyText } = useShortcutHotkey({\n enabled: isShortcutHotkeyEnabled,\n onTrigger: handleShortcutHotkeyFocus,\n });\n\n // Dynamic limit tags calculation\n const { rootRef, limitTags } = useDynamicLimitTags({\n chipMax: 130,\n gap: 4,\n horizontalPadding: 32,\n reservedPx: isSearch ? 120 : 90,\n });\n\n /**\n * Close the dropdown (if open) when:\n * - the component is dynamically disabled.\n * - if search mode and no options are provided.\n */\n useEffect(() => {\n if (!isOpen) return;\n if (disabled) setIsOpen(false);\n if (isSearch && options.length === 0) setIsOpen(false);\n }, [isOpen, disabled, isSearch, options.length]);\n\n /**\n * Toggles or sets the dropdown open state.\n * Does nothing when:\n * - the component is disabled.\n * - if search mode and no options are provided.\n *\n * @param open - Optional boolean to explicitly set open state; if undefined, toggles current state\n */\n const toggleOpen = (open?: boolean): void => {\n if (disabled) return;\n if (isSearch && options.length === 0) return;\n\n if (open !== undefined) {\n setIsOpen(open);\n return;\n }\n\n setIsOpen((prevOpen) => !prevOpen);\n };\n\n const renderSearchIcon = (): JSX.Element => {\n return (\n <StyledInputAdornment disabled={disabled} position=\"start\">\n <SearchIcon aria-hidden=\"true\" data-testid=\"search-icon\" />\n </StyledInputAdornment>\n );\n };\n\n const renderPopupIcon = (): JSX.Element => {\n return (\n <StyledInputAdornment disabled={disabled} position=\"end\">\n {isOpen ? <ArrowUp01Icon /> : <ArrowDown01Icon />}\n </StyledInputAdornment>\n );\n };\n\n const renderShortcutHotkey = (): JSX.Element => {\n return (\n <ShortcutBadgeWrapper>\n <Badge label={hotkeyText} size=\"small\" tone=\"neutral\" />\n </ShortcutBadgeWrapper>\n );\n };\n\n const renderEndAdornment = (): React.ReactNode => {\n return (\n <StyledEndAdornmentContainer>\n {loading ? <CircularProgress size=\"small\" /> : null}\n {isShortcutHotkeyEnabled ? renderShortcutHotkey() : null}\n </StyledEndAdornmentContainer>\n );\n };\n\n const renderInputField = (params: AutocompleteRenderInputParams): JSX.Element => {\n const hasOptions = Array.isArray(options) && options.length > 0;\n const showPopup = isCombobox || (isSearch && hasOptions);\n const ariaDescribedBy =\n [params.inputProps['aria-describedby'], isShortcutHotkeyEnabled ? screenReaderOnlyId : undefined]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <TextField\n disabled={disabled}\n errorText={errorText}\n fdKey={fdKey}\n fullWidth={fullWidth}\n helperText={helperText}\n inputRef={inputRef}\n label={label}\n placeholder={placeholder}\n required={required}\n slotProps={{\n input: {\n ...params.InputProps,\n endAdornment: (\n <>\n {renderEndAdornment()}\n {params.InputProps.endAdornment}\n </>\n ),\n startAdornment: (\n <>\n {isSearch ? renderSearchIcon() : null}\n {params.InputProps.startAdornment}\n </>\n ),\n },\n htmlInput: {\n ...params.inputProps,\n id: fdKey,\n 'aria-label': isSearch && !label ? ariaLabel : undefined,\n 'aria-describedby': ariaDescribedBy,\n // If the popup is not shown, hide the autocomplete listbox functionality from screen readers\n ...(!showPopup && {\n role: 'searchbox',\n 'aria-autocomplete': 'none',\n 'aria-invalid': !errorText && !required ? undefined : params.inputProps['aria-invalid'],\n }),\n },\n }}\n />\n );\n };\n\n const renderMenuOption = (\n optionProps: React.HTMLAttributes<HTMLLIElement> & { key: React.Key },\n option: AutocompleteOption,\n state: AutocompleteRenderOptionState,\n ): JSX.Element => {\n const { key, onClick, ...rest } = optionProps;\n\n if (multiple) {\n return (\n <MenuItem\n {...rest}\n key={key}\n checked={state.selected}\n label={option.label}\n onCheckedChange={(_checked, e) => {\n onClick?.(e as React.MouseEvent<HTMLLIElement, MouseEvent>);\n }}\n type=\"checkbox\"\n />\n );\n }\n\n return (\n <MenuItem\n {...rest}\n key={key}\n label={option.label}\n onClick={onClick}\n selected={state.selected}\n type=\"text\"\n />\n );\n };\n\n const renderSelectedTags = (\n selected: AutocompleteOption[],\n getTagProps: AutocompleteRenderGetTagProps,\n ): React.ReactNode =>\n selected.map((tag, index) => {\n const { key, onDelete, ...tagProps } = getTagProps({ index });\n const rawLabel = typeof tag === 'string' ? tag : tag.label;\n const label = truncateWithEllipsis(rawLabel, 13, { includeEllipsisInLimit: true });\n const isTruncated = label.endsWith('...');\n const tagKey = key ?? `tag-${typeof tag === 'string' ? tag : tag.value}`;\n\n if (isTruncated) {\n return (\n <Tooltip key={tagKey} title={rawLabel}>\n <span {...tagProps}>\n <Tag label={label} onDismiss={onDelete} />\n </span>\n </Tooltip>\n );\n }\n\n return (\n <span key={tagKey} {...tagProps}>\n <Tag label={label} onDismiss={onDelete} />\n </span>\n );\n });\n\n const handlePopupIndicatorClick = (event: React.MouseEvent): void => {\n if (disabled) {\n return;\n }\n\n event.stopPropagation();\n toggleOpen();\n };\n\n const handleChange = (\n event: React.SyntheticEvent,\n value: AutocompleteValue<AutocompleteOption, boolean, boolean, boolean>,\n reason: AutocompleteChangeReason,\n details?: AutocompleteChangeDetails<AutocompleteOption>,\n ): void => {\n if (!onChange) {\n return;\n }\n onChange(event, value, reason, details);\n };\n\n const handleInputChange = (\n event: React.SyntheticEvent,\n value: string,\n reason: AutocompleteInputChangeReason,\n ): void => {\n setInputText(value);\n if (!onInputChange) {\n return;\n }\n onInputChange(event, value, reason);\n };\n\n /**\n * Returns all options without filtering for search mode.\n * Disables MUI's built-in client-side filtering when type is 'search'.\n */\n const disableClientFilter = (opts: AutocompleteOption[]): AutocompleteOption[] => opts;\n\n /**\n * Extracts the display label from an option.\n * Supports both object options and freeSolo string values.\n */\n const getOptionLabel = (option: AutocompleteOption | string): string => {\n return typeof option === 'string' ? option : option.label;\n };\n\n /**\n * Provides a stable unique key for each option to optimize DOM reconciliation.\n */\n const getOptionKey = (option: AutocompleteOption | string): string => {\n return typeof option === 'string' ? option : String(option.value);\n };\n\n /**\n * Determines equality between an option and the current value.\n * Handles both freeSolo string values and object options to prevent selection glitches.\n */\n const getIsOptionEqualToValue = (a: AutocompleteOption, b: AutocompleteOption): boolean => {\n if (b === null || b === undefined) {\n return false;\n }\n return typeof b === 'string' ? a.label === b || String(a.value) === b : a.value === b.value;\n };\n\n return (\n <>\n <StyledAutocomplete\n ref={rootRef}\n className={className}\n clearIcon={<CancelIcon size=\"md\" />}\n clearText={translate('Clear_selection')}\n disableClearable={!isClearable}\n disableCloseOnSelect={multiple}\n disabled={disabled}\n filterOptions={isSearch ? disableClientFilter : undefined}\n forcePopupIcon={isCombobox}\n freeSolo={isSearch}\n fullWidth={fullWidth}\n getOptionKey={getOptionKey}\n getOptionLabel={getOptionLabel}\n inputValue={inputText}\n isOptionEqualToValue={getIsOptionEqualToValue}\n limitTags={limitTags}\n loading={loading}\n loadingText={`${translate('Loading')}...`}\n multiple={multiple}\n noOptionsText={translate('No_options')}\n onChange={handleChange}\n onClose={() => toggleOpen(false)}\n onInputChange={handleInputChange}\n onOpen={() => toggleOpen(true)}\n open={isOpen}\n openText={translate('Open_popup')}\n options={options}\n popupIcon={isCombobox ? renderPopupIcon() : null}\n renderInput={renderInputField}\n renderOption={renderMenuOption}\n renderTags={renderSelectedTags}\n slotProps={{\n popupIndicator: {\n onClick: handlePopupIndicatorClick,\n },\n }}\n value={normalizedValue}\n />\n\n {isShortcutHotkeyEnabled && (\n <VisuallyHidden fdKey=\"autocomplete-shortcut-hotkey\" id={screenReaderOnlyId}>\n {translate('Press_hotkey_to_focus_search', { hotkey: hotkeyText })}\n </VisuallyHidden>\n )}\n </>\n );\n};\n\nexport default Autocomplete;\n"],"names":["StyledAutocomplete","styled","shouldForwardProp","prop","fullWidth","width","StyledInputAdornment","MuiInputAdornment","theme","disabled","margin","color","palette","semantic","icon","StyledEndAdornmentContainer","Box","alignItems","display","gap","spacing","ShortcutBadgeWrapper","Autocomplete","ariaLabel","className","errorText","fdKey","helperText","label","loading","multiple","onChange","onInputChange","options","placeholder","required","shortcutHotkey","type","value","inputRef","useRef","inputText","setInputText","useState","isOpen","setIsOpen","translate","useTranslation","normalizedValue","Array","isArray","length","isSearch","isCombobox","isClearable","Boolean","isShortcutHotkeyEnabled","screenReaderOnlyId","useVisuallyHiddenId","handleShortcutHotkeyFocus","useCallback","current","focus","hotkeyText","useShortcutHotkey","enabled","onTrigger","rootRef","limitTags","useDynamicLimitTags","chipMax","horizontalPadding","reservedPx","useEffect","toggleOpen","open","undefined","prevOpen","_jsxs","_Fragment","children","_jsx","ref","clearIcon","CancelIcon","size","clearText","disableClearable","disableCloseOnSelect","filterOptions","opts","forcePopupIcon","freeSolo","getOptionKey","option","String","getOptionLabel","inputValue","isOptionEqualToValue","a","b","loadingText","noOptionsText","event","reason","details","onClose","onOpen","openText","popupIcon","position","ArrowUp01Icon","ArrowDown01Icon","renderInput","params","hasOptions","showPopup","ariaDescribedBy","inputProps","filter","join","TextField","slotProps","input","InputProps","endAdornment","CircularProgress","Badge","tone","startAdornment","SearchIcon","htmlInput","id","role","renderOption","optionProps","state","key","onClick","rest","_createElement","MenuItem","checked","selected","onCheckedChange","_checked","e","renderTags","getTagProps","map","tag","index","onDelete","tagProps","rawLabel","truncateWithEllipsis","includeEllipsisInLimit","isTruncated","endsWith","tagKey","Tooltip","title","Tag","onDismiss","popupIndicator","stopPropagation","VisuallyHidden","hotkey"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime");require("react"),require("@mui/material/Pagination");var t=require("@mui/material/usePagination/usePagination"),a=require("@mui/material/Box"),i=require("../../atoms/Button/index.cjs.js"),n=require("../../atoms/IconButton/index.cjs.js"),r=require("@mui/material/Typography"),s=require("@mui/material/Stack"),o=require("../../../icons/ArrowLeft02/index.cjs.js"),d=require("../../../icons/ArrowRight02/index.cjs.js"),l=require("@mui/material/styles"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime");require("react"),require("@mui/material/Pagination");var t=require("@mui/material/usePagination/usePagination"),a=require("@mui/material/Box"),i=require("../../atoms/Button/index.cjs.js"),n=require("../../atoms/IconButton/index.cjs.js"),r=require("@mui/material/Typography"),s=require("@mui/material/Stack"),o=require("../../../icons/ArrowLeft02/index.cjs.js"),d=require("../../../icons/ArrowRight02/index.cjs.js"),l=require("../../../providers/TranslationProvider.cjs.js"),c=require("@mui/material/styles"),p=require("@mui/material/useMediaQuery"),u=require("@mui/material/styles/useTheme");const g=c.styled("nav")((({theme:e})=>({display:"flex",flexDirection:"row",alignItems:"center",width:"100%",justifyContent:"space-between",padding:e.spacing(.5),gap:e.spacing(2)}))),x=c.styled("nav")((({theme:e,willRenderRowsPerPage:t})=>({display:"flex",flexDirection:"row",alignItems:"center",width:"100%",justifyContent:t?"space-between":"center",paddingLeft:e.spacing(1),paddingRight:e.spacing(1),gap:e.spacing(2)}))),m=c.styled(n.IconButton)((({theme:e})=>({borderRadius:e.radius["radius-8"],border:`1px solid ${e.palette.semantic.stroke["stroke-strong"]}`,"&:hover":{borderRadius:e.radius["radius-8"],border:`1px solid ${e.palette.semantic.stroke["stroke-strong"]}`},"&:focus":{borderRadius:e.radius["radius-8"],border:`1px solid ${e.palette.semantic.stroke["stroke-strong"]}`},"&:active":{borderRadius:e.radius["radius-8"],border:`1px solid ${e.palette.semantic.stroke["stroke-strong"]}`},"&:disabled":{borderRadius:e.radius["radius-8"],border:`1px solid ${e.palette.semantic.stroke["stroke-strong"]}`}}))),b=c.styled(r)((({theme:e})=>({color:e.palette.semantic.text["text-weak"]}))),y=c.styled(i.Button)((()=>({textDecoration:"none"}))),j=(e,t,a,i)=>i("Showing_start_end_of_total",{start:t*(e-1)+1,end:t*e,total:t*a}),k=({pageCount:i=1,boundaryPageCount:r=1,disabled:c=!1,rowsPerPage:k,page:h,onChange:v,size:f="medium"})=>{const w=p((e=>e.breakpoints.down("tablet"))),{items:C}=t({boundaryCount:r,count:i,disabled:c,onChange:v,page:h}),P=u(),{translate:q}=l.useTranslation();if(w){const t=C.find((e=>"previous"===e.type)),a=C.find((e=>"next"===e.type));return e.jsxs(g,{children:[!!t&&e.jsx(n.IconButton,{"aria-label":q("Previous_page"),"data-testid":"pagination-prev-btn-mobile",disabled:c||t.disabled,onClick:t.onClick,size:f,tone:"neutral",variant:"tertiary",children:e.jsx(o,{color:P.palette.semantic.text["text-weak"],size:"md"})}),e.jsx(s,{alignItems:"center",flexGrow:1,children:e.jsx(b,{"data-testid":"pagination-page-mobile",variant:"captionWeak",children:q("page_of_count",{page:h,count:i})})}),!!a&&e.jsx(n.IconButton,{"aria-label":q("Next_page"),"data-testid":"pagination-next-btn-mobile",disabled:c||a.disabled,onClick:a.onClick,size:f,tone:"neutral",variant:"tertiary",children:e.jsx(d,{color:P.palette.semantic.text["text-weak"],size:"md"})})]})}const _="number"==typeof k;return e.jsxs(x,{willRenderRowsPerPage:_,children:[e.jsx(s,{alignItems:"center",direction:"row",gap:P.spacing(1),children:C.map((t=>"previous"===t.type?e.jsx(y,{"aria-label":q("Previous_page"),"data-testid":"pagination-prev-btn",disabled:c||t.disabled,fdKey:"pagination-prev-btn",onClick:t.onClick,size:f,startIcon:e.jsx(o,{color:P.palette.semantic.text["text-weak"],size:"md"}),tone:"neutral",variant:"tertiary",children:e.jsx(b,{variant:"captionWeak",children:q("Previous")})},t.type):"start-ellipsis"===t.type||"end-ellipsis"===t.type?e.jsx(a,{children:e.jsx(b,{"data-testid":"pagination-ellipsis",variant:"captionWeak",children:"..."})},t.type):"next"===t.type?e.jsx(y,{"aria-label":q("Next_page"),"data-testid":"pagination-next-btn",disabled:c||t.disabled,endIcon:e.jsx(d,{color:P.palette.semantic.text["text-weak"],size:"md"}),fdKey:"pagination-next-btn",onClick:t.onClick,size:f,tone:"neutral",variant:"tertiary",children:e.jsx(b,{variant:"captionWeak",children:q("Next")})},t.type):t.selected?e.jsx(m,{"aria-current":"page","aria-label":q("Selected_page_number",{number:String(t.page)}),"data-testid":"pagination-current-page",disabled:c||t.disabled,fdKey:"pagination-page",onClick:t.onClick,size:f,tone:"neutral",variant:"tertiary",children:e.jsx(b,{variant:"captionWeak",children:t.page})},t.page):e.jsx(n.IconButton,{"aria-label":q("Page_number",{number:String(t.page)}),"data-testid":"pagination-page",disabled:c||t.disabled,fdKey:"pagination-page",onClick:t.onClick,size:f,tone:"neutral",variant:"tertiary",children:e.jsx(b,{variant:"captionWeak",children:t.page})},t.page)))}),e.jsx(s,{alignItems:"center",flexGrow:0,children:"number"==typeof k&&e.jsx(b,{"data-testid":"pagination-page-range",variant:"captionWeak",children:j(h,k,i,q)})})]})};exports.Pagination=k,exports.default=k;
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/molecules/Pagination/index.tsx"],"sourcesContent":["import React from \"react\";\n\nimport { type PaginationProps as MUIPaginationProps } from \"@mui/material/Pagination\";\nimport usePagination from \"@mui/material/usePagination/usePagination\";\n\nimport Box from \"@fd/components/atoms/Box\";\nimport Button from \"@fd/components/atoms/Button\";\nimport IconButton from \"@fd/components/atoms/IconButton\";\nimport Typography from \"@fd/components/atoms/Typography\";\nimport Stack from '@fd/components/molecules/Stack';\nimport ArrowLeft02Icon from \"@fd/icons/ArrowLeft02\";\nimport ArrowRight02Icon from \"@fd/icons/ArrowRight02\";\nimport styled from \"@fd/utilities/styledUtilities\"\nimport useMediaQuery from \"@fd/utilities/useMediaQuery\";\nimport useTheme from \"@fd/utilities/useTheme\";\n\nconst StyledPaginationMobileContainer = styled('nav')(({theme}) => ({\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n width: '100%',\n justifyContent: 'space-between',\n padding: theme.spacing(0.5),\n gap: theme.spacing(2),\n}));\n\nconst StyledPaginationDesktopContainer = styled('nav')<{ willRenderRowsPerPage: boolean }>(({theme, willRenderRowsPerPage}) => ({\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n width: '100%',\n justifyContent: willRenderRowsPerPage ? 'space-between' : 'center',\n paddingLeft: theme.spacing(1),\n paddingRight: theme.spacing(1),\n gap: theme.spacing(2),\n}));\n\nconst StyledSelectedPageBtn = styled(IconButton)(({ theme }) =>({\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n '&:hover': {\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n },\n '&:focus': {\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n },\n '&:active': {\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n },\n '&:disabled': {\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n },\n}));\n\nconst StyledTypography = styled(Typography)(({ theme }) => ({\n color: theme.palette.semantic.text['text-weak'],\n}))\n\nconst StyledPrevNextBtn = styled(Button)(() =>({\n textDecoration: 'none',\n}))\n\nconst getPaginationStatus = (page: number, rowsPerPage: number, pageCount: number, translations: PaginationTranslations): string => {\n const start = rowsPerPage * (page - 1) + 1;\n const end = rowsPerPage * page;\n return `${translations.showing} ${start} - ${end} ${translations.of} ${rowsPerPage * pageCount}`;\n}\n\nexport interface PaginationTranslations {\n previousPageAriaLabel: string;\n nextPageAriaLabel: string;\n selectedPageAriaLabel: string;\n paginationPageAriaLabel: string;\n next: string;\n previous: string;\n showing: string;\n of: string;\n}\n\nexport interface PaginationProps {\n pageCount?: number;\n boundaryPageCount?: number;\n disabled?: boolean;\n rowsPerPage?: number;\n size?: 'medium' | 'small';\n page: number;\n onChange: MUIPaginationProps['onChange'];\n translations: PaginationTranslations\n}\n\nexport const Pagination: React.FC<PaginationProps> = ({\n pageCount = 1,\n boundaryPageCount = 1,\n disabled = false,\n rowsPerPage,\n page,\n onChange,\n size = 'medium',\n translations,\n}) => {\n const isMobile = useMediaQuery((theme) => theme.breakpoints.down('tablet'));\n const { items } = usePagination({\n boundaryCount: boundaryPageCount,\n count: pageCount,\n disabled,\n onChange,\n page\n });\n\n const theme = useTheme();\n\n if (isMobile) {\n const previousBtn = items.find(item => item.type === 'previous');\n const nextBtn = items.find(item => item.type === 'next');\n return (\n <StyledPaginationMobileContainer>\n {\n !!previousBtn &&\n <IconButton\n aria-label={translations.previousPageAriaLabel}\n data-testid=\"pagination-prev-btn-mobile\"\n disabled={disabled || previousBtn.disabled}\n onClick={previousBtn.onClick}\n size={size}\n tone='neutral'\n variant='tertiary'\n >\n <ArrowLeft02Icon color={theme.palette.semantic.text[\"text-weak\"]} size=\"md\" />\n </IconButton>\n }\n <Stack alignItems='center' flexGrow={1}>\n <StyledTypography data-testid=\"pagination-page-mobile\" variant=\"captionWeak\">\n {page} {translations.of} {pageCount}\n </StyledTypography>\n </Stack>\n {\n !!nextBtn &&\n <IconButton\n aria-label={translations.nextPageAriaLabel}\n data-testid=\"pagination-next-btn-mobile\"\n disabled={disabled || nextBtn.disabled}\n onClick={nextBtn.onClick}\n size={size}\n tone='neutral'\n variant='tertiary'\n >\n <ArrowRight02Icon color={theme.palette.semantic.text[\"text-weak\"]} size=\"md\" />\n </IconButton>\n }\n\n </StyledPaginationMobileContainer>\n );\n }\n\n const willRenderRowsPerPage = typeof rowsPerPage === \"number\";\n\n return (\n <StyledPaginationDesktopContainer willRenderRowsPerPage={willRenderRowsPerPage}>\n <Stack\n alignItems='center'\n direction='row'\n gap={theme.spacing(1)}\n >\n {items.map((item) => {\n if (item.type === 'previous') {\n return (\n <StyledPrevNextBtn\n key={item.type}\n aria-label={translations.previousPageAriaLabel}\n data-testid=\"pagination-prev-btn\"\n disabled={disabled || item.disabled}\n fdKey=\"pagination-prev-btn\"\n onClick={item.onClick}\n size={size}\n startIcon={<ArrowLeft02Icon color={theme.palette.semantic.text[\"text-weak\"]} size=\"md\" />}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <StyledTypography variant=\"captionWeak\">\n {translations.previous}\n </StyledTypography>\n </StyledPrevNextBtn>\n )\n }\n\n if (item.type === 'start-ellipsis' || item.type === 'end-ellipsis') {\n return (\n <Box\n key={item.type}\n >\n <StyledTypography data-testid=\"pagination-ellipsis\" variant=\"captionWeak\">\n ...\n </StyledTypography>\n\n </Box>\n )\n }\n\n if (item.type === \"next\") {\n return (\n <StyledPrevNextBtn\n key={item.type}\n aria-label={translations.nextPageAriaLabel}\n data-testid=\"pagination-next-btn\"\n disabled={disabled || item.disabled}\n endIcon={<ArrowRight02Icon color={theme.palette.semantic.text[\"text-weak\"]} size=\"md\" />}\n fdKey=\"pagination-next-btn\"\n onClick={item.onClick}\n size={size}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <StyledTypography variant=\"captionWeak\">\n {translations.next}\n </StyledTypography>\n </StyledPrevNextBtn>\n )\n }\n\n if (item.selected) {\n return (\n <StyledSelectedPageBtn\n key={item.page}\n aria-label={translations.selectedPageAriaLabel}\n data-testid=\"pagination-current-page\"\n disabled={disabled || item.disabled}\n fdKey=\"pagination-page\"\n onClick={item.onClick}\n size={size}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <StyledTypography variant=\"captionWeak\">\n {item.page}\n </StyledTypography>\n </StyledSelectedPageBtn>\n )\n }\n\n return (\n <IconButton\n key={item.page}\n aria-label={`${translations.paginationPageAriaLabel} ${item.page}`}\n data-testid=\"pagination-page\"\n disabled={disabled || item.disabled}\n fdKey=\"pagination-page\"\n onClick={item.onClick}\n size={size}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <StyledTypography variant=\"captionWeak\">\n {item.page}\n </StyledTypography>\n </IconButton>\n )\n })}\n </Stack>\n <Stack\n alignItems='center'\n flexGrow={0}\n >\n {typeof rowsPerPage === \"number\" && (\n <StyledTypography data-testid=\"pagination-page-range\" variant=\"captionWeak\">\n {getPaginationStatus(page, rowsPerPage, pageCount, translations)}\n </StyledTypography>\n )}\n </Stack>\n </StyledPaginationDesktopContainer>\n );\n}\n\nexport default Pagination;"],"names":["StyledPaginationMobileContainer","styled","theme","display","flexDirection","alignItems","width","justifyContent","padding","spacing","gap","StyledPaginationDesktopContainer","willRenderRowsPerPage","paddingLeft","paddingRight","StyledSelectedPageBtn","IconButton","borderRadius","radius","border","palette","semantic","stroke","StyledTypography","Typography","color","text","StyledPrevNextBtn","Button","textDecoration","getPaginationStatus","page","rowsPerPage","pageCount","translations","start","end","showing","of","Pagination","boundaryPageCount","disabled","onChange","size","isMobile","useMediaQuery","breakpoints","down","items","usePagination","boundaryCount","count","useTheme","previousBtn","find","item","type","nextBtn","_jsxs","children","_jsx","previousPageAriaLabel","onClick","tone","variant","ArrowLeft02Icon","Stack","flexGrow","nextPageAriaLabel","ArrowRight02Icon","direction","map","fdKey","startIcon","previous","Box","endIcon","next","selected","selectedPageAriaLabel","paginationPageAriaLabel"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/molecules/Pagination/index.tsx"],"sourcesContent":["import React from 'react';\n\nimport { type PaginationProps as MUIPaginationProps } from '@mui/material/Pagination';\nimport usePagination from '@mui/material/usePagination/usePagination';\n\nimport Box from '@fd/components/atoms/Box';\nimport Button from '@fd/components/atoms/Button';\nimport IconButton from '@fd/components/atoms/IconButton';\nimport Typography from '@fd/components/atoms/Typography';\nimport Stack from '@fd/components/molecules/Stack';\nimport ArrowLeft02Icon from '@fd/icons/ArrowLeft02';\nimport ArrowRight02Icon from '@fd/icons/ArrowRight02';\nimport { type TranslateFunction, useTranslation } from '@fd/providers/TranslationProvider';\nimport styled from '@fd/utilities/styledUtilities';\nimport useMediaQuery from '@fd/utilities/useMediaQuery';\nimport useTheme from '@fd/utilities/useTheme';\n\nconst StyledPaginationMobileContainer = styled('nav')(({ theme }) => ({\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n width: '100%',\n justifyContent: 'space-between',\n padding: theme.spacing(0.5),\n gap: theme.spacing(2),\n}));\n\nconst StyledPaginationDesktopContainer = styled('nav')<{ willRenderRowsPerPage: boolean }>(\n ({ theme, willRenderRowsPerPage }) => ({\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n width: '100%',\n justifyContent: willRenderRowsPerPage ? 'space-between' : 'center',\n paddingLeft: theme.spacing(1),\n paddingRight: theme.spacing(1),\n gap: theme.spacing(2),\n }),\n);\n\nconst StyledSelectedPageBtn = styled(IconButton)(({ theme }) => ({\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n '&:hover': {\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n },\n '&:focus': {\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n },\n '&:active': {\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n },\n '&:disabled': {\n borderRadius: theme.radius['radius-8'],\n border: `1px solid ${theme.palette.semantic.stroke['stroke-strong']}`,\n },\n}));\n\nconst StyledTypography = styled(Typography)(({ theme }) => ({\n color: theme.palette.semantic.text['text-weak'],\n}));\n\nconst StyledPrevNextBtn = styled(Button)(() => ({\n textDecoration: 'none',\n}));\n\nconst getPaginationStatus = (\n page: number,\n rowsPerPage: number,\n pageCount: number,\n translate: TranslateFunction,\n): string => {\n const start = rowsPerPage * (page - 1) + 1;\n const end = rowsPerPage * page;\n return translate('Showing_start_end_of_total', { start, end, total: rowsPerPage * pageCount });\n};\n\nexport interface PaginationProps {\n pageCount?: number;\n boundaryPageCount?: number;\n disabled?: boolean;\n rowsPerPage?: number;\n size?: 'medium' | 'small';\n page: number;\n onChange: MUIPaginationProps['onChange'];\n}\n\nexport const Pagination: React.FC<PaginationProps> = ({\n pageCount = 1,\n boundaryPageCount = 1,\n disabled = false,\n rowsPerPage,\n page,\n onChange,\n size = 'medium',\n}) => {\n const isMobile = useMediaQuery((theme) => theme.breakpoints.down('tablet'));\n const { items } = usePagination({\n boundaryCount: boundaryPageCount,\n count: pageCount,\n disabled,\n onChange,\n page,\n });\n\n const theme = useTheme();\n const { translate } = useTranslation();\n\n if (isMobile) {\n const previousBtn = items.find((item) => item.type === 'previous');\n const nextBtn = items.find((item) => item.type === 'next');\n return (\n <StyledPaginationMobileContainer>\n {!!previousBtn && (\n <IconButton\n aria-label={translate('Previous_page')}\n data-testid=\"pagination-prev-btn-mobile\"\n disabled={disabled || previousBtn.disabled}\n onClick={previousBtn.onClick}\n size={size}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <ArrowLeft02Icon color={theme.palette.semantic.text['text-weak']} size=\"md\" />\n </IconButton>\n )}\n <Stack alignItems=\"center\" flexGrow={1}>\n <StyledTypography data-testid=\"pagination-page-mobile\" variant=\"captionWeak\">\n {translate('page_of_count', { page, count: pageCount })}\n </StyledTypography>\n </Stack>\n {!!nextBtn && (\n <IconButton\n aria-label={translate('Next_page')}\n data-testid=\"pagination-next-btn-mobile\"\n disabled={disabled || nextBtn.disabled}\n onClick={nextBtn.onClick}\n size={size}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <ArrowRight02Icon color={theme.palette.semantic.text['text-weak']} size=\"md\" />\n </IconButton>\n )}\n </StyledPaginationMobileContainer>\n );\n }\n\n const willRenderRowsPerPage = typeof rowsPerPage === 'number';\n\n return (\n <StyledPaginationDesktopContainer willRenderRowsPerPage={willRenderRowsPerPage}>\n <Stack alignItems=\"center\" direction=\"row\" gap={theme.spacing(1)}>\n {items.map((item) => {\n if (item.type === 'previous') {\n return (\n <StyledPrevNextBtn\n key={item.type}\n aria-label={translate('Previous_page')}\n data-testid=\"pagination-prev-btn\"\n disabled={disabled || item.disabled}\n fdKey=\"pagination-prev-btn\"\n onClick={item.onClick}\n size={size}\n startIcon={<ArrowLeft02Icon color={theme.palette.semantic.text['text-weak']} size=\"md\" />}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <StyledTypography variant=\"captionWeak\">{translate('Previous')}</StyledTypography>\n </StyledPrevNextBtn>\n );\n }\n\n if (item.type === 'start-ellipsis' || item.type === 'end-ellipsis') {\n return (\n <Box key={item.type}>\n <StyledTypography data-testid=\"pagination-ellipsis\" variant=\"captionWeak\">\n ...\n </StyledTypography>\n </Box>\n );\n }\n\n if (item.type === 'next') {\n return (\n <StyledPrevNextBtn\n key={item.type}\n aria-label={translate('Next_page')}\n data-testid=\"pagination-next-btn\"\n disabled={disabled || item.disabled}\n endIcon={<ArrowRight02Icon color={theme.palette.semantic.text['text-weak']} size=\"md\" />}\n fdKey=\"pagination-next-btn\"\n onClick={item.onClick}\n size={size}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <StyledTypography variant=\"captionWeak\">{translate('Next')}</StyledTypography>\n </StyledPrevNextBtn>\n );\n }\n\n if (item.selected) {\n return (\n <StyledSelectedPageBtn\n key={item.page}\n aria-current=\"page\"\n aria-label={translate('Selected_page_number', { number: String(item.page) })}\n data-testid=\"pagination-current-page\"\n disabled={disabled || item.disabled}\n fdKey=\"pagination-page\"\n onClick={item.onClick}\n size={size}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <StyledTypography variant=\"captionWeak\">{item.page}</StyledTypography>\n </StyledSelectedPageBtn>\n );\n }\n\n return (\n <IconButton\n key={item.page}\n aria-label={translate('Page_number', { number: String(item.page) })}\n data-testid=\"pagination-page\"\n disabled={disabled || item.disabled}\n fdKey=\"pagination-page\"\n onClick={item.onClick}\n size={size}\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n <StyledTypography variant=\"captionWeak\">{item.page}</StyledTypography>\n </IconButton>\n );\n })}\n </Stack>\n <Stack alignItems=\"center\" flexGrow={0}>\n {typeof rowsPerPage === 'number' && (\n <StyledTypography data-testid=\"pagination-page-range\" variant=\"captionWeak\">\n {getPaginationStatus(page, rowsPerPage, pageCount, translate)}\n </StyledTypography>\n )}\n </Stack>\n </StyledPaginationDesktopContainer>\n );\n};\n\nexport default Pagination;\n"],"names":["StyledPaginationMobileContainer","styled","theme","display","flexDirection","alignItems","width","justifyContent","padding","spacing","gap","StyledPaginationDesktopContainer","willRenderRowsPerPage","paddingLeft","paddingRight","StyledSelectedPageBtn","IconButton","borderRadius","radius","border","palette","semantic","stroke","StyledTypography","Typography","color","text","StyledPrevNextBtn","Button","textDecoration","getPaginationStatus","page","rowsPerPage","pageCount","translate","start","end","total","Pagination","boundaryPageCount","disabled","onChange","size","isMobile","useMediaQuery","breakpoints","down","items","usePagination","boundaryCount","count","useTheme","useTranslation","previousBtn","find","item","type","nextBtn","_jsxs","children","_jsx","onClick","tone","variant","ArrowLeft02Icon","Stack","flexGrow","ArrowRight02Icon","direction","map","fdKey","startIcon","Box","endIcon","selected","number","String"],"mappings":"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"}
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import react__default from 'react';
|
|
2
2
|
import { PaginationProps as PaginationProps$1 } from '@mui/material/Pagination';
|
|
3
3
|
|
|
4
|
-
interface PaginationTranslations {
|
|
5
|
-
previousPageAriaLabel: string;
|
|
6
|
-
nextPageAriaLabel: string;
|
|
7
|
-
selectedPageAriaLabel: string;
|
|
8
|
-
paginationPageAriaLabel: string;
|
|
9
|
-
next: string;
|
|
10
|
-
previous: string;
|
|
11
|
-
showing: string;
|
|
12
|
-
of: string;
|
|
13
|
-
}
|
|
14
4
|
interface PaginationProps {
|
|
15
5
|
pageCount?: number;
|
|
16
6
|
boundaryPageCount?: number;
|
|
@@ -19,9 +9,8 @@ interface PaginationProps {
|
|
|
19
9
|
size?: 'medium' | 'small';
|
|
20
10
|
page: number;
|
|
21
11
|
onChange: PaginationProps$1['onChange'];
|
|
22
|
-
translations: PaginationTranslations;
|
|
23
12
|
}
|
|
24
13
|
declare const Pagination: react__default.FC<PaginationProps>;
|
|
25
14
|
|
|
26
15
|
export { Pagination, Pagination as default };
|
|
27
|
-
export type { PaginationProps
|
|
16
|
+
export type { PaginationProps };
|