@flipdish/portal-library 7.10.6 → 7.11.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/dist/components/atoms/TextArea/index.cjs.js.map +1 -1
- package/dist/components/atoms/TextArea/index.d.ts +10 -0
- 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 +19 -0
- package/dist/components/atoms/TextField/index.js +1 -1
- package/dist/components/atoms/TextField/index.js.map +1 -1
- package/dist/components/atoms/VisuallyHidden/index.cjs.js +2 -0
- package/dist/components/atoms/VisuallyHidden/index.cjs.js.map +1 -0
- package/dist/components/atoms/VisuallyHidden/index.d.ts +30 -0
- package/dist/components/atoms/VisuallyHidden/index.js +2 -0
- package/dist/components/atoms/VisuallyHidden/index.js.map +1 -0
- package/dist/components/molecules/Autocomplete/hooks/useDynamicLimitTags.cjs.js +1 -1
- package/dist/components/molecules/Autocomplete/hooks/useDynamicLimitTags.cjs.js.map +1 -1
- package/dist/components/molecules/Autocomplete/hooks/useDynamicLimitTags.d.ts +7 -1
- package/dist/components/molecules/Autocomplete/hooks/useDynamicLimitTags.js +1 -1
- package/dist/components/molecules/Autocomplete/hooks/useDynamicLimitTags.js.map +1 -1
- package/dist/components/molecules/Autocomplete/hooks/useShortcutHotkey.cjs.js +2 -0
- package/dist/components/molecules/Autocomplete/hooks/useShortcutHotkey.cjs.js.map +1 -0
- package/dist/components/molecules/Autocomplete/hooks/useShortcutHotkey.d.ts +17 -0
- package/dist/components/molecules/Autocomplete/hooks/useShortcutHotkey.js +2 -0
- package/dist/components/molecules/Autocomplete/hooks/useShortcutHotkey.js.map +1 -0
- 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 +8 -2
- package/dist/components/molecules/Autocomplete/index.js +1 -1
- package/dist/components/molecules/Autocomplete/index.js.map +1 -1
- package/dist/components/molecules/Combobox/index.cjs.js.map +1 -1
- package/dist/components/molecules/Combobox/index.d.ts +13 -1
- package/dist/components/molecules/Combobox/index.js.map +1 -1
- package/dist/components/molecules/SearchInput/index.cjs.js +2 -0
- package/dist/components/molecules/SearchInput/index.cjs.js.map +1 -0
- package/dist/components/molecules/SearchInput/index.d.ts +25 -0
- package/dist/components/molecules/SearchInput/index.js +2 -0
- package/dist/components/molecules/SearchInput/index.js.map +1 -0
- package/dist/components/organisms/ImageUploadWidget/components/ImageDisplay.cjs.js.map +1 -1
- package/dist/components/organisms/ImageUploadWidget/components/ImageDisplay.js.map +1 -1
- package/dist/themes/overrides/autocompleteOverrides.cjs.js +1 -1
- package/dist/themes/overrides/autocompleteOverrides.cjs.js.map +1 -1
- package/dist/themes/overrides/autocompleteOverrides.js +1 -1
- package/dist/themes/overrides/autocompleteOverrides.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/atoms/TextArea/index.tsx"],"sourcesContent":["import TextField, { type TextFieldProps } from '../TextField';\n\nexport type TextAreaProps = Omit<\n TextFieldProps,\n 'hidePasswordAriaLabel' | 'multiline' | 'showPasswordAriaLabel' | 'type'\n> & {\n rows?: number;\n};\n\nexport const TextArea = ({ fdKey, rows = 6, ...props }: TextAreaProps): JSX.Element => {\n return <TextField {...props} multiline fdKey={fdKey} rows={rows} type=\"text\" />;\n};\n\nexport default TextArea;\n"],"names":["TextArea","fdKey","rows","props","_jsx","TextField","multiline","type"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/atoms/TextArea/index.tsx"],"sourcesContent":["import TextField, { type TextFieldProps } from '../TextField';\n\n/**\n * The props for the TextArea component.\n */\nexport type TextAreaProps = Omit<\n TextFieldProps,\n 'hidePasswordAriaLabel' | 'multiline' | 'showPasswordAriaLabel' | 'type'\n> & {\n /** The number of rows for the text area. */\n rows?: number;\n};\n\n/**\n * A TextArea component.\n *\n * @param props - The component props\n * @returns The rendered TextArea component\n */\nexport const TextArea = ({ fdKey, rows = 6, ...props }: TextAreaProps): JSX.Element => {\n return <TextField {...props} multiline fdKey={fdKey} rows={rows} type=\"text\" />;\n};\n\nexport default TextArea;\n"],"names":["TextArea","fdKey","rows","props","_jsx","TextField","multiline","type"],"mappings":"8IAmBO,MAAMA,EAAW,EAAGC,QAAOC,OAAO,KAAMC,KACtCC,EAAAA,IAACC,EAAAA,UAAS,IAAKF,EAAOG,aAAUL,MAAOA,EAAOC,KAAMA,EAAMK,KAAK"}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { TextFieldProps } from '../TextField/index.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The props for the TextArea component.
|
|
5
|
+
*/
|
|
3
6
|
type TextAreaProps = Omit<TextFieldProps, 'hidePasswordAriaLabel' | 'multiline' | 'showPasswordAriaLabel' | 'type'> & {
|
|
7
|
+
/** The number of rows for the text area. */
|
|
4
8
|
rows?: number;
|
|
5
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* A TextArea component.
|
|
12
|
+
*
|
|
13
|
+
* @param props - The component props
|
|
14
|
+
* @returns The rendered TextArea component
|
|
15
|
+
*/
|
|
6
16
|
declare const TextArea: ({ fdKey, rows, ...props }: TextAreaProps) => JSX.Element;
|
|
7
17
|
|
|
8
18
|
export { TextArea, TextArea as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/components/atoms/TextArea/index.tsx"],"sourcesContent":["import TextField, { type TextFieldProps } from '../TextField';\n\nexport type TextAreaProps = Omit<\n TextFieldProps,\n 'hidePasswordAriaLabel' | 'multiline' | 'showPasswordAriaLabel' | 'type'\n> & {\n rows?: number;\n};\n\nexport const TextArea = ({ fdKey, rows = 6, ...props }: TextAreaProps): JSX.Element => {\n return <TextField {...props} multiline fdKey={fdKey} rows={rows} type=\"text\" />;\n};\n\nexport default TextArea;\n"],"names":["TextArea","fdKey","rows","props","_jsx","TextField","multiline","type"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/atoms/TextArea/index.tsx"],"sourcesContent":["import TextField, { type TextFieldProps } from '../TextField';\n\n/**\n * The props for the TextArea component.\n */\nexport type TextAreaProps = Omit<\n TextFieldProps,\n 'hidePasswordAriaLabel' | 'multiline' | 'showPasswordAriaLabel' | 'type'\n> & {\n /** The number of rows for the text area. */\n rows?: number;\n};\n\n/**\n * A TextArea component.\n *\n * @param props - The component props\n * @returns The rendered TextArea component\n */\nexport const TextArea = ({ fdKey, rows = 6, ...props }: TextAreaProps): JSX.Element => {\n return <TextField {...props} multiline fdKey={fdKey} rows={rows} type=\"text\" />;\n};\n\nexport default TextArea;\n"],"names":["TextArea","fdKey","rows","props","_jsx","TextField","multiline","type"],"mappings":"0FAmBO,MAAMA,EAAW,EAAGC,QAAOC,OAAO,KAAMC,KACtCC,EAACC,EAAS,IAAKF,EAAOG,aAAUL,MAAOA,EAAOC,KAAMA,EAAMK,KAAK"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),r=require("react"),i=require("@mui/material/Box"),t=require("@mui/material/FormHelperText"),l=require("@mui/material/InputAdornment"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),r=require("react"),i=require("@mui/material/Box"),t=require("@mui/material/FormHelperText"),l=require("@mui/material/InputAdornment"),d=require("@mui/material/InputLabel"),s=require("@mui/material/styles"),n=require("@mui/material/TextField"),o=require("../../../icons/CancelCircle/index.cjs.js"),a=require("../../../icons/View/index.cjs.js"),u=require("../../../icons/ViewOff/index.cjs.js"),c=require("../IconButton/index.cjs.js");const p=s.styled(i,{shouldForwardProp:e=>"fullWidth"!==e})((({theme:e,fullWidth:r=!1})=>({display:"flex",flexDirection:"column",gap:e.spacing(.5),width:r?"100%":"min(364px, 100%)"}))),x=s.styled(n,{shouldForwardProp:e=>"fullWidth"!==e})((({fullWidth:e=!1})=>({display:"flex",width:e?"100%":"auto"}))),m=s.styled(l,{shouldForwardProp:e=>"disabled"!==e})((({theme:e,disabled:r=!1})=>({color:r?e.palette.semantic.icon["icon-disabled"]:e.palette.semantic.icon["icon-strong"]}))),h=({disabled:l=!1,endAdornment:s,errorText:n,fdKey:h,fullWidth:j=!1,helperText:f,hidePasswordAriaLabel:b,label:q,multiline:y=!1,required:w=!1,showPasswordAriaLabel:P,startAdornment:v,type:A="text",...F})=>{const[I,W]=r.useState(!1),B=f?`${h}-helper-text`:void 0,T=n?`${h}-error-message`:void 0,g=[B,T].filter(Boolean).join(" ")||void 0,C=F.slotProps?.htmlInput?.["aria-describedby"],L=[C,g].filter(Boolean).join(" ")||void 0,O=!!n&&!l,V="password"===A,$=()=>W((e=>!e)),_=(()=>{if(V){if(!P||!b)return;return e.jsx(m,{position:"end",children:e.jsx(c.IconButton,{"aria-label":I?b:P,disabled:l,onClick:$,size:"small",tone:"neutral",variant:"tertiary",children:I?e.jsx(u,{}):e.jsx(a,{})})})}if(s)return e.jsx(m,{disabled:l,position:"end",children:s})})(),k=(()=>{if(v)return e.jsx(m,{disabled:l,position:"start",children:v})})();return e.jsxs(p,{fullWidth:j,children:[e.jsxs(i,{children:[q&&e.jsx(d,{disabled:l,htmlFor:h,required:w,children:q}),f&&e.jsx(t,{disabled:l,id:B,children:f})]}),O&&e.jsxs(t,{error:!0,id:T,children:[e.jsx(o,{}),n]}),e.jsx(x,{...F,"data-fd":h,disabled:l,error:O,fullWidth:j,id:h,label:"",multiline:y,required:w,slotProps:{input:{...F.slotProps?.input??{},...k&&{startAdornment:k},..._&&{endAdornment:_}},htmlInput:{...F.slotProps?.htmlInput??{},"aria-describedby":L}},type:V?I?"text":"password":A,variant:"outlined"})]})};exports.TextField=h,exports.default=h;
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/atoms/TextField/index.tsx"],"sourcesContent":["import { type ReactNode, useState } from 'react';\n\nimport Box from '@mui/material/Box';\nimport MuiFormHelperText from '@mui/material/FormHelperText';\nimport MuiInputAdornment from '@mui/material/InputAdornment';\nimport MuiInputLabel from '@mui/material/InputLabel';\nimport { styled } from '@mui/material/styles';\nimport MuiTextField, { type TextFieldProps as MuiTextFieldProps } from '@mui/material/TextField';\n\nimport CancelCircleIcon from '@fd/icons/CancelCircle';\nimport ViewIcon from '@fd/icons/View';\nimport ViewOffIcon from '@fd/icons/ViewOff';\n\nimport IconButton from '../IconButton';\n\n// Common props for all TextField variants\ntype BaseTextFieldProps = Omit<MuiTextFieldProps, 'error' | 'id' | 'type' | 'variant'> & {\n endAdornment?: ReactNode;\n errorText?: string;\n fdKey: string;\n startAdornment?: ReactNode;\n};\n\n// Password TextField variant - requires aria labels\ntype PasswordTextFieldProps = BaseTextFieldProps & {\n type: 'password';\n hidePasswordAriaLabel: string;\n showPasswordAriaLabel: string;\n};\n\n// Generic TextField variant - for all other input types\ntype GenericTextFieldProps = BaseTextFieldProps & {\n type?: Exclude<MuiTextFieldProps['type'], 'password'>;\n hidePasswordAriaLabel?: never;\n showPasswordAriaLabel?: never;\n};\n\nexport type TextFieldProps = GenericTextFieldProps | PasswordTextFieldProps;\n\nconst StyledContainer = styled(Box, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ theme, fullWidth = false }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(0.5),\n width: fullWidth ? '100%' : 'min(364px, 100%)', // Constrain width to a maximum of 100% of the container width\n}));\n\nconst StyledTextField = styled(MuiTextField, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ fullWidth = false }) => ({\n display: 'flex',\n width: fullWidth ? '100%' : 'auto',\n}));\n\nexport const TextField = ({\n disabled = false,\n endAdornment = undefined,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n hidePasswordAriaLabel,\n label,\n multiline = false,\n required = false,\n showPasswordAriaLabel,\n startAdornment = undefined,\n type = 'text',\n ...props\n}: TextFieldProps): JSX.Element => {\n const [showPassword, setShowPassword] = useState<boolean>(false);\n\n const helperTextId = helperText ? `${fdKey}-helper-text` : undefined;\n const errorMessageId = errorText ? `${fdKey}-error-message` : undefined;\n\n // Combine helper text and error message IDs for aria-describedby\n const ariaDescribedBy = [helperTextId, errorMessageId].filter(Boolean).join(' ') || undefined;\n\n const isError = !!errorText && !disabled;\n const isPassword = type === 'password';\n\n const handleClickShowPassword = (): void => setShowPassword((show) => !show);\n\n const getFieldType = (): MuiTextFieldProps['type'] => {\n if (isPassword) {\n return showPassword ? 'text' : 'password';\n }\n\n return type;\n };\n\n const renderEndAdornment = (): React.ReactNode => {\n if (isPassword) {\n if (!showPasswordAriaLabel || !hidePasswordAriaLabel) {\n return undefined;\n }\n\n return (\n <MuiInputAdornment position=\"end\">\n <IconButton\n aria-label={showPassword ? hidePasswordAriaLabel : showPasswordAriaLabel}\n disabled={disabled}\n onClick={handleClickShowPassword}\n size=\"small\"\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n {showPassword ? <ViewOffIcon /> : <ViewIcon />}\n </IconButton>\n </MuiInputAdornment>\n );\n }\n if (endAdornment) {\n return <MuiInputAdornment position=\"end\">{endAdornment}</MuiInputAdornment>;\n }\n\n return undefined;\n };\n\n const renderStartAdornment = (): React.ReactNode => {\n if (startAdornment) {\n return <MuiInputAdornment position=\"start\">{startAdornment}</MuiInputAdornment>;\n }\n\n return undefined;\n };\n\n const renderedEndAdornment = renderEndAdornment();\n const renderedStartAdornment = renderStartAdornment();\n\n return (\n <StyledContainer fullWidth={fullWidth}>\n <Box>\n {label && (\n <MuiInputLabel disabled={disabled} htmlFor={fdKey} required={required}>\n {label}\n </MuiInputLabel>\n )}\n\n {helperText && (\n <MuiFormHelperText disabled={disabled} id={helperTextId}>\n {helperText}\n </MuiFormHelperText>\n )}\n </Box>\n\n {isError && (\n <MuiFormHelperText error id={errorMessageId}>\n <CancelCircleIcon />\n\n {errorText}\n </MuiFormHelperText>\n )}\n\n <StyledTextField\n data-fd={fdKey}\n disabled={disabled}\n error={isError}\n fullWidth={fullWidth}\n id={fdKey}\n label=\"\" // Remove label from TextField since we're rendering it separately\n multiline={multiline}\n required={required}\n slotProps={{\n input: {\n ...(props.slotProps?.input ?? {}),\n // Only pass startAdornment and endAdornment if they are defined\n ...(renderedStartAdornment && { startAdornment: renderedStartAdornment }),\n ...(renderedEndAdornment && { endAdornment: renderedEndAdornment }),\n },\n htmlInput: {\n ...(props.slotProps?.htmlInput ?? {}),\n 'aria-describedby': ariaDescribedBy,\n },\n }}\n type={getFieldType()}\n variant=\"outlined\"\n {...props}\n />\n </StyledContainer>\n );\n};\n\nexport default TextField;\n"],"names":["StyledContainer","styled","Box","shouldForwardProp","prop","theme","fullWidth","display","flexDirection","gap","spacing","width","StyledTextField","MuiTextField","TextField","disabled","endAdornment","errorText","fdKey","helperText","hidePasswordAriaLabel","label","multiline","required","showPasswordAriaLabel","startAdornment","type","props","showPassword","setShowPassword","useState","helperTextId","undefined","errorMessageId","ariaDescribedBy","filter","Boolean","join","isError","isPassword","handleClickShowPassword","show","renderedEndAdornment","_jsx","MuiInputAdornment","position","children","IconButton","onClick","size","tone","variant","ViewOffIcon","ViewIcon","renderEndAdornment","renderedStartAdornment","renderStartAdornment","_jsxs","MuiInputLabel","htmlFor","MuiFormHelperText","id","error","CancelCircleIcon","slotProps","input","htmlInput"],"mappings":"uhBAuCA,MAAMA,EAAkBC,EAAAA,OAAOC,EAAK,CAClCC,kBAAoBC,GAAkB,cAATA,GADPH,EAEI,EAAGI,QAAOC,aAAY,MAAO,CACvDC,QAAS,OACTC,cAAe,SACfC,IAAKJ,EAAMK,QAAQ,IACnBC,MAAOL,EAAY,OAAS,uBAGxBM,EAAkBX,EAAAA,OAAOY,EAAc,CAC3CV,kBAAoBC,GAAkB,cAATA,GADPH,EAEI,EAAGK,aAAY,MAAO,CAChDC,QAAS,OACTI,MAAOL,EAAY,OAAS,WAGjBQ,EAAY,EACvBC,YAAW,EACXC,eACAC,YACAC,QACAZ,aAAY,EACZa,aACAC,wBACAC,QACAC,aAAY,EACZC,YAAW,EACXC,wBACAC,iBACAC,OAAO,UACJC,MAEH,MAAOC,EAAcC,GAAmBC,EAAAA,UAAkB,GAEpDC,EAAeZ,EAAa,GAAGD,qBAAsBc,EACrDC,EAAiBhB,EAAY,GAAGC,uBAAwBc,EAGxDE,EAAkB,CAACH,EAAcE,GAAgBE,OAAOC,SAASC,KAAK,WAAQL,EAE9EM,IAAYrB,IAAcF,EAC1BwB,EAAsB,aAATb,EAEbc,EAA0B,IAAYX,GAAiBY,IAAUA,IA8CjEC,EApCqB,MACzB,GAAIH,EAAY,CACd,IAAKf,IAA0BJ,EAC7B,OAGF,OACEuB,EAAAA,IAACC,EAAiB,CAACC,SAAS,MAAKC,SAC/BH,MAACI,EAAAA,WAAU,CAAA,aACGnB,EAAeR,EAAwBI,EACnDT,SAAUA,EACViC,QAASR,EACTS,KAAK,QACLC,KAAK,UACLC,QAAQ,WAAUL,SAEjBlB,EAAee,EAAAA,IAACS,EAAW,CAAA,GAAMT,EAAAA,IAACU,EAAQ,CAAA,MAInD,CACA,GAAIrC,EACF,OAAO2B,EAAAA,IAACC,EAAiB,CAACC,SAAS,MAAKC,SAAE9B,KAcjBsC,GACvBC,EATuB,MAC3B,GAAI9B,EACF,OAAOkB,EAAAA,IAACC,EAAiB,CAACC,SAAS,QAAOC,SAAErB,KAOjB+B,GAE/B,OACEC,EAAAA,KAACzD,EAAe,CAACM,UAAWA,YAC1BmD,EAAAA,KAACvD,aACEmB,GACCsB,EAAAA,IAACe,GAAc3C,SAAUA,EAAU4C,QAASzC,EAAOK,SAAUA,EAAQuB,SAClEzB,IAIJF,GACCwB,EAAAA,IAACiB,GAAkB7C,SAAUA,EAAU8C,GAAI9B,EAAYe,SACpD3B,OAKNmB,GACCmB,EAAAA,KAACG,GAAkBE,OAAK,EAACD,GAAI5B,YAC3BU,EAAAA,IAACoB,MAEA9C,KAIL0B,EAAAA,IAAC/B,EAAe,CAAA,UACLM,EACTH,SAAUA,EACV+C,MAAOxB,EACPhC,UAAWA,EACXuD,GAAI3C,EACJG,MAAM,GACNC,UAAWA,EACXC,SAAUA,EACVyC,UAAW,CACTC,MAAO,IACDtC,EAAMqC,WAAWC,OAAS,MAE1BV,GAA0B,CAAE9B,eAAgB8B,MAC5Cb,GAAwB,CAAE1B,aAAc0B,IAE9CwB,UAAW,IACLvC,EAAMqC,WAAWE,WAAa,GAClC,mBAAoBhC,IAGxBR,KA3FAa,EACKX,EAAe,OAAS,WAG1BF,EAwFHyB,QAAQ,cACJxB"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/atoms/TextField/index.tsx"],"sourcesContent":["import { type ReactNode, useState } from 'react';\n\nimport Box from '@mui/material/Box';\nimport MuiFormHelperText from '@mui/material/FormHelperText';\nimport MuiInputAdornment from '@mui/material/InputAdornment';\nimport MuiInputLabel from '@mui/material/InputLabel';\nimport { styled } from '@mui/material/styles';\nimport MuiTextField, { type TextFieldProps as MuiTextFieldProps } from '@mui/material/TextField';\n\nimport CancelCircleIcon from '@fd/icons/CancelCircle';\nimport ViewIcon from '@fd/icons/View';\nimport ViewOffIcon from '@fd/icons/ViewOff';\n\nimport IconButton from '../IconButton';\n\n// Common props for all TextField variants\ntype BaseTextFieldProps = Omit<MuiTextFieldProps, 'error' | 'id' | 'type' | 'variant'> & {\n /** The content rendered at the end of the input (suffix). */\n endAdornment?: ReactNode;\n /** The error text to display. */\n errorText?: string;\n /** The key for the input. */\n fdKey: string;\n /** The content rendered at the start of the input (prefix). */\n startAdornment?: ReactNode;\n};\n\n// Password TextField variant - requires aria labels\ntype PasswordTextFieldProps = BaseTextFieldProps & {\n /** The type of the input. */\n type: 'password';\n /** The aria label for the hide password button. */\n hidePasswordAriaLabel: string;\n /** The aria label for the show password button. */\n showPasswordAriaLabel: string;\n};\n\n// Generic TextField variant - for all other input types\ntype GenericTextFieldProps = BaseTextFieldProps & {\n /** The type of the input. */\n type?: Exclude<MuiTextFieldProps['type'], 'password'>;\n /** The aria label for the hide password button. */\n hidePasswordAriaLabel?: never;\n /** The aria label for the show password button. */\n showPasswordAriaLabel?: never;\n};\n\n/**\n * The props for the TextField component.\n */\nexport type TextFieldProps = GenericTextFieldProps | PasswordTextFieldProps;\n\nconst StyledContainer = styled(Box, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ theme, fullWidth = false }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(0.5),\n width: fullWidth ? '100%' : 'min(364px, 100%)', // Constrain width to a maximum of 100% of the container width\n}));\n\nconst StyledTextField = styled(MuiTextField, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ fullWidth = false }) => ({\n display: 'flex',\n width: fullWidth ? '100%' : 'auto',\n}));\n\nconst StyledInputAdornment = styled(MuiInputAdornment, {\n shouldForwardProp: (prop) => prop !== 'disabled',\n})<{ disabled?: boolean }>(({ theme, disabled = false }) => ({\n color: disabled ? theme.palette.semantic.icon['icon-disabled'] : theme.palette.semantic.icon['icon-strong'],\n}));\n\n/**\n * A TextField component.\n *\n * @param props - The component props\n * @returns The rendered TextField component\n */\nexport const TextField = ({\n disabled = false,\n endAdornment = undefined,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n hidePasswordAriaLabel,\n label,\n multiline = false,\n required = false,\n showPasswordAriaLabel,\n startAdornment = undefined,\n type = 'text',\n ...props\n}: TextFieldProps): JSX.Element => {\n const [showPassword, setShowPassword] = useState<boolean>(false);\n\n const helperTextId = helperText ? `${fdKey}-helper-text` : undefined;\n const errorMessageId = errorText ? `${fdKey}-error-message` : undefined;\n\n // Combine helper text and error message IDs for aria-describedby\n const ariaDescribedBy = [helperTextId, errorMessageId].filter(Boolean).join(' ') || undefined;\n const incomingAriaDescribedBy = (props.slotProps?.htmlInput as Record<string, unknown>)?.[\n 'aria-describedby'\n ] as string | undefined;\n const mergedAriaDescribedBy =\n [incomingAriaDescribedBy, ariaDescribedBy].filter(Boolean).join(' ') || undefined;\n\n const isError = !!errorText && !disabled;\n const isPassword = type === 'password';\n\n const handleClickShowPassword = (): void => setShowPassword((show) => !show);\n\n const getFieldType = (): MuiTextFieldProps['type'] => {\n if (isPassword) {\n return showPassword ? 'text' : 'password';\n }\n\n return type;\n };\n\n const renderEndAdornment = (): React.ReactNode => {\n if (isPassword) {\n if (!showPasswordAriaLabel || !hidePasswordAriaLabel) {\n return undefined;\n }\n\n return (\n <StyledInputAdornment position=\"end\">\n <IconButton\n aria-label={showPassword ? hidePasswordAriaLabel : showPasswordAriaLabel}\n disabled={disabled}\n onClick={handleClickShowPassword}\n size=\"small\"\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n {showPassword ? <ViewOffIcon /> : <ViewIcon />}\n </IconButton>\n </StyledInputAdornment>\n );\n }\n if (endAdornment) {\n return (\n <StyledInputAdornment disabled={disabled} position=\"end\">\n {endAdornment}\n </StyledInputAdornment>\n );\n }\n\n return undefined;\n };\n\n const renderStartAdornment = (): React.ReactNode => {\n if (startAdornment) {\n return (\n <StyledInputAdornment disabled={disabled} position=\"start\">\n {startAdornment}\n </StyledInputAdornment>\n );\n }\n\n return undefined;\n };\n\n const renderedEndAdornment = renderEndAdornment();\n const renderedStartAdornment = renderStartAdornment();\n\n return (\n <StyledContainer fullWidth={fullWidth}>\n <Box>\n {label && (\n <MuiInputLabel disabled={disabled} htmlFor={fdKey} required={required}>\n {label}\n </MuiInputLabel>\n )}\n\n {helperText && (\n <MuiFormHelperText disabled={disabled} id={helperTextId}>\n {helperText}\n </MuiFormHelperText>\n )}\n </Box>\n\n {isError && (\n <MuiFormHelperText error id={errorMessageId}>\n <CancelCircleIcon />\n\n {errorText}\n </MuiFormHelperText>\n )}\n\n <StyledTextField\n {...props}\n data-fd={fdKey}\n disabled={disabled}\n error={isError}\n fullWidth={fullWidth}\n id={fdKey}\n label=\"\" // Remove label from TextField since we're rendering it separately\n multiline={multiline}\n required={required}\n slotProps={{\n input: {\n ...(props.slotProps?.input ?? {}),\n // Only pass startAdornment and endAdornment if they are defined\n ...(renderedStartAdornment && { startAdornment: renderedStartAdornment }),\n ...(renderedEndAdornment && { endAdornment: renderedEndAdornment }),\n },\n htmlInput: {\n ...(props.slotProps?.htmlInput ?? {}),\n 'aria-describedby': mergedAriaDescribedBy,\n },\n }}\n type={getFieldType()}\n variant=\"outlined\"\n />\n </StyledContainer>\n );\n};\n\nexport default TextField;\n"],"names":["StyledContainer","styled","Box","shouldForwardProp","prop","theme","fullWidth","display","flexDirection","gap","spacing","width","StyledTextField","MuiTextField","StyledInputAdornment","MuiInputAdornment","disabled","color","palette","semantic","icon","TextField","endAdornment","errorText","fdKey","helperText","hidePasswordAriaLabel","label","multiline","required","showPasswordAriaLabel","startAdornment","type","props","showPassword","setShowPassword","useState","helperTextId","undefined","errorMessageId","ariaDescribedBy","filter","Boolean","join","incomingAriaDescribedBy","slotProps","htmlInput","mergedAriaDescribedBy","isError","isPassword","handleClickShowPassword","show","renderedEndAdornment","_jsx","position","children","IconButton","onClick","size","tone","variant","ViewOffIcon","ViewIcon","renderEndAdornment","renderedStartAdornment","renderStartAdornment","_jsxs","MuiInputLabel","htmlFor","MuiFormHelperText","id","error","CancelCircleIcon","input"],"mappings":"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"}
|
|
@@ -2,22 +2,41 @@ import { ReactNode } from 'react';
|
|
|
2
2
|
import { TextFieldProps as TextFieldProps$1 } from '@mui/material/TextField';
|
|
3
3
|
|
|
4
4
|
type BaseTextFieldProps = Omit<TextFieldProps$1, 'error' | 'id' | 'type' | 'variant'> & {
|
|
5
|
+
/** The content rendered at the end of the input (suffix). */
|
|
5
6
|
endAdornment?: ReactNode;
|
|
7
|
+
/** The error text to display. */
|
|
6
8
|
errorText?: string;
|
|
9
|
+
/** The key for the input. */
|
|
7
10
|
fdKey: string;
|
|
11
|
+
/** The content rendered at the start of the input (prefix). */
|
|
8
12
|
startAdornment?: ReactNode;
|
|
9
13
|
};
|
|
10
14
|
type PasswordTextFieldProps = BaseTextFieldProps & {
|
|
15
|
+
/** The type of the input. */
|
|
11
16
|
type: 'password';
|
|
17
|
+
/** The aria label for the hide password button. */
|
|
12
18
|
hidePasswordAriaLabel: string;
|
|
19
|
+
/** The aria label for the show password button. */
|
|
13
20
|
showPasswordAriaLabel: string;
|
|
14
21
|
};
|
|
15
22
|
type GenericTextFieldProps = BaseTextFieldProps & {
|
|
23
|
+
/** The type of the input. */
|
|
16
24
|
type?: Exclude<TextFieldProps$1['type'], 'password'>;
|
|
25
|
+
/** The aria label for the hide password button. */
|
|
17
26
|
hidePasswordAriaLabel?: never;
|
|
27
|
+
/** The aria label for the show password button. */
|
|
18
28
|
showPasswordAriaLabel?: never;
|
|
19
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* The props for the TextField component.
|
|
32
|
+
*/
|
|
20
33
|
type TextFieldProps = GenericTextFieldProps | PasswordTextFieldProps;
|
|
34
|
+
/**
|
|
35
|
+
* A TextField component.
|
|
36
|
+
*
|
|
37
|
+
* @param props - The component props
|
|
38
|
+
* @returns The rendered TextField component
|
|
39
|
+
*/
|
|
21
40
|
declare const TextField: ({ disabled, endAdornment, errorText, fdKey, fullWidth, helperText, hidePasswordAriaLabel, label, multiline, required, showPasswordAriaLabel, startAdornment, type, ...props }: TextFieldProps) => JSX.Element;
|
|
22
41
|
|
|
23
42
|
export { TextField, TextField as default };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsxs as
|
|
1
|
+
import{jsxs as i,jsx as r}from"react/jsx-runtime";import{useState as e}from"react";import t from"@mui/material/Box";import o from"@mui/material/FormHelperText";import l from"@mui/material/InputAdornment";import d from"@mui/material/InputLabel";import{styled as n}from"@mui/material/styles";import a from"@mui/material/TextField";import s from"../../../icons/CancelCircle/index.js";import m from"../../../icons/View/index.js";import p from"../../../icons/ViewOff/index.js";import{IconButton as u}from"../IconButton/index.js";const f=n(t,{shouldForwardProp:i=>"fullWidth"!==i})((({theme:i,fullWidth:r=!1})=>({display:"flex",flexDirection:"column",gap:i.spacing(.5),width:r?"100%":"min(364px, 100%)"}))),c=n(a,{shouldForwardProp:i=>"fullWidth"!==i})((({fullWidth:i=!1})=>({display:"flex",width:i?"100%":"auto"}))),h=n(l,{shouldForwardProp:i=>"disabled"!==i})((({theme:i,disabled:r=!1})=>({color:r?i.palette.semantic.icon["icon-disabled"]:i.palette.semantic.icon["icon-strong"]}))),b=({disabled:l=!1,endAdornment:n,errorText:a,fdKey:b,fullWidth:x=!1,helperText:w,hidePasswordAriaLabel:y,label:P,multiline:j=!1,required:A=!1,showPasswordAriaLabel:W,startAdornment:v,type:F="text",...I})=>{const[g,B]=e(!1),T=w?`${b}-helper-text`:void 0,q=a?`${b}-error-message`:void 0,C=[T,q].filter(Boolean).join(" ")||void 0,L=I.slotProps?.htmlInput?.["aria-describedby"],V=[L,C].filter(Boolean).join(" ")||void 0,$=!!a&&!l,k="password"===F,z=()=>B((i=>!i)),D=(()=>{if(k){if(!W||!y)return;return r(h,{position:"end",children:r(u,{"aria-label":g?y:W,disabled:l,onClick:z,size:"small",tone:"neutral",variant:"tertiary",children:r(g?p:m,{})})})}if(n)return r(h,{disabled:l,position:"end",children:n})})(),H=(()=>{if(v)return r(h,{disabled:l,position:"start",children:v})})();return i(f,{fullWidth:x,children:[i(t,{children:[P&&r(d,{disabled:l,htmlFor:b,required:A,children:P}),w&&r(o,{disabled:l,id:T,children:w})]}),$&&i(o,{error:!0,id:q,children:[r(s,{}),a]}),r(c,{...I,"data-fd":b,disabled:l,error:$,fullWidth:x,id:b,label:"",multiline:j,required:A,slotProps:{input:{...I.slotProps?.input??{},...H&&{startAdornment:H},...D&&{endAdornment:D}},htmlInput:{...I.slotProps?.htmlInput??{},"aria-describedby":V}},type:k?g?"text":"password":F,variant:"outlined"})]})};export{b as TextField,b as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/components/atoms/TextField/index.tsx"],"sourcesContent":["import { type ReactNode, useState } from 'react';\n\nimport Box from '@mui/material/Box';\nimport MuiFormHelperText from '@mui/material/FormHelperText';\nimport MuiInputAdornment from '@mui/material/InputAdornment';\nimport MuiInputLabel from '@mui/material/InputLabel';\nimport { styled } from '@mui/material/styles';\nimport MuiTextField, { type TextFieldProps as MuiTextFieldProps } from '@mui/material/TextField';\n\nimport CancelCircleIcon from '@fd/icons/CancelCircle';\nimport ViewIcon from '@fd/icons/View';\nimport ViewOffIcon from '@fd/icons/ViewOff';\n\nimport IconButton from '../IconButton';\n\n// Common props for all TextField variants\ntype BaseTextFieldProps = Omit<MuiTextFieldProps, 'error' | 'id' | 'type' | 'variant'> & {\n endAdornment?: ReactNode;\n errorText?: string;\n fdKey: string;\n startAdornment?: ReactNode;\n};\n\n// Password TextField variant - requires aria labels\ntype PasswordTextFieldProps = BaseTextFieldProps & {\n type: 'password';\n hidePasswordAriaLabel: string;\n showPasswordAriaLabel: string;\n};\n\n// Generic TextField variant - for all other input types\ntype GenericTextFieldProps = BaseTextFieldProps & {\n type?: Exclude<MuiTextFieldProps['type'], 'password'>;\n hidePasswordAriaLabel?: never;\n showPasswordAriaLabel?: never;\n};\n\nexport type TextFieldProps = GenericTextFieldProps | PasswordTextFieldProps;\n\nconst StyledContainer = styled(Box, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ theme, fullWidth = false }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(0.5),\n width: fullWidth ? '100%' : 'min(364px, 100%)', // Constrain width to a maximum of 100% of the container width\n}));\n\nconst StyledTextField = styled(MuiTextField, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ fullWidth = false }) => ({\n display: 'flex',\n width: fullWidth ? '100%' : 'auto',\n}));\n\nexport const TextField = ({\n disabled = false,\n endAdornment = undefined,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n hidePasswordAriaLabel,\n label,\n multiline = false,\n required = false,\n showPasswordAriaLabel,\n startAdornment = undefined,\n type = 'text',\n ...props\n}: TextFieldProps): JSX.Element => {\n const [showPassword, setShowPassword] = useState<boolean>(false);\n\n const helperTextId = helperText ? `${fdKey}-helper-text` : undefined;\n const errorMessageId = errorText ? `${fdKey}-error-message` : undefined;\n\n // Combine helper text and error message IDs for aria-describedby\n const ariaDescribedBy = [helperTextId, errorMessageId].filter(Boolean).join(' ') || undefined;\n\n const isError = !!errorText && !disabled;\n const isPassword = type === 'password';\n\n const handleClickShowPassword = (): void => setShowPassword((show) => !show);\n\n const getFieldType = (): MuiTextFieldProps['type'] => {\n if (isPassword) {\n return showPassword ? 'text' : 'password';\n }\n\n return type;\n };\n\n const renderEndAdornment = (): React.ReactNode => {\n if (isPassword) {\n if (!showPasswordAriaLabel || !hidePasswordAriaLabel) {\n return undefined;\n }\n\n return (\n <MuiInputAdornment position=\"end\">\n <IconButton\n aria-label={showPassword ? hidePasswordAriaLabel : showPasswordAriaLabel}\n disabled={disabled}\n onClick={handleClickShowPassword}\n size=\"small\"\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n {showPassword ? <ViewOffIcon /> : <ViewIcon />}\n </IconButton>\n </MuiInputAdornment>\n );\n }\n if (endAdornment) {\n return <MuiInputAdornment position=\"end\">{endAdornment}</MuiInputAdornment>;\n }\n\n return undefined;\n };\n\n const renderStartAdornment = (): React.ReactNode => {\n if (startAdornment) {\n return <MuiInputAdornment position=\"start\">{startAdornment}</MuiInputAdornment>;\n }\n\n return undefined;\n };\n\n const renderedEndAdornment = renderEndAdornment();\n const renderedStartAdornment = renderStartAdornment();\n\n return (\n <StyledContainer fullWidth={fullWidth}>\n <Box>\n {label && (\n <MuiInputLabel disabled={disabled} htmlFor={fdKey} required={required}>\n {label}\n </MuiInputLabel>\n )}\n\n {helperText && (\n <MuiFormHelperText disabled={disabled} id={helperTextId}>\n {helperText}\n </MuiFormHelperText>\n )}\n </Box>\n\n {isError && (\n <MuiFormHelperText error id={errorMessageId}>\n <CancelCircleIcon />\n\n {errorText}\n </MuiFormHelperText>\n )}\n\n <StyledTextField\n data-fd={fdKey}\n disabled={disabled}\n error={isError}\n fullWidth={fullWidth}\n id={fdKey}\n label=\"\" // Remove label from TextField since we're rendering it separately\n multiline={multiline}\n required={required}\n slotProps={{\n input: {\n ...(props.slotProps?.input ?? {}),\n // Only pass startAdornment and endAdornment if they are defined\n ...(renderedStartAdornment && { startAdornment: renderedStartAdornment }),\n ...(renderedEndAdornment && { endAdornment: renderedEndAdornment }),\n },\n htmlInput: {\n ...(props.slotProps?.htmlInput ?? {}),\n 'aria-describedby': ariaDescribedBy,\n },\n }}\n type={getFieldType()}\n variant=\"outlined\"\n {...props}\n />\n </StyledContainer>\n );\n};\n\nexport default TextField;\n"],"names":["StyledContainer","styled","Box","shouldForwardProp","prop","theme","fullWidth","display","flexDirection","gap","spacing","width","StyledTextField","MuiTextField","TextField","disabled","endAdornment","errorText","fdKey","helperText","hidePasswordAriaLabel","label","multiline","required","showPasswordAriaLabel","startAdornment","type","props","showPassword","setShowPassword","useState","helperTextId","undefined","errorMessageId","ariaDescribedBy","filter","Boolean","join","isError","isPassword","handleClickShowPassword","show","renderedEndAdornment","_jsx","MuiInputAdornment","position","children","IconButton","onClick","size","tone","variant","ViewOffIcon","ViewIcon","renderEndAdornment","renderedStartAdornment","renderStartAdornment","_jsxs","MuiInputLabel","htmlFor","MuiFormHelperText","id","error","CancelCircleIcon","slotProps","input","htmlInput"],"mappings":"4gBAuCA,MAAMA,EAAkBC,EAAOC,EAAK,CAClCC,kBAAoBC,GAAkB,cAATA,GADPH,EAEI,EAAGI,QAAOC,aAAY,MAAO,CACvDC,QAAS,OACTC,cAAe,SACfC,IAAKJ,EAAMK,QAAQ,IACnBC,MAAOL,EAAY,OAAS,uBAGxBM,EAAkBX,EAAOY,EAAc,CAC3CV,kBAAoBC,GAAkB,cAATA,GADPH,EAEI,EAAGK,aAAY,MAAO,CAChDC,QAAS,OACTI,MAAOL,EAAY,OAAS,WAGjBQ,EAAY,EACvBC,YAAW,EACXC,eACAC,YACAC,QACAZ,aAAY,EACZa,aACAC,wBACAC,QACAC,aAAY,EACZC,YAAW,EACXC,wBACAC,iBACAC,OAAO,UACJC,MAEH,MAAOC,EAAcC,GAAmBC,GAAkB,GAEpDC,EAAeZ,EAAa,GAAGD,qBAAsBc,EACrDC,EAAiBhB,EAAY,GAAGC,uBAAwBc,EAGxDE,EAAkB,CAACH,EAAcE,GAAgBE,OAAOC,SAASC,KAAK,WAAQL,EAE9EM,IAAYrB,IAAcF,EAC1BwB,EAAsB,aAATb,EAEbc,EAA0B,IAAYX,GAAiBY,IAAUA,IA8CjEC,EApCqB,MACzB,GAAIH,EAAY,CACd,IAAKf,IAA0BJ,EAC7B,OAGF,OACEuB,EAACC,EAAiB,CAACC,SAAS,MAAKC,SAC/BH,EAACI,EAAU,CAAA,aACGnB,EAAeR,EAAwBI,EACnDT,SAAUA,EACViC,QAASR,EACTS,KAAK,QACLC,KAAK,UACLC,QAAQ,WAAUL,SAEFH,EAAff,EAAgBwB,EAAkBC,EAAP,CAAA,MAIpC,CACA,GAAIrC,EACF,OAAO2B,EAACC,EAAiB,CAACC,SAAS,MAAKC,SAAE9B,KAcjBsC,GACvBC,EATuB,MAC3B,GAAI9B,EACF,OAAOkB,EAACC,EAAiB,CAACC,SAAS,QAAOC,SAAErB,KAOjB+B,GAE/B,OACEC,EAACzD,EAAe,CAACM,UAAWA,YAC1BmD,EAACvD,aACEmB,GACCsB,EAACe,GAAc3C,SAAUA,EAAU4C,QAASzC,EAAOK,SAAUA,EAAQuB,SAClEzB,IAIJF,GACCwB,EAACiB,GAAkB7C,SAAUA,EAAU8C,GAAI9B,EAAYe,SACpD3B,OAKNmB,GACCmB,EAACG,GAAkBE,OAAK,EAACD,GAAI5B,YAC3BU,EAACoB,MAEA9C,KAIL0B,EAAC/B,EAAe,CAAA,UACLM,EACTH,SAAUA,EACV+C,MAAOxB,EACPhC,UAAWA,EACXuD,GAAI3C,EACJG,MAAM,GACNC,UAAWA,EACXC,SAAUA,EACVyC,UAAW,CACTC,MAAO,IACDtC,EAAMqC,WAAWC,OAAS,MAE1BV,GAA0B,CAAE9B,eAAgB8B,MAC5Cb,GAAwB,CAAE1B,aAAc0B,IAE9CwB,UAAW,IACLvC,EAAMqC,WAAWE,WAAa,GAClC,mBAAoBhC,IAGxBR,KA3FAa,EACKX,EAAe,OAAS,WAG1BF,EAwFHyB,QAAQ,cACJxB"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/atoms/TextField/index.tsx"],"sourcesContent":["import { type ReactNode, useState } from 'react';\n\nimport Box from '@mui/material/Box';\nimport MuiFormHelperText from '@mui/material/FormHelperText';\nimport MuiInputAdornment from '@mui/material/InputAdornment';\nimport MuiInputLabel from '@mui/material/InputLabel';\nimport { styled } from '@mui/material/styles';\nimport MuiTextField, { type TextFieldProps as MuiTextFieldProps } from '@mui/material/TextField';\n\nimport CancelCircleIcon from '@fd/icons/CancelCircle';\nimport ViewIcon from '@fd/icons/View';\nimport ViewOffIcon from '@fd/icons/ViewOff';\n\nimport IconButton from '../IconButton';\n\n// Common props for all TextField variants\ntype BaseTextFieldProps = Omit<MuiTextFieldProps, 'error' | 'id' | 'type' | 'variant'> & {\n /** The content rendered at the end of the input (suffix). */\n endAdornment?: ReactNode;\n /** The error text to display. */\n errorText?: string;\n /** The key for the input. */\n fdKey: string;\n /** The content rendered at the start of the input (prefix). */\n startAdornment?: ReactNode;\n};\n\n// Password TextField variant - requires aria labels\ntype PasswordTextFieldProps = BaseTextFieldProps & {\n /** The type of the input. */\n type: 'password';\n /** The aria label for the hide password button. */\n hidePasswordAriaLabel: string;\n /** The aria label for the show password button. */\n showPasswordAriaLabel: string;\n};\n\n// Generic TextField variant - for all other input types\ntype GenericTextFieldProps = BaseTextFieldProps & {\n /** The type of the input. */\n type?: Exclude<MuiTextFieldProps['type'], 'password'>;\n /** The aria label for the hide password button. */\n hidePasswordAriaLabel?: never;\n /** The aria label for the show password button. */\n showPasswordAriaLabel?: never;\n};\n\n/**\n * The props for the TextField component.\n */\nexport type TextFieldProps = GenericTextFieldProps | PasswordTextFieldProps;\n\nconst StyledContainer = styled(Box, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ theme, fullWidth = false }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(0.5),\n width: fullWidth ? '100%' : 'min(364px, 100%)', // Constrain width to a maximum of 100% of the container width\n}));\n\nconst StyledTextField = styled(MuiTextField, {\n shouldForwardProp: (prop) => prop !== 'fullWidth',\n})<{ fullWidth?: boolean }>(({ fullWidth = false }) => ({\n display: 'flex',\n width: fullWidth ? '100%' : 'auto',\n}));\n\nconst StyledInputAdornment = styled(MuiInputAdornment, {\n shouldForwardProp: (prop) => prop !== 'disabled',\n})<{ disabled?: boolean }>(({ theme, disabled = false }) => ({\n color: disabled ? theme.palette.semantic.icon['icon-disabled'] : theme.palette.semantic.icon['icon-strong'],\n}));\n\n/**\n * A TextField component.\n *\n * @param props - The component props\n * @returns The rendered TextField component\n */\nexport const TextField = ({\n disabled = false,\n endAdornment = undefined,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n hidePasswordAriaLabel,\n label,\n multiline = false,\n required = false,\n showPasswordAriaLabel,\n startAdornment = undefined,\n type = 'text',\n ...props\n}: TextFieldProps): JSX.Element => {\n const [showPassword, setShowPassword] = useState<boolean>(false);\n\n const helperTextId = helperText ? `${fdKey}-helper-text` : undefined;\n const errorMessageId = errorText ? `${fdKey}-error-message` : undefined;\n\n // Combine helper text and error message IDs for aria-describedby\n const ariaDescribedBy = [helperTextId, errorMessageId].filter(Boolean).join(' ') || undefined;\n const incomingAriaDescribedBy = (props.slotProps?.htmlInput as Record<string, unknown>)?.[\n 'aria-describedby'\n ] as string | undefined;\n const mergedAriaDescribedBy =\n [incomingAriaDescribedBy, ariaDescribedBy].filter(Boolean).join(' ') || undefined;\n\n const isError = !!errorText && !disabled;\n const isPassword = type === 'password';\n\n const handleClickShowPassword = (): void => setShowPassword((show) => !show);\n\n const getFieldType = (): MuiTextFieldProps['type'] => {\n if (isPassword) {\n return showPassword ? 'text' : 'password';\n }\n\n return type;\n };\n\n const renderEndAdornment = (): React.ReactNode => {\n if (isPassword) {\n if (!showPasswordAriaLabel || !hidePasswordAriaLabel) {\n return undefined;\n }\n\n return (\n <StyledInputAdornment position=\"end\">\n <IconButton\n aria-label={showPassword ? hidePasswordAriaLabel : showPasswordAriaLabel}\n disabled={disabled}\n onClick={handleClickShowPassword}\n size=\"small\"\n tone=\"neutral\"\n variant=\"tertiary\"\n >\n {showPassword ? <ViewOffIcon /> : <ViewIcon />}\n </IconButton>\n </StyledInputAdornment>\n );\n }\n if (endAdornment) {\n return (\n <StyledInputAdornment disabled={disabled} position=\"end\">\n {endAdornment}\n </StyledInputAdornment>\n );\n }\n\n return undefined;\n };\n\n const renderStartAdornment = (): React.ReactNode => {\n if (startAdornment) {\n return (\n <StyledInputAdornment disabled={disabled} position=\"start\">\n {startAdornment}\n </StyledInputAdornment>\n );\n }\n\n return undefined;\n };\n\n const renderedEndAdornment = renderEndAdornment();\n const renderedStartAdornment = renderStartAdornment();\n\n return (\n <StyledContainer fullWidth={fullWidth}>\n <Box>\n {label && (\n <MuiInputLabel disabled={disabled} htmlFor={fdKey} required={required}>\n {label}\n </MuiInputLabel>\n )}\n\n {helperText && (\n <MuiFormHelperText disabled={disabled} id={helperTextId}>\n {helperText}\n </MuiFormHelperText>\n )}\n </Box>\n\n {isError && (\n <MuiFormHelperText error id={errorMessageId}>\n <CancelCircleIcon />\n\n {errorText}\n </MuiFormHelperText>\n )}\n\n <StyledTextField\n {...props}\n data-fd={fdKey}\n disabled={disabled}\n error={isError}\n fullWidth={fullWidth}\n id={fdKey}\n label=\"\" // Remove label from TextField since we're rendering it separately\n multiline={multiline}\n required={required}\n slotProps={{\n input: {\n ...(props.slotProps?.input ?? {}),\n // Only pass startAdornment and endAdornment if they are defined\n ...(renderedStartAdornment && { startAdornment: renderedStartAdornment }),\n ...(renderedEndAdornment && { endAdornment: renderedEndAdornment }),\n },\n htmlInput: {\n ...(props.slotProps?.htmlInput ?? {}),\n 'aria-describedby': mergedAriaDescribedBy,\n },\n }}\n type={getFieldType()}\n variant=\"outlined\"\n />\n </StyledContainer>\n );\n};\n\nexport default TextField;\n"],"names":["StyledContainer","styled","Box","shouldForwardProp","prop","theme","fullWidth","display","flexDirection","gap","spacing","width","StyledTextField","MuiTextField","StyledInputAdornment","MuiInputAdornment","disabled","color","palette","semantic","icon","TextField","endAdornment","errorText","fdKey","helperText","hidePasswordAriaLabel","label","multiline","required","showPasswordAriaLabel","startAdornment","type","props","showPassword","setShowPassword","useState","helperTextId","undefined","errorMessageId","ariaDescribedBy","filter","Boolean","join","incomingAriaDescribedBy","slotProps","htmlInput","mergedAriaDescribedBy","isError","isPassword","handleClickShowPassword","show","renderedEndAdornment","_jsx","position","children","IconButton","onClick","size","tone","variant","ViewOffIcon","ViewIcon","renderEndAdornment","renderedStartAdornment","renderStartAdornment","_jsxs","MuiInputLabel","htmlFor","MuiFormHelperText","id","error","CancelCircleIcon","input"],"mappings":"4gBAoDA,MAAMA,EAAkBC,EAAOC,EAAK,CAClCC,kBAAoBC,GAAkB,cAATA,GADPH,EAEI,EAAGI,QAAOC,aAAY,MAAO,CACvDC,QAAS,OACTC,cAAe,SACfC,IAAKJ,EAAMK,QAAQ,IACnBC,MAAOL,EAAY,OAAS,uBAGxBM,EAAkBX,EAAOY,EAAc,CAC3CV,kBAAoBC,GAAkB,cAATA,GADPH,EAEI,EAAGK,aAAY,MAAO,CAChDC,QAAS,OACTI,MAAOL,EAAY,OAAS,WAGxBQ,EAAuBb,EAAOc,EAAmB,CACrDZ,kBAAoBC,GAAkB,aAATA,GADFH,EAEF,EAAGI,QAAOW,YAAW,MAAO,CACrDC,MAAOD,EAAWX,EAAMa,QAAQC,SAASC,KAAK,iBAAmBf,EAAMa,QAAQC,SAASC,KAAK,mBASlFC,EAAY,EACvBL,YAAW,EACXM,eACAC,YACAC,QACAlB,aAAY,EACZmB,aACAC,wBACAC,QACAC,aAAY,EACZC,YAAW,EACXC,wBACAC,iBACAC,OAAO,UACJC,MAEH,MAAOC,EAAcC,GAAmBC,GAAkB,GAEpDC,EAAeZ,EAAa,GAAGD,qBAAsBc,EACrDC,EAAiBhB,EAAY,GAAGC,uBAAwBc,EAGxDE,EAAkB,CAACH,EAAcE,GAAgBE,OAAOC,SAASC,KAAK,WAAQL,EAC9EM,EAA2BX,EAAMY,WAAWC,YAChD,oBAEIC,EACJ,CAACH,EAAyBJ,GAAiBC,OAAOC,SAASC,KAAK,WAAQL,EAEpEU,IAAYzB,IAAcP,EAC1BiC,EAAsB,aAATjB,EAEbkB,EAA0B,IAAYf,GAAiBgB,IAAUA,IAsDjEC,EA5CqB,MACzB,GAAIH,EAAY,CACd,IAAKnB,IAA0BJ,EAC7B,OAGF,OACE2B,EAACvC,EAAoB,CAACwC,SAAS,MAAKC,SAClCF,EAACG,EAAU,CAAA,aACGtB,EAAeR,EAAwBI,EACnDd,SAAUA,EACVyC,QAASP,EACTQ,KAAK,QACLC,KAAK,UACLC,QAAQ,WAAUL,SAEFF,EAAfnB,EAAgB2B,EAAkBC,EAAP,CAAA,MAIpC,CACA,GAAIxC,EACF,OACE+B,EAACvC,EAAoB,CAACE,SAAUA,EAAUsC,SAAS,MAAKC,SACrDjC,KAoBoByC,GACvBC,EAbuB,MAC3B,GAAIjC,EACF,OACEsB,EAACvC,EAAoB,CAACE,SAAUA,EAAUsC,SAAS,QAAOC,SACvDxB,KASsBkC,GAE/B,OACEC,EAAClE,EAAe,CAACM,UAAWA,YAC1B4D,EAAChE,aACEyB,GACC0B,EAACc,GAAcnD,SAAUA,EAAUoD,QAAS5C,EAAOK,SAAUA,EAAQ0B,SAClE5B,IAIJF,GACC4B,EAACgB,EAAiB,CAACrD,SAAUA,EAAUsD,GAAIjC,EAAYkB,SACpD9B,OAKNuB,GACCkB,EAACG,EAAiB,CAACE,OAAK,EAACD,GAAI/B,EAAcgB,SAAA,CACzCF,EAACmB,EAAgB,CAAA,GAEhBjD,KAIL8B,EAACzC,EAAe,IACVqB,EAAK,UACAT,EACTR,SAAUA,EACVuD,MAAOvB,EACP1C,UAAWA,EACXgE,GAAI9C,EACJG,MAAM,GACNC,UAAWA,EACXC,SAAUA,EACVgB,UAAW,CACT4B,MAAO,IACDxC,EAAMY,WAAW4B,OAAS,MAE1BT,GAA0B,CAAEjC,eAAgBiC,MAC5CZ,GAAwB,CAAE9B,aAAc8B,IAE9CN,UAAW,IACLb,EAAMY,WAAWC,WAAa,GAClC,mBAAoBC,IAGxBf,KApGAiB,EACKf,EAAe,OAAS,WAG1BF,EAiGH4B,QAAQ"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),r=require("react");const s=require("@mui/material/styles").styled("span")((()=>({border:0,clip:"rect(0 0 0 0)",height:1,margin:-1,overflow:"hidden",padding:0,position:"absolute",whiteSpace:"nowrap",width:1}))),a=r.forwardRef((({as:r="span",fdKey:a,...i},d)=>e.jsx(s,{ref:d,as:r,"data-fd":a,...i})));a.displayName="VisuallyHidden";exports.VisuallyHidden=a,exports.default=a,exports.useVisuallyHiddenId=(e="sr-")=>`${e}${r.useId()}`;
|
|
2
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/atoms/VisuallyHidden/index.tsx"],"sourcesContent":["import { forwardRef, useId } from 'react';\n\nimport { styled } from '@mui/material/styles';\n\n/**\n * Props for the VisuallyHidden component.\n */\nexport interface VisuallyHiddenProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** The id of the visually hidden element. */\n id?: string;\n /** The element type to render as. */\n as?: React.ElementType;\n /** The key for the visually hidden element. */\n fdKey: string;\n}\n\nconst Root = styled('span')(() => ({\n border: 0,\n clip: 'rect(0 0 0 0)',\n height: 1,\n margin: -1,\n overflow: 'hidden',\n padding: 0,\n position: 'absolute',\n whiteSpace: 'nowrap',\n width: 1,\n}));\n\n/**\n * A visually hidden component.\n *\n * @param props - The component props\n * @returns The rendered VisuallyHidden component\n */\nexport const VisuallyHidden = forwardRef<HTMLSpanElement, VisuallyHiddenProps>(\n ({ as = 'span', fdKey, ...props }, ref) => {\n return <Root ref={ref} as={as} data-fd={fdKey} {...props} />;\n },\n);\nVisuallyHidden.displayName = 'VisuallyHidden';\n\n/**\n * Generates a unique id for a visually hidden element.\n *\n * @param prefix - The prefix for the id.\n * @returns The generated id.\n */\nexport const useVisuallyHiddenId = (prefix = 'sr-'): string => {\n const reactId = useId();\n return `${prefix}${reactId}`;\n};\n\nexport default VisuallyHidden;\n"],"names":["Root","styled","border","clip","height","margin","overflow","padding","position","whiteSpace","width","VisuallyHidden","forwardRef","as","fdKey","props","ref","_jsx","displayName","prefix","useId"],"mappings":"0HAgBA,MAAMA,kCAAOC,OAAO,OAAPA,EAAe,KAAA,CAC1BC,OAAQ,EACRC,KAAM,gBACNC,OAAQ,EACRC,QAAQ,EACRC,SAAU,SACVC,QAAS,EACTC,SAAU,WACVC,WAAY,SACZC,MAAO,MASIC,EAAiBC,EAAAA,YAC5B,EAAGC,KAAK,OAAQC,WAAUC,GAASC,IAC1BC,MAACjB,EAAI,CAACgB,IAAKA,EAAKH,GAAIA,EAAE,UAAWC,KAAWC,MAGvDJ,EAAeO,YAAc,wFAQM,CAACC,EAAS,QAEpC,GAAGA,IADMC,EAAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props for the VisuallyHidden component.
|
|
5
|
+
*/
|
|
6
|
+
interface VisuallyHiddenProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
7
|
+
/** The id of the visually hidden element. */
|
|
8
|
+
id?: string;
|
|
9
|
+
/** The element type to render as. */
|
|
10
|
+
as?: React.ElementType;
|
|
11
|
+
/** The key for the visually hidden element. */
|
|
12
|
+
fdKey: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A visually hidden component.
|
|
16
|
+
*
|
|
17
|
+
* @param props - The component props
|
|
18
|
+
* @returns The rendered VisuallyHidden component
|
|
19
|
+
*/
|
|
20
|
+
declare const VisuallyHidden: react.ForwardRefExoticComponent<VisuallyHiddenProps & react.RefAttributes<HTMLSpanElement>>;
|
|
21
|
+
/**
|
|
22
|
+
* Generates a unique id for a visually hidden element.
|
|
23
|
+
*
|
|
24
|
+
* @param prefix - The prefix for the id.
|
|
25
|
+
* @returns The generated id.
|
|
26
|
+
*/
|
|
27
|
+
declare const useVisuallyHiddenId: (prefix?: string) => string;
|
|
28
|
+
|
|
29
|
+
export { VisuallyHidden, VisuallyHidden as default, useVisuallyHiddenId };
|
|
30
|
+
export type { VisuallyHiddenProps };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{jsx as a}from"react/jsx-runtime";import{forwardRef as e,useId as r}from"react";import{styled as t}from"@mui/material/styles";const i=t("span")((()=>({border:0,clip:"rect(0 0 0 0)",height:1,margin:-1,overflow:"hidden",padding:0,position:"absolute",whiteSpace:"nowrap",width:1}))),o=e((({as:e="span",fdKey:r,...t},o)=>a(i,{ref:o,as:e,"data-fd":r,...t})));o.displayName="VisuallyHidden";const s=(a="sr-")=>`${a}${r()}`;export{o as VisuallyHidden,o as default,s as useVisuallyHiddenId};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/atoms/VisuallyHidden/index.tsx"],"sourcesContent":["import { forwardRef, useId } from 'react';\n\nimport { styled } from '@mui/material/styles';\n\n/**\n * Props for the VisuallyHidden component.\n */\nexport interface VisuallyHiddenProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** The id of the visually hidden element. */\n id?: string;\n /** The element type to render as. */\n as?: React.ElementType;\n /** The key for the visually hidden element. */\n fdKey: string;\n}\n\nconst Root = styled('span')(() => ({\n border: 0,\n clip: 'rect(0 0 0 0)',\n height: 1,\n margin: -1,\n overflow: 'hidden',\n padding: 0,\n position: 'absolute',\n whiteSpace: 'nowrap',\n width: 1,\n}));\n\n/**\n * A visually hidden component.\n *\n * @param props - The component props\n * @returns The rendered VisuallyHidden component\n */\nexport const VisuallyHidden = forwardRef<HTMLSpanElement, VisuallyHiddenProps>(\n ({ as = 'span', fdKey, ...props }, ref) => {\n return <Root ref={ref} as={as} data-fd={fdKey} {...props} />;\n },\n);\nVisuallyHidden.displayName = 'VisuallyHidden';\n\n/**\n * Generates a unique id for a visually hidden element.\n *\n * @param prefix - The prefix for the id.\n * @returns The generated id.\n */\nexport const useVisuallyHiddenId = (prefix = 'sr-'): string => {\n const reactId = useId();\n return `${prefix}${reactId}`;\n};\n\nexport default VisuallyHidden;\n"],"names":["Root","styled","border","clip","height","margin","overflow","padding","position","whiteSpace","width","VisuallyHidden","forwardRef","as","fdKey","props","ref","_jsx","displayName","useVisuallyHiddenId","prefix","useId"],"mappings":"oIAgBA,MAAMA,EAAOC,EAAO,OAAPA,EAAe,KAAA,CAC1BC,OAAQ,EACRC,KAAM,gBACNC,OAAQ,EACRC,QAAQ,EACRC,SAAU,SACVC,QAAS,EACTC,SAAU,WACVC,WAAY,SACZC,MAAO,MASIC,EAAiBC,GAC5B,EAAGC,KAAK,OAAQC,WAAUC,GAASC,IAC1BC,EAACjB,EAAI,CAACgB,IAAKA,EAAKH,GAAIA,EAAE,UAAWC,KAAWC,MAGvDJ,EAAeO,YAAc,uBAQhBC,EAAsB,CAACC,EAAS,QAEpC,GAAGA,IADMC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react");exports.useDynamicLimitTags=
|
|
1
|
+
"use strict";var e=require("react");exports.useDynamicLimitTags=t=>{const{chipMax:r=130,gap:s=4,horizontalPadding:n=32,reservedPx:a=0}=t??{},i=e.useRef(null),[o,c]=e.useState(1);return e.useLayoutEffect((()=>{const e=i.current;if(!e)return;const t=()=>{const t=e.clientWidth,i=Math.max(0,t-n-a),o=r+s,u=Math.max(1,Math.floor(i/o));c(u)};t();const o=new ResizeObserver(t);return o.observe(e),()=>o.disconnect()}),[r,s,n,a]),{rootRef:i,limitTags:o}};
|
|
2
2
|
//# sourceMappingURL=useDynamicLimitTags.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDynamicLimitTags.cjs.js","sources":["../../../../../src/components/molecules/Autocomplete/hooks/useDynamicLimitTags.ts"],"sourcesContent":["import { useLayoutEffect, useRef, useState } from 'react';\n\nexport interface UseDynamicLimitTagsProps {\n chipMax?: number; // px\n gap?: number; // px, matches theme gap between tags\n horizontalPadding?: number; // px, inputRoot left+right padding\n reservedPx?: number; // px, start/end adornments (icons) and search input width you want to reserve\n}\n\nexport interface UseDynamicLimitTagsReturn {\n rootRef: React.RefObject<HTMLDivElement | null>;\n limitTags: number;\n}\n\nexport
|
|
1
|
+
{"version":3,"file":"useDynamicLimitTags.cjs.js","sources":["../../../../../src/components/molecules/Autocomplete/hooks/useDynamicLimitTags.ts"],"sourcesContent":["import { useLayoutEffect, useRef, useState } from 'react';\n\nexport interface UseDynamicLimitTagsProps {\n chipMax?: number; // px\n gap?: number; // px, matches theme gap between tags\n horizontalPadding?: number; // px, inputRoot left+right padding\n reservedPx?: number; // px, start/end adornments (icons) and search input width you want to reserve\n}\n\nexport interface UseDynamicLimitTagsReturn {\n rootRef: React.RefObject<HTMLDivElement | null>;\n limitTags: number;\n}\n\n/**\n * Calculates the maximum number of tags that can fit within the available space based on the component's width.\n *\n * @param props - The component props\n * @returns The root ref and the limit tags\n */\nexport const useDynamicLimitTags = (props?: UseDynamicLimitTagsProps): UseDynamicLimitTagsReturn => {\n const {\n chipMax = 130,\n gap = 4,\n horizontalPadding = 32, // matches padding: theme.spacing(0.5, 2) → 16px each side\n reservedPx = 0, // tweak if you have more adornments or larger search input\n } = props ?? {};\n\n const rootRef = useRef<HTMLDivElement | null>(null);\n const [limitTags, setLimitTags] = useState<number>(1);\n\n useLayoutEffect(() => {\n const el = rootRef.current;\n if (!el) return;\n\n const update = (): void => {\n const width = el.clientWidth;\n const usable = Math.max(0, width - horizontalPadding - reservedPx);\n const perChip = chipMax + gap;\n const count = Math.max(1, Math.floor(usable / perChip));\n setLimitTags(count);\n };\n\n update();\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return (): void => ro.disconnect();\n }, [chipMax, gap, horizontalPadding, reservedPx]);\n\n return { rootRef, limitTags };\n};\n"],"names":["props","chipMax","gap","horizontalPadding","reservedPx","rootRef","useRef","limitTags","setLimitTags","useState","useLayoutEffect","el","current","update","width","clientWidth","usable","Math","max","perChip","count","floor","ro","ResizeObserver","observe","disconnect"],"mappings":"gEAoBoCA,IAClC,MAAMC,QACJA,EAAU,IAAGC,IACbA,EAAM,EAACC,kBACPA,EAAoB,GAAEC,WACtBA,EAAa,GACXJ,GAAS,CAAA,EAEPK,EAAUC,EAAAA,OAA8B,OACvCC,EAAWC,GAAgBC,EAAAA,SAAiB,GAoBnD,OAlBAC,EAAAA,iBAAgB,KACd,MAAMC,EAAKN,EAAQO,QACnB,IAAKD,EAAI,OAET,MAAME,EAAS,KACb,MAAMC,EAAQH,EAAGI,YACXC,EAASC,KAAKC,IAAI,EAAGJ,EAAQX,EAAoBC,GACjDe,EAAUlB,EAAUC,EACpBkB,EAAQH,KAAKC,IAAI,EAAGD,KAAKI,MAAML,EAASG,IAC9CX,EAAaY,IAGfP,IACA,MAAMS,EAAK,IAAIC,eAAeV,GAE9B,OADAS,EAAGE,QAAQb,GACJ,IAAYW,EAAGG,eACrB,CAACxB,EAASC,EAAKC,EAAmBC,IAE9B,CAAEC,UAASE"}
|
|
@@ -8,7 +8,13 @@ interface UseDynamicLimitTagsReturn {
|
|
|
8
8
|
rootRef: React.RefObject<HTMLDivElement | null>;
|
|
9
9
|
limitTags: number;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Calculates the maximum number of tags that can fit within the available space based on the component's width.
|
|
13
|
+
*
|
|
14
|
+
* @param props - The component props
|
|
15
|
+
* @returns The root ref and the limit tags
|
|
16
|
+
*/
|
|
17
|
+
declare const useDynamicLimitTags: (props?: UseDynamicLimitTagsProps) => UseDynamicLimitTagsReturn;
|
|
12
18
|
|
|
13
19
|
export { useDynamicLimitTags };
|
|
14
20
|
export type { UseDynamicLimitTagsProps, UseDynamicLimitTagsReturn };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useRef as t,useState as r,useLayoutEffect as e}from"react";
|
|
1
|
+
import{useRef as t,useState as r,useLayoutEffect as e}from"react";const n=n=>{const{chipMax:o=130,gap:c=4,horizontalPadding:s=32,reservedPx:a=0}=n??{},i=t(null),[h,l]=r(1);return e((()=>{const t=i.current;if(!t)return;const r=()=>{const r=t.clientWidth,e=Math.max(0,r-s-a),n=o+c,i=Math.max(1,Math.floor(e/n));l(i)};r();const e=new ResizeObserver(r);return e.observe(t),()=>e.disconnect()}),[o,c,s,a]),{rootRef:i,limitTags:h}};export{n as useDynamicLimitTags};
|
|
2
2
|
//# sourceMappingURL=useDynamicLimitTags.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDynamicLimitTags.js","sources":["../../../../../src/components/molecules/Autocomplete/hooks/useDynamicLimitTags.ts"],"sourcesContent":["import { useLayoutEffect, useRef, useState } from 'react';\n\nexport interface UseDynamicLimitTagsProps {\n chipMax?: number; // px\n gap?: number; // px, matches theme gap between tags\n horizontalPadding?: number; // px, inputRoot left+right padding\n reservedPx?: number; // px, start/end adornments (icons) and search input width you want to reserve\n}\n\nexport interface UseDynamicLimitTagsReturn {\n rootRef: React.RefObject<HTMLDivElement | null>;\n limitTags: number;\n}\n\nexport
|
|
1
|
+
{"version":3,"file":"useDynamicLimitTags.js","sources":["../../../../../src/components/molecules/Autocomplete/hooks/useDynamicLimitTags.ts"],"sourcesContent":["import { useLayoutEffect, useRef, useState } from 'react';\n\nexport interface UseDynamicLimitTagsProps {\n chipMax?: number; // px\n gap?: number; // px, matches theme gap between tags\n horizontalPadding?: number; // px, inputRoot left+right padding\n reservedPx?: number; // px, start/end adornments (icons) and search input width you want to reserve\n}\n\nexport interface UseDynamicLimitTagsReturn {\n rootRef: React.RefObject<HTMLDivElement | null>;\n limitTags: number;\n}\n\n/**\n * Calculates the maximum number of tags that can fit within the available space based on the component's width.\n *\n * @param props - The component props\n * @returns The root ref and the limit tags\n */\nexport const useDynamicLimitTags = (props?: UseDynamicLimitTagsProps): UseDynamicLimitTagsReturn => {\n const {\n chipMax = 130,\n gap = 4,\n horizontalPadding = 32, // matches padding: theme.spacing(0.5, 2) → 16px each side\n reservedPx = 0, // tweak if you have more adornments or larger search input\n } = props ?? {};\n\n const rootRef = useRef<HTMLDivElement | null>(null);\n const [limitTags, setLimitTags] = useState<number>(1);\n\n useLayoutEffect(() => {\n const el = rootRef.current;\n if (!el) return;\n\n const update = (): void => {\n const width = el.clientWidth;\n const usable = Math.max(0, width - horizontalPadding - reservedPx);\n const perChip = chipMax + gap;\n const count = Math.max(1, Math.floor(usable / perChip));\n setLimitTags(count);\n };\n\n update();\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return (): void => ro.disconnect();\n }, [chipMax, gap, horizontalPadding, reservedPx]);\n\n return { rootRef, limitTags };\n};\n"],"names":["useDynamicLimitTags","props","chipMax","gap","horizontalPadding","reservedPx","rootRef","useRef","limitTags","setLimitTags","useState","useLayoutEffect","el","current","update","width","clientWidth","usable","Math","max","perChip","count","floor","ro","ResizeObserver","observe","disconnect"],"mappings":"kEAoBO,MAAMA,EAAuBC,IAClC,MAAMC,QACJA,EAAU,IAAGC,IACbA,EAAM,EAACC,kBACPA,EAAoB,GAAEC,WACtBA,EAAa,GACXJ,GAAS,CAAA,EAEPK,EAAUC,EAA8B,OACvCC,EAAWC,GAAgBC,EAAiB,GAoBnD,OAlBAC,GAAgB,KACd,MAAMC,EAAKN,EAAQO,QACnB,IAAKD,EAAI,OAET,MAAME,EAAS,KACb,MAAMC,EAAQH,EAAGI,YACXC,EAASC,KAAKC,IAAI,EAAGJ,EAAQX,EAAoBC,GACjDe,EAAUlB,EAAUC,EACpBkB,EAAQH,KAAKC,IAAI,EAAGD,KAAKI,MAAML,EAASG,IAC9CX,EAAaY,IAGfP,IACA,MAAMS,EAAK,IAAIC,eAAeV,GAE9B,OADAS,EAAGE,QAAQb,GACJ,IAAYW,EAAGG,eACrB,CAACxB,EAASC,EAAKC,EAAmBC,IAE9B,CAAEC,UAASE"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var e=require("react");exports.useShortcutHotkey=({enabled:t=!1,onTrigger:r})=>{const n="undefined"!=typeof navigator&&/Mac|iPod|iPhone|iPad/.test(navigator.platform),o=n?"⌘ + K":"Ctrl + K";return e.useEffect((()=>{if(!t)return;const e=e=>{const t=e.key?.toLowerCase();(n&&e.metaKey&&"k"===t||!n&&e.ctrlKey&&"k"===t)&&(e.preventDefault(),r?.())};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)}),[t,n,r]),{hotkeyText:o}};
|
|
2
|
+
//# sourceMappingURL=useShortcutHotkey.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useShortcutHotkey.cjs.js","sources":["../../../../../src/components/molecules/Autocomplete/hooks/useShortcutHotkey.ts"],"sourcesContent":["import { useEffect } from 'react';\n\nexport interface UseShortcutHotkeyOptions {\n enabled?: boolean;\n onTrigger?: () => void;\n}\n\nexport interface UseShortcutHotkeyResult {\n hotkeyText: string;\n}\n\n/**\n * Sets up a global Cmd/Ctrl + K listener when enabled and returns the platform-appropriate display label.\n *\n * @param props - The component props\n * @returns The hotkey text\n */\nexport const useShortcutHotkey = ({\n enabled = false,\n onTrigger,\n}: UseShortcutHotkeyOptions): UseShortcutHotkeyResult => {\n const isMac = typeof navigator !== 'undefined' && /Mac|iPod|iPhone|iPad/.test(navigator.platform);\n const hotkeyText = isMac ? '⌘ + K' : 'Ctrl + K';\n\n useEffect((): (() => void) | void => {\n if (!enabled) return;\n\n const handler = (e: KeyboardEvent): void => {\n const key = e.key?.toLowerCase();\n if ((isMac && e.metaKey && key === 'k') || (!isMac && e.ctrlKey && key === 'k')) {\n e.preventDefault();\n onTrigger?.();\n }\n };\n\n window.addEventListener('keydown', handler);\n return (): void => window.removeEventListener('keydown', handler);\n }, [enabled, isMac, onTrigger]);\n\n return { hotkeyText };\n};\n"],"names":["enabled","onTrigger","isMac","navigator","test","platform","hotkeyText","useEffect","handler","e","key","toLowerCase","metaKey","ctrlKey","preventDefault","window","addEventListener","removeEventListener"],"mappings":"8DAiBiC,EAC/BA,WAAU,EACVC,gBAEA,MAAMC,EAA6B,oBAAdC,WAA6B,uBAAuBC,KAAKD,UAAUE,UAClFC,EAAaJ,EAAQ,QAAU,WAiBrC,OAfAK,EAAAA,WAAU,KACR,IAAKP,EAAS,OAEd,MAAMQ,EAAWC,IACf,MAAMC,EAAMD,EAAEC,KAAKC,eACdT,GAASO,EAAEG,SAAmB,MAARF,IAAkBR,GAASO,EAAEI,SAAmB,MAARH,KACjED,EAAEK,iBACFb,QAKJ,OADAc,OAAOC,iBAAiB,UAAWR,GAC5B,IAAYO,OAAOE,oBAAoB,UAAWT,KACxD,CAACR,EAASE,EAAOD,IAEb,CAAEK"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface UseShortcutHotkeyOptions {
|
|
2
|
+
enabled?: boolean;
|
|
3
|
+
onTrigger?: () => void;
|
|
4
|
+
}
|
|
5
|
+
interface UseShortcutHotkeyResult {
|
|
6
|
+
hotkeyText: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Sets up a global Cmd/Ctrl + K listener when enabled and returns the platform-appropriate display label.
|
|
10
|
+
*
|
|
11
|
+
* @param props - The component props
|
|
12
|
+
* @returns The hotkey text
|
|
13
|
+
*/
|
|
14
|
+
declare const useShortcutHotkey: ({ enabled, onTrigger, }: UseShortcutHotkeyOptions) => UseShortcutHotkeyResult;
|
|
15
|
+
|
|
16
|
+
export { useShortcutHotkey };
|
|
17
|
+
export type { UseShortcutHotkeyOptions, UseShortcutHotkeyResult };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{useEffect as e}from"react";const t=({enabled:t=!1,onTrigger:n})=>{const o="undefined"!=typeof navigator&&/Mac|iPod|iPhone|iPad/.test(navigator.platform),r=o?"⌘ + K":"Ctrl + K";return e((()=>{if(!t)return;const e=e=>{const t=e.key?.toLowerCase();(o&&e.metaKey&&"k"===t||!o&&e.ctrlKey&&"k"===t)&&(e.preventDefault(),n?.())};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)}),[t,o,n]),{hotkeyText:r}};export{t as useShortcutHotkey};
|
|
2
|
+
//# sourceMappingURL=useShortcutHotkey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useShortcutHotkey.js","sources":["../../../../../src/components/molecules/Autocomplete/hooks/useShortcutHotkey.ts"],"sourcesContent":["import { useEffect } from 'react';\n\nexport interface UseShortcutHotkeyOptions {\n enabled?: boolean;\n onTrigger?: () => void;\n}\n\nexport interface UseShortcutHotkeyResult {\n hotkeyText: string;\n}\n\n/**\n * Sets up a global Cmd/Ctrl + K listener when enabled and returns the platform-appropriate display label.\n *\n * @param props - The component props\n * @returns The hotkey text\n */\nexport const useShortcutHotkey = ({\n enabled = false,\n onTrigger,\n}: UseShortcutHotkeyOptions): UseShortcutHotkeyResult => {\n const isMac = typeof navigator !== 'undefined' && /Mac|iPod|iPhone|iPad/.test(navigator.platform);\n const hotkeyText = isMac ? '⌘ + K' : 'Ctrl + K';\n\n useEffect((): (() => void) | void => {\n if (!enabled) return;\n\n const handler = (e: KeyboardEvent): void => {\n const key = e.key?.toLowerCase();\n if ((isMac && e.metaKey && key === 'k') || (!isMac && e.ctrlKey && key === 'k')) {\n e.preventDefault();\n onTrigger?.();\n }\n };\n\n window.addEventListener('keydown', handler);\n return (): void => window.removeEventListener('keydown', handler);\n }, [enabled, isMac, onTrigger]);\n\n return { hotkeyText };\n};\n"],"names":["useShortcutHotkey","enabled","onTrigger","isMac","navigator","test","platform","hotkeyText","useEffect","handler","e","key","toLowerCase","metaKey","ctrlKey","preventDefault","window","addEventListener","removeEventListener"],"mappings":"kCAiBO,MAAMA,EAAoB,EAC/BC,WAAU,EACVC,gBAEA,MAAMC,EAA6B,oBAAdC,WAA6B,uBAAuBC,KAAKD,UAAUE,UAClFC,EAAaJ,EAAQ,QAAU,WAiBrC,OAfAK,GAAU,KACR,IAAKP,EAAS,OAEd,MAAMQ,EAAWC,IACf,MAAMC,EAAMD,EAAEC,KAAKC,eACdT,GAASO,EAAEG,SAAmB,MAARF,IAAkBR,GAASO,EAAEI,SAAmB,MAARH,KACjED,EAAEK,iBACFb,QAKJ,OADAc,OAAOC,iBAAiB,UAAWR,GAC5B,IAAYO,OAAOE,oBAAoB,UAAWT,KACxD,CAACR,EAASE,EAAOD,IAEb,CAAEK"}
|
|
@@ -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"),s=require("@mui/material/Autocomplete"),t=require("@mui/material/Box"),r=require("@mui/material/InputAdornment"),l=require("@mui/material/styles"),n=require("../../atoms/Badge/index.cjs.js"),a=require("../../atoms/CircularProgress/index.cjs.js"),o=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"),m=require("../../../icons/ArrowDown01/index.cjs.js"),x=require("../../../icons/ArrowUp01/index.cjs.js"),h=require("../../../icons/Cancel/index.cjs.js"),g=require("../../../icons/Search/index.cjs.js"),j=require("../../../utilities/stringUtilities.cjs.js"),y=require("./hooks/useDynamicLimitTags.cjs.js"),b=require("./hooks/useShortcutHotkey.cjs.js");const f=s,T=l.styled(f,{shouldForwardProp:e=>"fullWidth"!==e})((({fullWidth:e=!1})=>({width:e?"100%":"min(364px, 100%)"}))),q=l.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"]}}))),A=l.styled(t)((({theme:e})=>({alignItems:"center",display:"flex",gap:e.spacing(1)}))),k=l.styled("span")((()=>({display:"inline-flex",".Mui-focused &":{display:"none"}}))),v=({ariaLabel:s,className:t,disabled:r=!1,errorText:l,fdKey:f,fullWidth:v=!1,helperText:I,label:P,loading:C=!1,multiple:L=!1,onChange:O,onInputChange:S,options:D=[],placeholder:E,required:F=!1,shortcutHotkey:H=!1,translations:M,type:W="search",value:w})=>{const B=e.useRef(null),[V,z]=e.useState(""),[K,R]=e.useState(!1),N=L?Array.isArray(w)?w:null==w?[]:[w]:Array.isArray(w)?w.length>0?w[0]:null:w??null,U="search"===W,_="combobox"===W,$=(Boolean(V)||Boolean(N))&&!r,G=U&&H&&!N&&!r,J=c.useVisuallyHiddenId(),Q=e.useCallback((()=>{B.current?.focus()}),[]),{hotkeyText:X}=b.useShortcutHotkey({enabled:G,onTrigger:Q}),{rootRef:Y,limitTags:Z}=y.useDynamicLimitTags({chipMax:130,gap:4,horizontalPadding:32,reservedPx:U?120:90});e.useEffect((()=>{K&&(r&&R(!1),U&&0===D.length&&R(!1))}),[K,r,U,D.length]);const ee=e=>{r||U&&0===D.length||R(void 0===e?e=>!e:e)};return i.jsxs(i.Fragment,{children:[i.jsx(T,{ref:Y,className:t,clearIcon:i.jsx(h,{size:"md"}),clearText:M.clearTextAriaLabel,disableClearable:!$,disableCloseOnSelect:L,disabled:r,filterOptions:U?e=>e:void 0,forcePopupIcon:_,freeSolo:U,fullWidth:v,getOptionKey:e=>"string"==typeof e?e:String(e.value),getOptionLabel:e=>"string"==typeof e?e:e.label,inputValue:V,isOptionEqualToValue:(e,i)=>null!=i&&("string"==typeof i?e.label===i||String(e.value)===i:e.value===i.value),limitTags:Z,loading:C,loadingText:M.loadingText,multiple:L,noOptionsText:M.noOptionsText,onChange:(e,i,s,t)=>{O&&O(e,i,s,t)},onClose:()=>ee(!1),onInputChange:(e,i,s)=>{z(i),S&&S(e,i,s)},onOpen:()=>ee(!0),open:K,openText:M.openPopupAriaLabel,options:D,popupIcon:_?i.jsx(q,{disabled:r,position:"end",children:K?i.jsx(x,{}):i.jsx(m,{})}):null,renderInput:e=>{const t=Array.isArray(D)&&D.length>0,o=_||U&&t,d=[e.inputProps["aria-describedby"],G?J:void 0].filter(Boolean).join(" ")||void 0;return i.jsx(u.TextField,{disabled:r,errorText:l,fdKey:f,fullWidth:v,helperText:I,inputRef:B,label:P,placeholder:E,required:F,slotProps:{input:{...e.InputProps,endAdornment:i.jsxs(i.Fragment,{children:[i.jsxs(A,{children:[C?i.jsx(a.CircularProgress,{size:"small"}):null,G?i.jsx(k,{children:i.jsx(n.Badge,{label:X,size:"small",tone:"neutral"})}):null]}),e.InputProps.endAdornment]}),startAdornment:i.jsxs(i.Fragment,{children:[U?i.jsx(q,{disabled:r,position:"start",children:i.jsx(g,{"aria-hidden":"true"})}):null,e.InputProps.startAdornment]})},htmlInput:{...e.inputProps,id:f,"aria-label":U&&!P?s:void 0,"aria-describedby":d,...!o&&{role:"searchbox","aria-autocomplete":"none","aria-invalid":l||F?e.inputProps["aria-invalid"]:void 0}}}})},renderOption:(i,s,t)=>{const{key:r,onClick:l,...n}=i;return L?e.createElement(o.MenuItem,{...n,key:r,checked:t.selected,label:s.label,onCheckedChange:(e,i)=>{l?.(i)},type:"checkbox"}):e.createElement(o.MenuItem,{...n,key:r,label:s.label,onClick:l,selected:t.selected,type:"text"})},renderTags:(e,s)=>e.map(((e,t)=>{const{key:r,onDelete:l,...n}=s({index:t}),a="string"==typeof e?e:e.label,o=j.truncateWithEllipsis(a,13,{includeEllipsisInLimit:!0}),u=o.endsWith("..."),c=r??`tag-${"string"==typeof e?e:e.value}`;return u?i.jsx(p.Tooltip,{title:a,children:i.jsx("span",{...n,children:i.jsx(d.Tag,{dismissAriaLabel:M.dismissTagAriaLabel,label:o,onDismiss:l})})},c):i.jsx("span",{...n,children:i.jsx(d.Tag,{dismissAriaLabel:M.dismissTagAriaLabel,label:o,onDismiss:l})},c)})),slotProps:{popupIndicator:{onClick:e=>{r||(e.stopPropagation(),ee())}}},value:N}),G&&i.jsx(c.VisuallyHidden,{fdKey:"autocomplete-shortcut-hotkey",id:J,children:M.shortcutHotkeyAriaDescription})]})};exports.Autocomplete=v,exports.default=v;
|
|
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 { useEffect, 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 { styled } from '@mui/material/styles';\n\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 CircularProgress from '../../atoms/CircularProgress';\nimport MenuItem from '../../atoms/MenuItem';\nimport Tag from '../../atoms/Tag';\nimport TextField, { type TextFieldProps } from '../../atoms/TextField';\nimport { useDynamicLimitTags } from './hooks/useDynamicLimitTags';\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\n extends Omit<TextFieldProps, 'endAdornment' | 'multiline' | 'onChange' | 'options' | 'startAdornment'> {\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 /** 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 };\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 StyledAdornment = styled(Box, {\n shouldForwardProp: (prop) => !['clickable', 'disabled', 'placement'].includes(prop as string),\n})<{ clickable?: boolean; error?: boolean; disabled?: boolean; placement: 'end' | 'middle' | 'start' }>(\n ({ theme, clickable = false, disabled = false, placement }) => ({\n alignItems: 'center',\n cursor: clickable ? (disabled ? 'not-allowed' : 'pointer') : 'default',\n display: 'flex',\n justifyContent: 'center',\n padding: 0,\n pointerEvents: clickable ? 'auto' : 'none',\n\n ...(placement === 'start' && { paddingRight: theme.spacing(1) }),\n ...(placement === 'middle' && { padding: theme.spacing(0, 1) }),\n\n '& svg': {\n color: disabled\n ? theme.palette.semantic.icon['icon-disabled']\n : theme.palette.semantic.icon['icon-strong'],\n },\n }),\n);\n\nconst StyledLoadingSpinnerContainer = styled(Box, {\n shouldForwardProp: (prop) => prop !== 'placement',\n})<{ placement?: 'end' | 'middle' | 'start' }>(({ theme, placement }) => ({\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'center',\n padding: 0,\n\n ...(placement === 'start' && { paddingRight: theme.spacing(1) }),\n ...(placement === 'middle' && { padding: theme.spacing(0, 1) }),\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 className,\n disabled = false,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n label,\n loading = false,\n multiple = false,\n placeholder,\n onChange,\n onInputChange,\n options = [],\n required = false,\n translations,\n type = 'search',\n value,\n}: AutocompleteProps): JSX.Element => {\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const isSearch = type === 'search';\n const isCombobox = type === 'combobox';\n\n const { rootRef, limitTags } = useDynamicLimitTags({\n chipMax: 130,\n gap: 4,\n horizontalPadding: 32,\n reservedPx: isSearch ? 120 : 90,\n });\n\n // Close the dropdown (if open) when the component is dynamically disabled\n useEffect(() => {\n if (disabled) {\n setIsOpen(false);\n }\n }, [disabled]);\n\n /**\n * Toggles or sets the dropdown open state.\n * Does nothing when the component is disabled.\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) {\n return;\n }\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 <StyledAdornment disabled={disabled} placement=\"start\">\n <SearchIcon aria-hidden=\"true\" />\n </StyledAdornment>\n );\n };\n\n const renderPopupIcon = (): JSX.Element => {\n return (\n <StyledAdornment clickable disabled={disabled} placement=\"end\">\n {isOpen ? <ArrowUp01Icon /> : <ArrowDown01Icon />}\n </StyledAdornment>\n );\n };\n\n const renderLoadingSpinner = (): JSX.Element => {\n return (\n <StyledLoadingSpinnerContainer placement={isSearch ? 'end' : 'middle'}>\n <CircularProgress size=\"small\" />\n </StyledLoadingSpinnerContainer>\n );\n };\n\n const renderInputField = (params: AutocompleteRenderInputParams): JSX.Element => (\n <TextField\n disabled={disabled}\n errorText={errorText}\n fdKey={fdKey}\n fullWidth={fullWidth}\n helperText={helperText}\n label={label}\n placeholder={placeholder}\n required={required}\n slotProps={{\n input: {\n ...params.InputProps,\n endAdornment: (\n <>\n {loading ? renderLoadingSpinner() : null}\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 },\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 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 /**\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 return (\n <StyledAutocomplete\n ref={rootRef}\n className={className}\n clearIcon={<CancelIcon size=\"md\" />}\n clearText={translations.clearTextAriaLabel}\n disableClearable={disabled || loading}\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 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={isSearch ? null : renderPopupIcon()}\n renderInput={renderInputField}\n renderOption={renderMenuOption}\n renderTags={renderSelectedTags}\n slotProps={{\n popupIndicator: {\n onClick: handlePopupIndicatorClick,\n },\n }}\n value={getValue()}\n />\n );\n};\n\nexport default Autocomplete;\n"],"names":["MuiCustomAutocomplete","StyledAutocomplete","styled","shouldForwardProp","prop","fullWidth","width","StyledAdornment","Box","includes","theme","clickable","disabled","placement","alignItems","cursor","display","justifyContent","padding","pointerEvents","paddingRight","spacing","color","palette","semantic","icon","StyledLoadingSpinnerContainer","Autocomplete","className","errorText","fdKey","helperText","label","loading","multiple","placeholder","onChange","onInputChange","options","required","translations","type","value","isOpen","setIsOpen","useState","isSearch","isCombobox","rootRef","limitTags","useDynamicLimitTags","chipMax","gap","horizontalPadding","reservedPx","useEffect","toggleOpen","open","undefined","prevOpen","_jsx","ref","clearIcon","CancelIcon","size","clearText","clearTextAriaLabel","disableClearable","disableCloseOnSelect","filterOptions","opts","forcePopupIcon","freeSolo","getOptionKey","option","String","getOptionLabel","isOptionEqualToValue","a","b","loadingText","noOptionsText","event","reason","details","onClose","onOpen","openText","openPopupAriaLabel","popupIcon","children","ArrowUp01Icon","ArrowDown01Icon","renderInput","params","TextField","slotProps","input","InputProps","endAdornment","_jsxs","_Fragment","CircularProgress","startAdornment","SearchIcon","htmlInput","inputProps","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","Array","isArray","length"],"mappings":"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"}
|
|
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":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AutocompleteProps as AutocompleteProps$1 } from '@mui/material/Autocomplete';
|
|
2
|
-
import { TextFieldProps } from '
|
|
2
|
+
import { TextFieldProps } from '@fd/components/atoms/TextField';
|
|
3
3
|
|
|
4
4
|
type MuiCustomAutocompleteProps<M extends boolean = boolean, // Multiple
|
|
5
5
|
DC extends boolean = boolean, // DisableClearable
|
|
@@ -18,6 +18,8 @@ interface AutocompleteOption {
|
|
|
18
18
|
* Supports both single and multiple selection modes with optional search functionality.
|
|
19
19
|
*/
|
|
20
20
|
interface AutocompleteProps extends Omit<TextFieldProps, 'endAdornment' | 'multiline' | 'onChange' | 'options' | 'startAdornment'> {
|
|
21
|
+
/** Aria-label for the input when no label is provided. */
|
|
22
|
+
ariaLabel?: string;
|
|
21
23
|
/** Shows a loading indicator inside the input (e.g., while fetching). */
|
|
22
24
|
loading?: boolean;
|
|
23
25
|
/** Enables selection of multiple options and shows checkboxes and tags for selected values. */
|
|
@@ -28,6 +30,8 @@ interface AutocompleteProps extends Omit<TextFieldProps, 'endAdornment' | 'multi
|
|
|
28
30
|
onInputChange?: MuiCustomAutocompleteProps['onInputChange'];
|
|
29
31
|
/** Options to display in the dropdown list. */
|
|
30
32
|
options: AutocompleteOption[];
|
|
33
|
+
/** Shows the keyboard shortcut badge (Cmd/Ctrl + K) and enables focusing via the shortcut when in search mode. */
|
|
34
|
+
shortcutHotkey?: boolean;
|
|
31
35
|
/** UI and accessibility labels used by the component. */
|
|
32
36
|
translations: {
|
|
33
37
|
/** Aria-label for the clear button. */
|
|
@@ -40,6 +44,8 @@ interface AutocompleteProps extends Omit<TextFieldProps, 'endAdornment' | 'multi
|
|
|
40
44
|
noOptionsText: string;
|
|
41
45
|
/** Aria-label for the popup indicator button. */
|
|
42
46
|
openPopupAriaLabel: string;
|
|
47
|
+
/** Screen reader hint describing the shortcut, e.g., "Press ⌘+K to focus search". */
|
|
48
|
+
shortcutHotkeyAriaDescription: string;
|
|
43
49
|
};
|
|
44
50
|
/** Visual behavior: 'search' shows a leading search icon; 'combobox' shows a popup button. */
|
|
45
51
|
type?: 'combobox' | 'search';
|
|
@@ -53,7 +59,7 @@ interface AutocompleteProps extends Omit<TextFieldProps, 'endAdornment' | 'multi
|
|
|
53
59
|
* @param props - The component props
|
|
54
60
|
* @returns The rendered Autocomplete component
|
|
55
61
|
*/
|
|
56
|
-
declare const Autocomplete: ({ className, disabled, errorText, fdKey, fullWidth, helperText, label, loading, multiple,
|
|
62
|
+
declare const Autocomplete: ({ ariaLabel, className, disabled, errorText, fdKey, fullWidth, helperText, label, loading, multiple, onChange, onInputChange, options, placeholder, required, shortcutHotkey, translations, type, value, }: AutocompleteProps) => JSX.Element;
|
|
57
63
|
|
|
58
64
|
export { Autocomplete, Autocomplete as default };
|
|
59
65
|
export type { AutocompleteOption, AutocompleteProps };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{useRef as e,useState as i,useCallback as o,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 u}from"../../atoms/Badge/index.js";import{CircularProgress as c}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 b,VisuallyHidden as x}from"../../atoms/VisuallyHidden/index.js";import{Tooltip as y}from"../Tooltip/index.js";import T from"../../../icons/ArrowDown01/index.js";import A from"../../../icons/ArrowUp01/index.js";import k from"../../../icons/Cancel/index.js";import v from"../../../icons/Search/index.js";import{truncateWithEllipsis as j}from"../../../utilities/stringUtilities.js";import{useDynamicLimitTags as I}from"./hooks/useDynamicLimitTags.js";import{useShortcutHotkey as P}from"./hooks/useShortcutHotkey.js";const C=m(s,{shouldForwardProp:e=>"fullWidth"!==e})((({fullWidth:e=!1})=>({width:e?"100%":"min(364px, 100%)"}))),L=m(p,{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"]}}))),O=m(d)((({theme:e})=>({alignItems:"center",display:"flex",gap:e.spacing(1)}))),w=m("span")((()=>({display:"inline-flex",".Mui-focused &":{display:"none"}}))),D=({ariaLabel:s,className:d,disabled:p=!1,errorText:m,fdKey:D,fullWidth:S=!1,helperText:W,label:B,loading:z=!1,multiple:H=!1,onChange:K,onInputChange:M,options:q=[],placeholder:E,required:F=!1,shortcutHotkey:V=!1,translations:N,type:R="search",value:U})=>{const $=e(null),[G,J]=i(""),[Q,X]=i(!1),Y=H?Array.isArray(U)?U:null==U?[]:[U]:Array.isArray(U)?U.length>0?U[0]:null:U??null,Z="search"===R,_="combobox"===R,ee=(Boolean(G)||Boolean(Y))&&!p,ie=Z&&V&&!Y&&!p,oe=b(),te=o((()=>{$.current?.focus()}),[]),{hotkeyText:re}=P({enabled:ie,onTrigger:te}),{rootRef:ne,limitTags:le}=I({chipMax:130,gap:4,horizontalPadding:32,reservedPx:Z?120:90});t((()=>{Q&&(p&&X(!1),Z&&0===q.length&&X(!1))}),[Q,p,Z,q.length]);const ae=e=>{p||Z&&0===q.length||X(void 0===e?e=>!e:e)};return n(l,{children:[a(C,{ref:ne,className:d,clearIcon:a(k,{size:"md"}),clearText:N.clearTextAriaLabel,disableClearable:!ee,disableCloseOnSelect:H,disabled:p,filterOptions:Z?e=>e:void 0,forcePopupIcon:_,freeSolo:Z,fullWidth:S,getOptionKey:e=>"string"==typeof e?e:String(e.value),getOptionLabel:e=>"string"==typeof e?e:e.label,inputValue:G,isOptionEqualToValue:(e,i)=>null!=i&&("string"==typeof i?e.label===i||String(e.value)===i:e.value===i.value),limitTags:le,loading:z,loadingText:N.loadingText,multiple:H,noOptionsText:N.noOptionsText,onChange:(e,i,o,t)=>{K&&K(e,i,o,t)},onClose:()=>ae(!1),onInputChange:(e,i,o)=>{J(i),M&&M(e,i,o)},onOpen:()=>ae(!0),open:Q,openText:N.openPopupAriaLabel,options:q,popupIcon:_?a(L,{disabled:p,position:"end",children:a(Q?A:T,{})}):null,renderInput:e=>{const i=Array.isArray(q)&&q.length>0,o=_||Z&&i,t=[e.inputProps["aria-describedby"],ie?oe:void 0].filter(Boolean).join(" ")||void 0;return a(g,{disabled:p,errorText:m,fdKey:D,fullWidth:S,helperText:W,inputRef:$,label:B,placeholder:E,required:F,slotProps:{input:{...e.InputProps,endAdornment:n(l,{children:[n(O,{children:[z?a(c,{size:"small"}):null,ie?a(w,{children:a(u,{label:re,size:"small",tone:"neutral"})}):null]}),e.InputProps.endAdornment]}),startAdornment:n(l,{children:[Z?a(L,{disabled:p,position:"start",children:a(v,{"aria-hidden":"true"})}):null,e.InputProps.startAdornment]})},htmlInput:{...e.inputProps,id:D,"aria-label":Z&&!B?s:void 0,"aria-describedby":t,...!o&&{role:"searchbox","aria-autocomplete":"none","aria-invalid":m||F?e.inputProps["aria-invalid"]:void 0}}}})},renderOption:(e,i,o)=>{const{key:t,onClick:n,...l}=e;return r(h,H?{...l,key:t,checked:o.selected,label:i.label,onCheckedChange:(e,i)=>{n?.(i)},type:"checkbox"}:{...l,key:t,label:i.label,onClick:n,selected:o.selected,type:"text"})},renderTags:(e,i)=>e.map(((e,o)=>{const{key:t,onDelete:r,...n}=i({index:o}),l="string"==typeof e?e:e.label,s=j(l,13,{includeEllipsisInLimit:!0}),d=s.endsWith("..."),p=t??`tag-${"string"==typeof e?e:e.value}`;return d?a(y,{title:l,children:a("span",{...n,children:a(f,{dismissAriaLabel:N.dismissTagAriaLabel,label:s,onDismiss:r})})},p):a("span",{...n,children:a(f,{dismissAriaLabel:N.dismissTagAriaLabel,label:s,onDismiss:r})},p)})),slotProps:{popupIndicator:{onClick:e=>{p||(e.stopPropagation(),ae())}}},value:Y}),ie&&a(x,{fdKey:"autocomplete-shortcut-hotkey",id:oe,children:N.shortcutHotkeyAriaDescription})]})};export{D as Autocomplete,D 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 { useEffect, 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 { styled } from '@mui/material/styles';\n\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 CircularProgress from '../../atoms/CircularProgress';\nimport MenuItem from '../../atoms/MenuItem';\nimport Tag from '../../atoms/Tag';\nimport TextField, { type TextFieldProps } from '../../atoms/TextField';\nimport { useDynamicLimitTags } from './hooks/useDynamicLimitTags';\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\n extends Omit<TextFieldProps, 'endAdornment' | 'multiline' | 'onChange' | 'options' | 'startAdornment'> {\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 /** 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 };\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 StyledAdornment = styled(Box, {\n shouldForwardProp: (prop) => !['clickable', 'disabled', 'placement'].includes(prop as string),\n})<{ clickable?: boolean; error?: boolean; disabled?: boolean; placement: 'end' | 'middle' | 'start' }>(\n ({ theme, clickable = false, disabled = false, placement }) => ({\n alignItems: 'center',\n cursor: clickable ? (disabled ? 'not-allowed' : 'pointer') : 'default',\n display: 'flex',\n justifyContent: 'center',\n padding: 0,\n pointerEvents: clickable ? 'auto' : 'none',\n\n ...(placement === 'start' && { paddingRight: theme.spacing(1) }),\n ...(placement === 'middle' && { padding: theme.spacing(0, 1) }),\n\n '& svg': {\n color: disabled\n ? theme.palette.semantic.icon['icon-disabled']\n : theme.palette.semantic.icon['icon-strong'],\n },\n }),\n);\n\nconst StyledLoadingSpinnerContainer = styled(Box, {\n shouldForwardProp: (prop) => prop !== 'placement',\n})<{ placement?: 'end' | 'middle' | 'start' }>(({ theme, placement }) => ({\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'center',\n padding: 0,\n\n ...(placement === 'start' && { paddingRight: theme.spacing(1) }),\n ...(placement === 'middle' && { padding: theme.spacing(0, 1) }),\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 className,\n disabled = false,\n errorText,\n fdKey,\n fullWidth = false,\n helperText,\n label,\n loading = false,\n multiple = false,\n placeholder,\n onChange,\n onInputChange,\n options = [],\n required = false,\n translations,\n type = 'search',\n value,\n}: AutocompleteProps): JSX.Element => {\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const isSearch = type === 'search';\n const isCombobox = type === 'combobox';\n\n const { rootRef, limitTags } = useDynamicLimitTags({\n chipMax: 130,\n gap: 4,\n horizontalPadding: 32,\n reservedPx: isSearch ? 120 : 90,\n });\n\n // Close the dropdown (if open) when the component is dynamically disabled\n useEffect(() => {\n if (disabled) {\n setIsOpen(false);\n }\n }, [disabled]);\n\n /**\n * Toggles or sets the dropdown open state.\n * Does nothing when the component is disabled.\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) {\n return;\n }\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 <StyledAdornment disabled={disabled} placement=\"start\">\n <SearchIcon aria-hidden=\"true\" />\n </StyledAdornment>\n );\n };\n\n const renderPopupIcon = (): JSX.Element => {\n return (\n <StyledAdornment clickable disabled={disabled} placement=\"end\">\n {isOpen ? <ArrowUp01Icon /> : <ArrowDown01Icon />}\n </StyledAdornment>\n );\n };\n\n const renderLoadingSpinner = (): JSX.Element => {\n return (\n <StyledLoadingSpinnerContainer placement={isSearch ? 'end' : 'middle'}>\n <CircularProgress size=\"small\" />\n </StyledLoadingSpinnerContainer>\n );\n };\n\n const renderInputField = (params: AutocompleteRenderInputParams): JSX.Element => (\n <TextField\n disabled={disabled}\n errorText={errorText}\n fdKey={fdKey}\n fullWidth={fullWidth}\n helperText={helperText}\n label={label}\n placeholder={placeholder}\n required={required}\n slotProps={{\n input: {\n ...params.InputProps,\n endAdornment: (\n <>\n {loading ? renderLoadingSpinner() : null}\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 },\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 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 /**\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 return (\n <StyledAutocomplete\n ref={rootRef}\n className={className}\n clearIcon={<CancelIcon size=\"md\" />}\n clearText={translations.clearTextAriaLabel}\n disableClearable={disabled || loading}\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 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={isSearch ? null : renderPopupIcon()}\n renderInput={renderInputField}\n renderOption={renderMenuOption}\n renderTags={renderSelectedTags}\n slotProps={{\n popupIndicator: {\n onClick: handlePopupIndicatorClick,\n },\n }}\n value={getValue()}\n />\n );\n};\n\nexport default Autocomplete;\n"],"names":["StyledAutocomplete","styled","shouldForwardProp","prop","fullWidth","width","StyledAdornment","Box","includes","theme","clickable","disabled","placement","alignItems","cursor","display","justifyContent","padding","pointerEvents","paddingRight","spacing","color","palette","semantic","icon","StyledLoadingSpinnerContainer","Autocomplete","className","errorText","fdKey","helperText","label","loading","multiple","placeholder","onChange","onInputChange","options","required","translations","type","value","isOpen","setIsOpen","useState","isSearch","isCombobox","rootRef","limitTags","useDynamicLimitTags","chipMax","gap","horizontalPadding","reservedPx","useEffect","toggleOpen","open","undefined","prevOpen","_jsx","ref","clearIcon","CancelIcon","size","clearText","clearTextAriaLabel","disableClearable","disableCloseOnSelect","filterOptions","opts","forcePopupIcon","freeSolo","getOptionKey","option","String","getOptionLabel","isOptionEqualToValue","a","b","loadingText","noOptionsText","event","reason","details","onClose","onOpen","openText","openPopupAriaLabel","popupIcon","children","ArrowUp01Icon","ArrowDown01Icon","renderInput","params","TextField","slotProps","input","InputProps","endAdornment","_jsxs","_Fragment","CircularProgress","startAdornment","SearchIcon","htmlInput","inputProps","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","Array","isArray","length"],"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 { 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/molecules/Combobox/index.tsx"],"sourcesContent":["import Autocomplete, { type AutocompleteOption, type AutocompleteProps } from '../Autocomplete';\n\nexport type ComboboxOption = AutocompleteOption;\n\nexport type ComboboxProps = Omit<AutocompleteProps, 'type'>;\n\nexport const Combobox = (props: ComboboxProps): JSX.Element => {\n return <Autocomplete {...props} type=\"combobox\" />;\n};\n\nexport default Combobox;\n"],"names":["Combobox","props","_jsx","Autocomplete","type"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/molecules/Combobox/index.tsx"],"sourcesContent":["import Autocomplete, { type AutocompleteOption, type AutocompleteProps } from '../Autocomplete';\n\n/**\n * The option type for the Combobox component.\n */\nexport type ComboboxOption = AutocompleteOption;\n\n/**\n * The props for the Combobox component.\n */\nexport type ComboboxProps = Omit<AutocompleteProps, 'shortcutHotkey' | 'type'>;\n\n/**\n * A Combobox component.\n *\n * @param props - The component props\n * @returns The rendered Combobox component\n */\nexport const Combobox = (props: ComboboxProps): JSX.Element => {\n return <Autocomplete {...props} type=\"combobox\" />;\n};\n\nexport default Combobox;\n"],"names":["Combobox","props","_jsx","Autocomplete","type"],"mappings":"iJAkBO,MAAMA,EAAYC,GAChBC,EAAAA,IAACC,EAAAA,aAAY,IAAKF,EAAOG,KAAK"}
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { AutocompleteOption, AutocompleteProps } from '../Autocomplete/index.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The option type for the Combobox component.
|
|
5
|
+
*/
|
|
3
6
|
type ComboboxOption = AutocompleteOption;
|
|
4
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The props for the Combobox component.
|
|
9
|
+
*/
|
|
10
|
+
type ComboboxProps = Omit<AutocompleteProps, 'shortcutHotkey' | 'type'>;
|
|
11
|
+
/**
|
|
12
|
+
* A Combobox component.
|
|
13
|
+
*
|
|
14
|
+
* @param props - The component props
|
|
15
|
+
* @returns The rendered Combobox component
|
|
16
|
+
*/
|
|
5
17
|
declare const Combobox: (props: ComboboxProps) => JSX.Element;
|
|
6
18
|
|
|
7
19
|
export { Combobox, Combobox as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/components/molecules/Combobox/index.tsx"],"sourcesContent":["import Autocomplete, { type AutocompleteOption, type AutocompleteProps } from '../Autocomplete';\n\nexport type ComboboxOption = AutocompleteOption;\n\nexport type ComboboxProps = Omit<AutocompleteProps, 'type'>;\n\nexport const Combobox = (props: ComboboxProps): JSX.Element => {\n return <Autocomplete {...props} type=\"combobox\" />;\n};\n\nexport default Combobox;\n"],"names":["Combobox","props","_jsx","Autocomplete","type"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/molecules/Combobox/index.tsx"],"sourcesContent":["import Autocomplete, { type AutocompleteOption, type AutocompleteProps } from '../Autocomplete';\n\n/**\n * The option type for the Combobox component.\n */\nexport type ComboboxOption = AutocompleteOption;\n\n/**\n * The props for the Combobox component.\n */\nexport type ComboboxProps = Omit<AutocompleteProps, 'shortcutHotkey' | 'type'>;\n\n/**\n * A Combobox component.\n *\n * @param props - The component props\n * @returns The rendered Combobox component\n */\nexport const Combobox = (props: ComboboxProps): JSX.Element => {\n return <Autocomplete {...props} type=\"combobox\" />;\n};\n\nexport default Combobox;\n"],"names":["Combobox","props","_jsx","Autocomplete","type"],"mappings":"gGAkBO,MAAMA,EAAYC,GAChBC,EAACC,EAAY,IAAKF,EAAOG,KAAK"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),t=require("../Autocomplete/index.cjs.js");const a=({ariaLabel:a,clearTextAriaLabel:r,onChange:o,shortcutHotkeyAriaDescription:i,...s})=>e.jsx(t.Autocomplete,{...s,ariaLabel:a,multiple:!1,onChange:()=>{},onInputChange:o,options:[],translations:{clearTextAriaLabel:r,shortcutHotkeyAriaDescription:i,dismissTagAriaLabel:"",loadingText:"",noOptionsText:"",openPopupAriaLabel:""},type:"search"});exports.SearchInput=a,exports.default=a;
|
|
2
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../../../src/components/molecules/SearchInput/index.tsx"],"sourcesContent":["import Autocomplete, { type AutocompleteProps } from '../Autocomplete';\n\n/**\n * The props for the SearchInput component.\n */\nexport type SearchInputProps = Omit<\n AutocompleteProps,\n | 'errorText'\n | 'helperText'\n | 'label'\n | 'multiple'\n | 'onChange'\n | 'onInputChange'\n | 'options'\n | 'required'\n | 'translations'\n | 'type'\n> & {\n /** Aria-label for the search input. */\n ariaLabel: string;\n /** Aria-label for the clear button. */\n clearTextAriaLabel: AutocompleteProps['translations']['clearTextAriaLabel'];\n /** Called when the input text changes. */\n onChange: AutocompleteProps['onInputChange'];\n /** Screen reader hint describing the shortcut, e.g., \"Press ⌘+K to focus search\". */\n shortcutHotkeyAriaDescription: AutocompleteProps['translations']['shortcutHotkeyAriaDescription'];\n};\n\n/**\n * A SearchInput component.\n *\n * @param props - The component props\n * @returns The rendered SearchInput component\n */\nexport const SearchInput = ({\n ariaLabel,\n clearTextAriaLabel,\n onChange,\n shortcutHotkeyAriaDescription,\n ...props\n}: SearchInputProps): JSX.Element => {\n return (\n <Autocomplete\n {...props}\n ariaLabel={ariaLabel}\n multiple={false}\n onChange={() => {}}\n onInputChange={onChange}\n options={[]}\n translations={{\n clearTextAriaLabel,\n shortcutHotkeyAriaDescription,\n dismissTagAriaLabel: '',\n loadingText: '',\n noOptionsText: '',\n openPopupAriaLabel: '',\n }}\n type=\"search\"\n />\n );\n};\n\nexport default SearchInput;\n"],"names":["SearchInput","ariaLabel","clearTextAriaLabel","onChange","shortcutHotkeyAriaDescription","props","_jsx","Autocomplete","multiple","onInputChange","options","translations","dismissTagAriaLabel","loadingText","noOptionsText","openPopupAriaLabel","type"],"mappings":"iJAkCO,MAAMA,EAAc,EACzBC,YACAC,qBACAC,WACAC,mCACGC,KAGDC,EAAAA,IAACC,EAAAA,aAAY,IACPF,EACJJ,UAAWA,EACXO,UAAU,EACVL,SAAU,OACVM,cAAeN,EACfO,QAAS,GACTC,aAAc,CACZT,qBACAE,gCACAQ,oBAAqB,GACrBC,YAAa,GACbC,cAAe,GACfC,mBAAoB,IAEtBC,KAAK"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AutocompleteProps } from '../Autocomplete/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The props for the SearchInput component.
|
|
5
|
+
*/
|
|
6
|
+
type SearchInputProps = Omit<AutocompleteProps, 'errorText' | 'helperText' | 'label' | 'multiple' | 'onChange' | 'onInputChange' | 'options' | 'required' | 'translations' | 'type'> & {
|
|
7
|
+
/** Aria-label for the search input. */
|
|
8
|
+
ariaLabel: string;
|
|
9
|
+
/** Aria-label for the clear button. */
|
|
10
|
+
clearTextAriaLabel: AutocompleteProps['translations']['clearTextAriaLabel'];
|
|
11
|
+
/** Called when the input text changes. */
|
|
12
|
+
onChange: AutocompleteProps['onInputChange'];
|
|
13
|
+
/** Screen reader hint describing the shortcut, e.g., "Press ⌘+K to focus search". */
|
|
14
|
+
shortcutHotkeyAriaDescription: AutocompleteProps['translations']['shortcutHotkeyAriaDescription'];
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A SearchInput component.
|
|
18
|
+
*
|
|
19
|
+
* @param props - The component props
|
|
20
|
+
* @returns The rendered SearchInput component
|
|
21
|
+
*/
|
|
22
|
+
declare const SearchInput: ({ ariaLabel, clearTextAriaLabel, onChange, shortcutHotkeyAriaDescription, ...props }: SearchInputProps) => JSX.Element;
|
|
23
|
+
|
|
24
|
+
export { SearchInput, SearchInput as default };
|
|
25
|
+
export type { SearchInputProps };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{jsx as e}from"react/jsx-runtime";import{Autocomplete as a}from"../Autocomplete/index.js";const t=({ariaLabel:t,clearTextAriaLabel:o,onChange:i,shortcutHotkeyAriaDescription:r,...n})=>e(a,{...n,ariaLabel:t,multiple:!1,onChange:()=>{},onInputChange:i,options:[],translations:{clearTextAriaLabel:o,shortcutHotkeyAriaDescription:r,dismissTagAriaLabel:"",loadingText:"",noOptionsText:"",openPopupAriaLabel:""},type:"search"});export{t as SearchInput,t as default};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/molecules/SearchInput/index.tsx"],"sourcesContent":["import Autocomplete, { type AutocompleteProps } from '../Autocomplete';\n\n/**\n * The props for the SearchInput component.\n */\nexport type SearchInputProps = Omit<\n AutocompleteProps,\n | 'errorText'\n | 'helperText'\n | 'label'\n | 'multiple'\n | 'onChange'\n | 'onInputChange'\n | 'options'\n | 'required'\n | 'translations'\n | 'type'\n> & {\n /** Aria-label for the search input. */\n ariaLabel: string;\n /** Aria-label for the clear button. */\n clearTextAriaLabel: AutocompleteProps['translations']['clearTextAriaLabel'];\n /** Called when the input text changes. */\n onChange: AutocompleteProps['onInputChange'];\n /** Screen reader hint describing the shortcut, e.g., \"Press ⌘+K to focus search\". */\n shortcutHotkeyAriaDescription: AutocompleteProps['translations']['shortcutHotkeyAriaDescription'];\n};\n\n/**\n * A SearchInput component.\n *\n * @param props - The component props\n * @returns The rendered SearchInput component\n */\nexport const SearchInput = ({\n ariaLabel,\n clearTextAriaLabel,\n onChange,\n shortcutHotkeyAriaDescription,\n ...props\n}: SearchInputProps): JSX.Element => {\n return (\n <Autocomplete\n {...props}\n ariaLabel={ariaLabel}\n multiple={false}\n onChange={() => {}}\n onInputChange={onChange}\n options={[]}\n translations={{\n clearTextAriaLabel,\n shortcutHotkeyAriaDescription,\n dismissTagAriaLabel: '',\n loadingText: '',\n noOptionsText: '',\n openPopupAriaLabel: '',\n }}\n type=\"search\"\n />\n );\n};\n\nexport default SearchInput;\n"],"names":["SearchInput","ariaLabel","clearTextAriaLabel","onChange","shortcutHotkeyAriaDescription","props","_jsx","Autocomplete","multiple","onInputChange","options","translations","dismissTagAriaLabel","loadingText","noOptionsText","openPopupAriaLabel","type"],"mappings":"gGAkCO,MAAMA,EAAc,EACzBC,YACAC,qBACAC,WACAC,mCACGC,KAGDC,EAACC,EAAY,IACPF,EACJJ,UAAWA,EACXO,UAAU,EACVL,SAAU,OACVM,cAAeN,EACfO,QAAS,GACTC,aAAc,CACZT,qBACAE,gCACAQ,oBAAqB,GACrBC,YAAa,GACbC,cAAe,GACfC,mBAAoB,IAEtBC,KAAK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageDisplay.cjs.js","sources":["../../../../../src/components/organisms/ImageUploadWidget/components/ImageDisplay.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\n\nimport Skeleton from '@mui/material/Skeleton/Skeleton';\nimport styled from '@mui/material/styles/styled';\n\nimport { AdvancedImage } from '@cloudinary/react';\nimport { Cloudinary, type CloudinaryImage } from '@cloudinary/url-gen';\nimport Imgix from 'react-imgix';\n\ninterface ImageDisplayProps {\n src: string;\n isCloudinaryAsset?: boolean;\n cdnCloudName?: string;\n}\n\nconst StyledSkeleton = styled(Skeleton)({\n width: '100%',\n height: '100%',\n});\n\nconst ImageDisplay: React.FC<ImageDisplayProps> = ({ src, isCloudinaryAsset, cdnCloudName }) => {\n const [loading, setLoading] = useState(true);\n\n const handleLoadingChange = (loadingState: boolean): void => {\n setLoading(loadingState);\n };\n\n const cloudinaryImage = useMemo<CloudinaryImage | null>(() => {\n if (isCloudinaryAsset) {\n const cloudinaryInstance = new Cloudinary({\n cloud: {\n cloudName: cdnCloudName,\n },\n });\n return cloudinaryInstance.image(src);\n }\n return null;\n }, [src, isCloudinaryAsset, cdnCloudName]);\n\n if (isCloudinaryAsset && cloudinaryImage) {\n return (\n <>\n <AdvancedImage\n cldImg={cloudinaryImage}\n onError={() => handleLoadingChange(false)}\n onLoad={() => handleLoadingChange(false)}\n style={{ maxWidth: loading ? '0%' : '100%', maxHeight: '100%', objectFit: 'cover' }}\n />\n {loading && <StyledSkeleton animation=\"wave\" variant=\"rounded\" />}\n </>\n );\n }\n\n return (\n <>\n <Imgix\n htmlAttributes={{\n onLoad: () => handleLoadingChange(false),\n onError: () => handleLoadingChange(false),\n style: {\n maxWidth: loading ? '0%' : '100%',\n maxHeight: '100%',\n objectFit: 'cover',\n },\n }}\n src={src}\n />\n {loading && <StyledSkeleton animation=\"wave\" variant=\"rounded\" />}\n </>\n );\n};\n\nexport default ImageDisplay
|
|
1
|
+
{"version":3,"file":"ImageDisplay.cjs.js","sources":["../../../../../src/components/organisms/ImageUploadWidget/components/ImageDisplay.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\n\nimport Skeleton from '@mui/material/Skeleton/Skeleton';\nimport styled from '@mui/material/styles/styled';\n\nimport { AdvancedImage } from '@cloudinary/react';\nimport { Cloudinary, type CloudinaryImage } from '@cloudinary/url-gen';\nimport Imgix from 'react-imgix';\n\ninterface ImageDisplayProps {\n src: string;\n isCloudinaryAsset?: boolean;\n cdnCloudName?: string;\n}\n\nconst StyledSkeleton = styled(Skeleton)({\n width: '100%',\n height: '100%',\n});\n\nconst ImageDisplay: React.FC<ImageDisplayProps> = ({ src, isCloudinaryAsset, cdnCloudName }) => {\n const [loading, setLoading] = useState(true);\n\n const handleLoadingChange = (loadingState: boolean): void => {\n setLoading(loadingState);\n };\n\n const cloudinaryImage = useMemo<CloudinaryImage | null>(() => {\n if (isCloudinaryAsset) {\n const cloudinaryInstance = new Cloudinary({\n cloud: {\n cloudName: cdnCloudName,\n },\n });\n return cloudinaryInstance.image(src);\n }\n return null;\n }, [src, isCloudinaryAsset, cdnCloudName]);\n\n if (isCloudinaryAsset && cloudinaryImage) {\n return (\n <>\n <AdvancedImage\n cldImg={cloudinaryImage}\n onError={() => handleLoadingChange(false)}\n onLoad={() => handleLoadingChange(false)}\n style={{ maxWidth: loading ? '0%' : '100%', maxHeight: '100%', objectFit: 'cover' }}\n />\n {loading && <StyledSkeleton animation=\"wave\" variant=\"rounded\" />}\n </>\n );\n }\n\n return (\n <>\n <Imgix\n htmlAttributes={{\n onLoad: () => handleLoadingChange(false),\n onError: () => handleLoadingChange(false),\n style: {\n maxWidth: loading ? '0%' : '100%',\n maxHeight: '100%',\n objectFit: 'cover',\n },\n }}\n src={src}\n />\n {loading && <StyledSkeleton animation=\"wave\" variant=\"rounded\" />}\n </>\n );\n};\n\nexport default ImageDisplay;"],"names":["StyledSkeleton","styled","Skeleton","width","height","src","isCloudinaryAsset","cdnCloudName","loading","setLoading","useState","handleLoadingChange","loadingState","cloudinaryImage","useMemo","Cloudinary","cloud","cloudName","image","_jsxs","_Fragment","children","_jsx","AdvancedImage","cldImg","onError","onLoad","style","maxWidth","maxHeight","objectFit","animation","variant","Imgix","htmlAttributes"],"mappings":"kPAeA,MAAMA,EAAiBC,EAAOC,EAAPD,CAAiB,CACtCE,MAAO,OACPC,OAAQ,wBAGwC,EAAGC,MAAKC,oBAAmBC,mBAC3E,MAAOC,EAASC,GAAcC,EAAAA,UAAS,GAEjCC,EAAuBC,IAC3BH,EAAWG,IAGPC,EAAkBC,EAAAA,SAAgC,KACtD,GAAIR,EAAmB,CAMrB,OAL2B,IAAIS,aAAW,CACxCC,MAAO,CACLC,UAAWV,KAGWW,MAAMb,EAClC,CACA,OAAO,OACN,CAACA,EAAKC,EAAmBC,IAE5B,OAAID,GAAqBO,EAErBM,EAAAA,KAAAC,EAAAA,SAAA,CAAAC,SAAA,CACEC,MAACC,EAAAA,eACCC,OAAQX,EACRY,QAAS,IAAMd,GAAoB,GACnCe,OAAQ,IAAMf,GAAoB,GAClCgB,MAAO,CAAEC,SAAUpB,EAAU,KAAO,OAAQqB,UAAW,OAAQC,UAAW,WAE3EtB,GAAWc,MAACtB,GAAe+B,UAAU,OAAOC,QAAQ,eAMzDb,EAAAA,KAAAC,EAAAA,SAAA,CAAAC,SAAA,CACEC,MAACW,EAAK,CACJC,eAAgB,CACdR,OAAQ,IAAMf,GAAoB,GAClCc,QAAS,IAAMd,GAAoB,GACnCgB,MAAO,CACLC,SAAUpB,EAAU,KAAO,OAC3BqB,UAAW,OACXC,UAAW,UAGfzB,IAAKA,IAENG,GAAWc,EAAAA,IAACtB,EAAc,CAAC+B,UAAU,OAAOC,QAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageDisplay.js","sources":["../../../../../src/components/organisms/ImageUploadWidget/components/ImageDisplay.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\n\nimport Skeleton from '@mui/material/Skeleton/Skeleton';\nimport styled from '@mui/material/styles/styled';\n\nimport { AdvancedImage } from '@cloudinary/react';\nimport { Cloudinary, type CloudinaryImage } from '@cloudinary/url-gen';\nimport Imgix from 'react-imgix';\n\ninterface ImageDisplayProps {\n src: string;\n isCloudinaryAsset?: boolean;\n cdnCloudName?: string;\n}\n\nconst StyledSkeleton = styled(Skeleton)({\n width: '100%',\n height: '100%',\n});\n\nconst ImageDisplay: React.FC<ImageDisplayProps> = ({ src, isCloudinaryAsset, cdnCloudName }) => {\n const [loading, setLoading] = useState(true);\n\n const handleLoadingChange = (loadingState: boolean): void => {\n setLoading(loadingState);\n };\n\n const cloudinaryImage = useMemo<CloudinaryImage | null>(() => {\n if (isCloudinaryAsset) {\n const cloudinaryInstance = new Cloudinary({\n cloud: {\n cloudName: cdnCloudName,\n },\n });\n return cloudinaryInstance.image(src);\n }\n return null;\n }, [src, isCloudinaryAsset, cdnCloudName]);\n\n if (isCloudinaryAsset && cloudinaryImage) {\n return (\n <>\n <AdvancedImage\n cldImg={cloudinaryImage}\n onError={() => handleLoadingChange(false)}\n onLoad={() => handleLoadingChange(false)}\n style={{ maxWidth: loading ? '0%' : '100%', maxHeight: '100%', objectFit: 'cover' }}\n />\n {loading && <StyledSkeleton animation=\"wave\" variant=\"rounded\" />}\n </>\n );\n }\n\n return (\n <>\n <Imgix\n htmlAttributes={{\n onLoad: () => handleLoadingChange(false),\n onError: () => handleLoadingChange(false),\n style: {\n maxWidth: loading ? '0%' : '100%',\n maxHeight: '100%',\n objectFit: 'cover',\n },\n }}\n src={src}\n />\n {loading && <StyledSkeleton animation=\"wave\" variant=\"rounded\" />}\n </>\n );\n};\n\nexport default ImageDisplay
|
|
1
|
+
{"version":3,"file":"ImageDisplay.js","sources":["../../../../../src/components/organisms/ImageUploadWidget/components/ImageDisplay.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\n\nimport Skeleton from '@mui/material/Skeleton/Skeleton';\nimport styled from '@mui/material/styles/styled';\n\nimport { AdvancedImage } from '@cloudinary/react';\nimport { Cloudinary, type CloudinaryImage } from '@cloudinary/url-gen';\nimport Imgix from 'react-imgix';\n\ninterface ImageDisplayProps {\n src: string;\n isCloudinaryAsset?: boolean;\n cdnCloudName?: string;\n}\n\nconst StyledSkeleton = styled(Skeleton)({\n width: '100%',\n height: '100%',\n});\n\nconst ImageDisplay: React.FC<ImageDisplayProps> = ({ src, isCloudinaryAsset, cdnCloudName }) => {\n const [loading, setLoading] = useState(true);\n\n const handleLoadingChange = (loadingState: boolean): void => {\n setLoading(loadingState);\n };\n\n const cloudinaryImage = useMemo<CloudinaryImage | null>(() => {\n if (isCloudinaryAsset) {\n const cloudinaryInstance = new Cloudinary({\n cloud: {\n cloudName: cdnCloudName,\n },\n });\n return cloudinaryInstance.image(src);\n }\n return null;\n }, [src, isCloudinaryAsset, cdnCloudName]);\n\n if (isCloudinaryAsset && cloudinaryImage) {\n return (\n <>\n <AdvancedImage\n cldImg={cloudinaryImage}\n onError={() => handleLoadingChange(false)}\n onLoad={() => handleLoadingChange(false)}\n style={{ maxWidth: loading ? '0%' : '100%', maxHeight: '100%', objectFit: 'cover' }}\n />\n {loading && <StyledSkeleton animation=\"wave\" variant=\"rounded\" />}\n </>\n );\n }\n\n return (\n <>\n <Imgix\n htmlAttributes={{\n onLoad: () => handleLoadingChange(false),\n onError: () => handleLoadingChange(false),\n style: {\n maxWidth: loading ? '0%' : '100%',\n maxHeight: '100%',\n objectFit: 'cover',\n },\n }}\n src={src}\n />\n {loading && <StyledSkeleton animation=\"wave\" variant=\"rounded\" />}\n </>\n );\n};\n\nexport default ImageDisplay;"],"names":["StyledSkeleton","styled","Skeleton","width","height","ImageDisplay","src","isCloudinaryAsset","cdnCloudName","loading","setLoading","useState","handleLoadingChange","loadingState","cloudinaryImage","useMemo","Cloudinary","cloud","cloudName","image","_jsxs","_Fragment","children","_jsx","AdvancedImage","cldImg","onError","onLoad","style","maxWidth","maxHeight","objectFit","animation","variant","Imgix","htmlAttributes"],"mappings":"sUAeA,MAAMA,EAAiBC,EAAOC,EAAPD,CAAiB,CACtCE,MAAO,OACPC,OAAQ,SAGJC,EAA4C,EAAGC,MAAKC,oBAAmBC,mBAC3E,MAAOC,EAASC,GAAcC,GAAS,GAEjCC,EAAuBC,IAC3BH,EAAWG,IAGPC,EAAkBC,GAAgC,KACtD,GAAIR,EAAmB,CAMrB,OAL2B,IAAIS,EAAW,CACxCC,MAAO,CACLC,UAAWV,KAGWW,MAAMb,EAClC,CACA,OAAO,OACN,CAACA,EAAKC,EAAmBC,IAE5B,OAEIY,EAAAC,EAFAd,GAAqBO,EAErB,CAAAQ,SAAA,CACEC,EAACC,GACCC,OAAQX,EACRY,QAAS,IAAMd,GAAoB,GACnCe,OAAQ,IAAMf,GAAoB,GAClCgB,MAAO,CAAEC,SAAUpB,EAAU,KAAO,OAAQqB,UAAW,OAAQC,UAAW,WAE3EtB,GAAWc,EAACvB,GAAegC,UAAU,OAAOC,QAAQ,cAMzD,CAAAX,SAAA,CACEC,EAACW,EAAK,CACJC,eAAgB,CACdR,OAAQ,IAAMf,GAAoB,GAClCc,QAAS,IAAMd,GAAoB,GACnCgB,MAAO,CACLC,SAAUpB,EAAU,KAAO,OAC3BqB,UAAW,OACXC,UAAW,UAGfzB,IAAKA,IAENG,GAAWc,EAACvB,EAAc,CAACgC,UAAU,OAAOC,QAAQ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("@mui/material/styles");var e=require("../typography.cjs.js");const t=t=>({defaultProps:{slotProps:{clearIndicator:{disableRipple:!0,disableFocusRipple:!0,disableTouchRipple:!0},popupIndicator:{disableRipple:!0,disableFocusRipple:!0,disableTouchRipple:!0},paper:{elevation:0,sx:e=>({backgroundColor:e.palette.semantic.background["background-overlay"],border:"1px solid",borderColor:e.palette.semantic.stroke["stroke-weak"],borderRadius:e.radius["radius-8"],boxShadow:e.customShadows.overlay,m:e.spacing(.5,0)})},listbox:{sx:e=>({p:e.spacing(1,0)})}}},styleOverrides:{root:{"& .MuiOutlinedInput-root .MuiInputBase-input.MuiAutocomplete-input":{padding:0}},inputRoot:{alignItems:"center",display:"flex",
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("@mui/material/styles");var e=require("../typography.cjs.js");const t=t=>({defaultProps:{slotProps:{clearIndicator:{disableRipple:!0,disableFocusRipple:!0,disableTouchRipple:!0},popupIndicator:{disableRipple:!0,disableFocusRipple:!0,disableTouchRipple:!0},paper:{elevation:0,sx:e=>({backgroundColor:e.palette.semantic.background["background-overlay"],border:"1px solid",borderColor:e.palette.semantic.stroke["stroke-weak"],borderRadius:e.radius["radius-8"],boxShadow:e.customShadows.overlay,m:e.spacing(.5,0)})},listbox:{sx:e=>({p:e.spacing(1,0)})}}},styleOverrides:{root:{"& .MuiOutlinedInput-root .MuiInputBase-input.MuiAutocomplete-input":{padding:0}},inputRoot:{alignItems:"center",display:"flex",padding:t.spacing(.5,2)},input:{alignSelf:"center",lineHeight:t.typography.body2.lineHeight,padding:0},endAdornment:{alignItems:"center",display:"flex",gap:t.spacing(1),justifyContent:"center"},clearIndicator:{height:24,margin:0,opacity:1,padding:0,visibility:"visible",width:24},popupIndicator:{height:24,margin:0,padding:0,width:24},popupIndicatorOpen:{transform:"none"},tag:{margin:t.spacing(.25),maxWidth:"100%"},noOptions:{...e.typography.b1Weak,color:t.palette.semantic.text["text-weak"],[t.breakpoints.down("tablet")]:{...e.getMobileTextStyle("b1")}},loading:{...e.typography.b1Weak,color:t.palette.semantic.text["text-weak"],[t.breakpoints.down("tablet")]:{...e.getMobileTextStyle("b1")}}}});exports.autocompleteOverrides=t,exports.default=t;
|
|
2
2
|
//# sourceMappingURL=autocompleteOverrides.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autocompleteOverrides.cjs.js","sources":["../../../src/themes/overrides/autocompleteOverrides.ts"],"sourcesContent":["import { type Components, type Theme } from '@mui/material/styles';\n\nimport { getMobileTextStyle, typography } from '@fd/themes/typography';\n\nexport const autocompleteOverrides = (theme: Theme): Components<Theme>['MuiAutocomplete'] => ({\n defaultProps: {\n slotProps: {\n clearIndicator: {\n disableRipple: true,\n disableFocusRipple: true,\n disableTouchRipple: true,\n },\n popupIndicator: {\n disableRipple: true,\n disableFocusRipple: true,\n disableTouchRipple: true,\n },\n paper: {\n elevation: 0,\n sx: (theme) => ({\n backgroundColor: theme.palette.semantic.background['background-overlay'],\n border: '1px solid',\n borderColor: theme.palette.semantic.stroke['stroke-weak'],\n borderRadius: theme.radius['radius-8'],\n boxShadow: theme.customShadows.overlay,\n m: theme.spacing(0.5, 0),\n }),\n },\n listbox: {\n sx: (theme) => ({
|
|
1
|
+
{"version":3,"file":"autocompleteOverrides.cjs.js","sources":["../../../src/themes/overrides/autocompleteOverrides.ts"],"sourcesContent":["import { type Components, type Theme } from '@mui/material/styles';\n\nimport { getMobileTextStyle, typography } from '@fd/themes/typography';\n\nexport const autocompleteOverrides = (theme: Theme): Components<Theme>['MuiAutocomplete'] => ({\n defaultProps: {\n slotProps: {\n clearIndicator: {\n disableRipple: true,\n disableFocusRipple: true,\n disableTouchRipple: true,\n },\n popupIndicator: {\n disableRipple: true,\n disableFocusRipple: true,\n disableTouchRipple: true,\n },\n paper: {\n elevation: 0,\n sx: (theme) => ({\n backgroundColor: theme.palette.semantic.background['background-overlay'],\n border: '1px solid',\n borderColor: theme.palette.semantic.stroke['stroke-weak'],\n borderRadius: theme.radius['radius-8'],\n boxShadow: theme.customShadows.overlay,\n m: theme.spacing(0.5, 0),\n }),\n },\n listbox: {\n sx: (theme) => ({\n p: theme.spacing(1, 0),\n }),\n },\n },\n },\n styleOverrides: {\n root: {\n '& .MuiOutlinedInput-root .MuiInputBase-input.MuiAutocomplete-input': {\n padding: 0,\n },\n },\n inputRoot: {\n alignItems: 'center',\n display: 'flex',\n padding: theme.spacing(0.5, 2),\n },\n input: {\n alignSelf: 'center',\n lineHeight: theme.typography.body2.lineHeight, // align text with tags\n padding: 0,\n },\n endAdornment: {\n alignItems: 'center',\n display: 'flex',\n gap: theme.spacing(1),\n justifyContent: 'center',\n },\n clearIndicator: {\n height: 24,\n margin: 0,\n opacity: 1,\n padding: 0,\n visibility: 'visible',\n width: 24,\n },\n popupIndicator: {\n height: 24,\n margin: 0,\n padding: 0,\n width: 24,\n },\n popupIndicatorOpen: {\n transform: 'none',\n },\n tag: {\n margin: theme.spacing(0.25),\n maxWidth: '100%',\n },\n noOptions: {\n ...typography.b1Weak,\n color: theme.palette.semantic.text['text-weak'],\n\n [theme.breakpoints.down('tablet')]: {\n ...getMobileTextStyle('b1'),\n },\n },\n loading: {\n ...typography.b1Weak,\n color: theme.palette.semantic.text['text-weak'],\n\n [theme.breakpoints.down('tablet')]: {\n ...getMobileTextStyle('b1'),\n },\n },\n },\n});\n\nexport default autocompleteOverrides;\n"],"names":["autocompleteOverrides","theme","defaultProps","slotProps","clearIndicator","disableRipple","disableFocusRipple","disableTouchRipple","popupIndicator","paper","elevation","sx","backgroundColor","palette","semantic","background","border","borderColor","stroke","borderRadius","radius","boxShadow","customShadows","overlay","m","spacing","listbox","p","styleOverrides","root","padding","inputRoot","alignItems","display","input","alignSelf","lineHeight","typography","body2","endAdornment","gap","justifyContent","height","margin","opacity","visibility","width","popupIndicatorOpen","transform","tag","maxWidth","noOptions","b1Weak","color","text","breakpoints","down","getMobileTextStyle","loading"],"mappings":"gJAIaA,EAAyBC,IAAY,CAChDC,aAAc,CACZC,UAAW,CACTC,eAAgB,CACdC,eAAe,EACfC,oBAAoB,EACpBC,oBAAoB,GAEtBC,eAAgB,CACdH,eAAe,EACfC,oBAAoB,EACpBC,oBAAoB,GAEtBE,MAAO,CACLC,UAAW,EACXC,GAAKV,IAAK,CACRW,gBAAiBX,EAAMY,QAAQC,SAASC,WAAW,sBACnDC,OAAQ,YACRC,YAAahB,EAAMY,QAAQC,SAASI,OAAO,eAC3CC,aAAclB,EAAMmB,OAAO,YAC3BC,UAAWpB,EAAMqB,cAAcC,QAC/BC,EAAGvB,EAAMwB,QAAQ,GAAK,MAG1BC,QAAS,CACPf,GAAKV,IAAK,CACR0B,EAAG1B,EAAMwB,QAAQ,EAAG,QAK5BG,eAAgB,CACdC,KAAM,CACJ,qEAAsE,CACpEC,QAAS,IAGbC,UAAW,CACTC,WAAY,SACZC,QAAS,OACTH,QAAS7B,EAAMwB,QAAQ,GAAK,IAE9BS,MAAO,CACLC,UAAW,SACXC,WAAYnC,EAAMoC,WAAWC,MAAMF,WACnCN,QAAS,GAEXS,aAAc,CACZP,WAAY,SACZC,QAAS,OACTO,IAAKvC,EAAMwB,QAAQ,GACnBgB,eAAgB,UAElBrC,eAAgB,CACdsC,OAAQ,GACRC,OAAQ,EACRC,QAAS,EACTd,QAAS,EACTe,WAAY,UACZC,MAAO,IAETtC,eAAgB,CACdkC,OAAQ,GACRC,OAAQ,EACRb,QAAS,EACTgB,MAAO,IAETC,mBAAoB,CAClBC,UAAW,QAEbC,IAAK,CACHN,OAAQ1C,EAAMwB,QAAQ,KACtByB,SAAU,QAEZC,UAAW,IACNd,EAAAA,WAAWe,OACdC,MAAOpD,EAAMY,QAAQC,SAASwC,KAAK,aAEnC,CAACrD,EAAMsD,YAAYC,KAAK,WAAY,IAC/BC,EAAAA,mBAAmB,QAG1BC,QAAS,IACJrB,EAAAA,WAAWe,OACdC,MAAOpD,EAAMY,QAAQC,SAASwC,KAAK,aAEnC,CAACrD,EAAMsD,YAAYC,KAAK,WAAY,IAC/BC,EAAAA,mBAAmB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"@mui/material/styles";import{getMobileTextStyle as e,typography as t}from"../typography.js";const
|
|
1
|
+
import"@mui/material/styles";import{getMobileTextStyle as e,typography as t}from"../typography.js";const i=i=>({defaultProps:{slotProps:{clearIndicator:{disableRipple:!0,disableFocusRipple:!0,disableTouchRipple:!0},popupIndicator:{disableRipple:!0,disableFocusRipple:!0,disableTouchRipple:!0},paper:{elevation:0,sx:e=>({backgroundColor:e.palette.semantic.background["background-overlay"],border:"1px solid",borderColor:e.palette.semantic.stroke["stroke-weak"],borderRadius:e.radius["radius-8"],boxShadow:e.customShadows.overlay,m:e.spacing(.5,0)})},listbox:{sx:e=>({p:e.spacing(1,0)})}}},styleOverrides:{root:{"& .MuiOutlinedInput-root .MuiInputBase-input.MuiAutocomplete-input":{padding:0}},inputRoot:{alignItems:"center",display:"flex",padding:i.spacing(.5,2)},input:{alignSelf:"center",lineHeight:i.typography.body2.lineHeight,padding:0},endAdornment:{alignItems:"center",display:"flex",gap:i.spacing(1),justifyContent:"center"},clearIndicator:{height:24,margin:0,opacity:1,padding:0,visibility:"visible",width:24},popupIndicator:{height:24,margin:0,padding:0,width:24},popupIndicatorOpen:{transform:"none"},tag:{margin:i.spacing(.25),maxWidth:"100%"},noOptions:{...t.b1Weak,color:i.palette.semantic.text["text-weak"],[i.breakpoints.down("tablet")]:{...e("b1")}},loading:{...t.b1Weak,color:i.palette.semantic.text["text-weak"],[i.breakpoints.down("tablet")]:{...e("b1")}}}});export{i as autocompleteOverrides,i as default};
|
|
2
2
|
//# sourceMappingURL=autocompleteOverrides.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autocompleteOverrides.js","sources":["../../../src/themes/overrides/autocompleteOverrides.ts"],"sourcesContent":["import { type Components, type Theme } from '@mui/material/styles';\n\nimport { getMobileTextStyle, typography } from '@fd/themes/typography';\n\nexport const autocompleteOverrides = (theme: Theme): Components<Theme>['MuiAutocomplete'] => ({\n defaultProps: {\n slotProps: {\n clearIndicator: {\n disableRipple: true,\n disableFocusRipple: true,\n disableTouchRipple: true,\n },\n popupIndicator: {\n disableRipple: true,\n disableFocusRipple: true,\n disableTouchRipple: true,\n },\n paper: {\n elevation: 0,\n sx: (theme) => ({\n backgroundColor: theme.palette.semantic.background['background-overlay'],\n border: '1px solid',\n borderColor: theme.palette.semantic.stroke['stroke-weak'],\n borderRadius: theme.radius['radius-8'],\n boxShadow: theme.customShadows.overlay,\n m: theme.spacing(0.5, 0),\n }),\n },\n listbox: {\n sx: (theme) => ({
|
|
1
|
+
{"version":3,"file":"autocompleteOverrides.js","sources":["../../../src/themes/overrides/autocompleteOverrides.ts"],"sourcesContent":["import { type Components, type Theme } from '@mui/material/styles';\n\nimport { getMobileTextStyle, typography } from '@fd/themes/typography';\n\nexport const autocompleteOverrides = (theme: Theme): Components<Theme>['MuiAutocomplete'] => ({\n defaultProps: {\n slotProps: {\n clearIndicator: {\n disableRipple: true,\n disableFocusRipple: true,\n disableTouchRipple: true,\n },\n popupIndicator: {\n disableRipple: true,\n disableFocusRipple: true,\n disableTouchRipple: true,\n },\n paper: {\n elevation: 0,\n sx: (theme) => ({\n backgroundColor: theme.palette.semantic.background['background-overlay'],\n border: '1px solid',\n borderColor: theme.palette.semantic.stroke['stroke-weak'],\n borderRadius: theme.radius['radius-8'],\n boxShadow: theme.customShadows.overlay,\n m: theme.spacing(0.5, 0),\n }),\n },\n listbox: {\n sx: (theme) => ({\n p: theme.spacing(1, 0),\n }),\n },\n },\n },\n styleOverrides: {\n root: {\n '& .MuiOutlinedInput-root .MuiInputBase-input.MuiAutocomplete-input': {\n padding: 0,\n },\n },\n inputRoot: {\n alignItems: 'center',\n display: 'flex',\n padding: theme.spacing(0.5, 2),\n },\n input: {\n alignSelf: 'center',\n lineHeight: theme.typography.body2.lineHeight, // align text with tags\n padding: 0,\n },\n endAdornment: {\n alignItems: 'center',\n display: 'flex',\n gap: theme.spacing(1),\n justifyContent: 'center',\n },\n clearIndicator: {\n height: 24,\n margin: 0,\n opacity: 1,\n padding: 0,\n visibility: 'visible',\n width: 24,\n },\n popupIndicator: {\n height: 24,\n margin: 0,\n padding: 0,\n width: 24,\n },\n popupIndicatorOpen: {\n transform: 'none',\n },\n tag: {\n margin: theme.spacing(0.25),\n maxWidth: '100%',\n },\n noOptions: {\n ...typography.b1Weak,\n color: theme.palette.semantic.text['text-weak'],\n\n [theme.breakpoints.down('tablet')]: {\n ...getMobileTextStyle('b1'),\n },\n },\n loading: {\n ...typography.b1Weak,\n color: theme.palette.semantic.text['text-weak'],\n\n [theme.breakpoints.down('tablet')]: {\n ...getMobileTextStyle('b1'),\n },\n },\n },\n});\n\nexport default autocompleteOverrides;\n"],"names":["autocompleteOverrides","theme","defaultProps","slotProps","clearIndicator","disableRipple","disableFocusRipple","disableTouchRipple","popupIndicator","paper","elevation","sx","backgroundColor","palette","semantic","background","border","borderColor","stroke","borderRadius","radius","boxShadow","customShadows","overlay","m","spacing","listbox","p","styleOverrides","root","padding","inputRoot","alignItems","display","input","alignSelf","lineHeight","typography","body2","endAdornment","gap","justifyContent","height","margin","opacity","visibility","width","popupIndicatorOpen","transform","tag","maxWidth","noOptions","b1Weak","color","text","breakpoints","down","getMobileTextStyle","loading"],"mappings":"yGAIaA,EAAyBC,IAAY,CAChDC,aAAc,CACZC,UAAW,CACTC,eAAgB,CACdC,eAAe,EACfC,oBAAoB,EACpBC,oBAAoB,GAEtBC,eAAgB,CACdH,eAAe,EACfC,oBAAoB,EACpBC,oBAAoB,GAEtBE,MAAO,CACLC,UAAW,EACXC,GAAKV,IAAK,CACRW,gBAAiBX,EAAMY,QAAQC,SAASC,WAAW,sBACnDC,OAAQ,YACRC,YAAahB,EAAMY,QAAQC,SAASI,OAAO,eAC3CC,aAAclB,EAAMmB,OAAO,YAC3BC,UAAWpB,EAAMqB,cAAcC,QAC/BC,EAAGvB,EAAMwB,QAAQ,GAAK,MAG1BC,QAAS,CACPf,GAAKV,IAAK,CACR0B,EAAG1B,EAAMwB,QAAQ,EAAG,QAK5BG,eAAgB,CACdC,KAAM,CACJ,qEAAsE,CACpEC,QAAS,IAGbC,UAAW,CACTC,WAAY,SACZC,QAAS,OACTH,QAAS7B,EAAMwB,QAAQ,GAAK,IAE9BS,MAAO,CACLC,UAAW,SACXC,WAAYnC,EAAMoC,WAAWC,MAAMF,WACnCN,QAAS,GAEXS,aAAc,CACZP,WAAY,SACZC,QAAS,OACTO,IAAKvC,EAAMwB,QAAQ,GACnBgB,eAAgB,UAElBrC,eAAgB,CACdsC,OAAQ,GACRC,OAAQ,EACRC,QAAS,EACTd,QAAS,EACTe,WAAY,UACZC,MAAO,IAETtC,eAAgB,CACdkC,OAAQ,GACRC,OAAQ,EACRb,QAAS,EACTgB,MAAO,IAETC,mBAAoB,CAClBC,UAAW,QAEbC,IAAK,CACHN,OAAQ1C,EAAMwB,QAAQ,KACtByB,SAAU,QAEZC,UAAW,IACNd,EAAWe,OACdC,MAAOpD,EAAMY,QAAQC,SAASwC,KAAK,aAEnC,CAACrD,EAAMsD,YAAYC,KAAK,WAAY,IAC/BC,EAAmB,QAG1BC,QAAS,IACJrB,EAAWe,OACdC,MAAOpD,EAAMY,QAAQC,SAASwC,KAAK,aAEnC,CAACrD,EAAMsD,YAAYC,KAAK,WAAY,IAC/BC,EAAmB"}
|