@transferwise/components 46.160.2 → 46.160.4
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/build/FlowNavigation/FlowNavigation.js +6 -4
- package/build/FlowNavigation/FlowNavigation.js.map +1 -1
- package/build/FlowNavigation/FlowNavigation.mjs +6 -4
- package/build/FlowNavigation/FlowNavigation.mjs.map +1 -1
- package/build/Inputs/SelectInput/Options/SelectInputOptions.js +33 -5
- package/build/Inputs/SelectInput/Options/SelectInputOptions.js.map +1 -1
- package/build/Inputs/SelectInput/Options/SelectInputOptions.mjs +34 -6
- package/build/Inputs/SelectInput/Options/SelectInputOptions.mjs.map +1 -1
- package/build/Inputs/SelectInput/SelectInput.js +28 -4
- package/build/Inputs/SelectInput/SelectInput.js.map +1 -1
- package/build/Inputs/SelectInput/SelectInput.mjs +29 -5
- package/build/Inputs/SelectInput/SelectInput.mjs.map +1 -1
- package/build/Inputs/SelectInput/SelectInput.utils.js +0 -2
- package/build/Inputs/SelectInput/SelectInput.utils.js.map +1 -1
- package/build/Inputs/SelectInput/SelectInput.utils.mjs +1 -2
- package/build/Inputs/SelectInput/SelectInput.utils.mjs.map +1 -1
- package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.js +5 -1
- package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.js.map +1 -1
- package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.mjs +5 -1
- package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.mjs.map +1 -1
- package/build/Inputs/SelectInput/constants.js +8 -0
- package/build/Inputs/SelectInput/constants.js.map +1 -0
- package/build/Inputs/SelectInput/constants.mjs +5 -0
- package/build/Inputs/SelectInput/constants.mjs.map +1 -0
- package/build/Inputs/SelectInput/hooks/useTypeahead.js +57 -0
- package/build/Inputs/SelectInput/hooks/useTypeahead.js.map +1 -0
- package/build/Inputs/SelectInput/hooks/useTypeahead.mjs +54 -0
- package/build/Inputs/SelectInput/hooks/useTypeahead.mjs.map +1 -0
- package/build/i18n/ja.json +1 -1
- package/build/i18n/ja.json.js +1 -1
- package/build/i18n/ja.json.mjs +1 -1
- package/build/main.css +10 -0
- package/build/styles/FlowNavigation/FlowNavigation.css +10 -0
- package/build/styles/main.css +10 -0
- package/build/types/FlowNavigation/FlowNavigation.d.ts.map +1 -1
- package/build/types/Inputs/SelectInput/Options/SelectInputOptions.d.ts +3 -1
- package/build/types/Inputs/SelectInput/Options/SelectInputOptions.d.ts.map +1 -1
- package/build/types/Inputs/SelectInput/SelectInput.d.ts.map +1 -1
- package/build/types/Inputs/SelectInput/SelectInput.utils.d.ts +0 -1
- package/build/types/Inputs/SelectInput/SelectInput.utils.d.ts.map +1 -1
- package/build/types/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.d.ts.map +1 -1
- package/build/types/Inputs/SelectInput/constants.d.ts +3 -0
- package/build/types/Inputs/SelectInput/constants.d.ts.map +1 -0
- package/build/types/Inputs/SelectInput/hooks/useTypeahead.d.ts +8 -0
- package/build/types/Inputs/SelectInput/hooks/useTypeahead.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/FlowNavigation/FlowNavigation.css +10 -0
- package/src/FlowNavigation/FlowNavigation.less +11 -0
- package/src/FlowNavigation/FlowNavigation.tsx +6 -4
- package/src/Inputs/SelectInput/Options/SelectInputOptions.tsx +36 -6
- package/src/Inputs/SelectInput/SelectInput.test.tsx +143 -0
- package/src/Inputs/SelectInput/SelectInput.tsx +31 -5
- package/src/Inputs/SelectInput/SelectInput.utils.ts +0 -2
- package/src/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.tsx +3 -0
- package/src/Inputs/SelectInput/constants.ts +3 -0
- package/src/Inputs/SelectInput/hooks/useTypeahead.ts +82 -0
- package/src/i18n/ja.json +1 -1
- package/src/main.css +10 -0
|
@@ -51,12 +51,13 @@ const FlowNavigation = ({
|
|
|
51
51
|
const intl = reactIntl.useIntl();
|
|
52
52
|
const screenSm = useScreenSize.useScreenSize(neptuneTokens.Breakpoint.SMALL);
|
|
53
53
|
const screenLg = useScreenSize.useScreenSize(neptuneTokens.Breakpoint.LARGE);
|
|
54
|
+
const hasSteps = steps && steps.length > 0;
|
|
55
|
+
const displayGoBack = onGoBack != null && activeStep > 0;
|
|
54
56
|
const closeButton = onClose != null && /*#__PURE__*/jsxRuntime.jsx(CloseButton.CloseButton, {
|
|
55
57
|
size: "lg",
|
|
56
58
|
onClick: onClose
|
|
57
59
|
});
|
|
58
60
|
const newAvatar = done ? null : avatar;
|
|
59
|
-
const displayGoBack = onGoBack != null && activeStep > 0;
|
|
60
61
|
const flowHeaderContent = /*#__PURE__*/jsxRuntime.jsx(FlowHeader.default, {
|
|
61
62
|
className: clsx.clsx('np-flow-navigation__content', screenSm == null ? 'np-flow-navigation--hidden' : {
|
|
62
63
|
'np-flow-navigation--xs-max': !screenSm,
|
|
@@ -75,7 +76,7 @@ const FlowNavigation = ({
|
|
|
75
76
|
}) : /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
76
77
|
className: "np-flow-header__left",
|
|
77
78
|
children: logo
|
|
78
|
-
}), !screenSm && !done &&
|
|
79
|
+
}), !screenSm && !done && hasSteps && /*#__PURE__*/jsxRuntime.jsx(AnimatedLabel.default, {
|
|
79
80
|
className: "m-x-1",
|
|
80
81
|
steps: steps,
|
|
81
82
|
activeLabel: activeStep
|
|
@@ -87,7 +88,7 @@ const FlowNavigation = ({
|
|
|
87
88
|
className: "m-x-1"
|
|
88
89
|
}), closeButton]
|
|
89
90
|
}),
|
|
90
|
-
bottomContent: !done &&
|
|
91
|
+
bottomContent: !done && hasSteps ? /*#__PURE__*/jsxRuntime.jsx(Stepper.default, {
|
|
91
92
|
activeStep: activeStep,
|
|
92
93
|
steps: steps,
|
|
93
94
|
className: clsx.clsx('np-flow-navigation__stepper')
|
|
@@ -97,7 +98,8 @@ const FlowNavigation = ({
|
|
|
97
98
|
return /*#__PURE__*/jsxRuntime.jsx(Container.default, {
|
|
98
99
|
size: "fluid",
|
|
99
100
|
className: clsx.clsx('np-flow-navigation', {
|
|
100
|
-
'np-flow-navigation--border-bottom': showBottomBorder
|
|
101
|
+
'np-flow-navigation--border-bottom': showBottomBorder,
|
|
102
|
+
'np-flow-navigation--no-steps': !hasSteps || done
|
|
101
103
|
}),
|
|
102
104
|
children: flowHeaderContent
|
|
103
105
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlowNavigation.js","sources":["../../src/FlowNavigation/FlowNavigation.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useIntl } from 'react-intl';\nimport { Breakpoint } from '@transferwise/neptune-tokens';\n\nimport { Layout } from '../common';\nimport { CloseButton } from '../common/CloseButton';\nimport FlowHeader from '../common/FlowHeader/FlowHeader';\nimport Logo from '../Logo';\nimport Stepper, { type Step } from '../Stepper/Stepper';\nimport Container from '../Container';\n\nimport { useScreenSize } from '../common/hooks/useScreenSize';\nimport messages from './FlowNavigation.messages';\nimport AnimatedLabel from './AnimatedLabel';\nimport IconButton from '../IconButton';\nimport { ArrowLeft } from '@transferwise/icons';\n\nconst defaultLogo = <Logo />;\n\nexport interface FlowNavigationProps {\n /** @default 0 */\n activeStep?: number;\n avatar?: React.ReactNode;\n /** @default <Logo /> */\n logo?: React.ReactNode;\n /** @default false */\n done?: boolean;\n /** Called when the close button is clicked. If not provided the close button won't show */\n onClose?: (() => void) | React.MouseEventHandler<HTMLButtonElement>;\n /** Called when the back button is clicked. If not provided the back button won't show. The back button only shows on small screens */\n onGoBack?: () => void;\n /** Steps to be displayed in stepper. If not provided, the stepper won't show. */\n steps?: readonly Step[];\n /**\n * Controls whether the bottom border is displayed.\n * @default true\n */\n showBottomBorder?: boolean;\n}\n\nconst FlowNavigation = ({\n activeStep = 0,\n avatar,\n logo = defaultLogo,\n done = false,\n onClose,\n onGoBack,\n steps,\n showBottomBorder = true,\n}: FlowNavigationProps) => {\n const intl = useIntl();\n const screenSm = useScreenSize(Breakpoint.SMALL);\n const screenLg = useScreenSize(Breakpoint.LARGE);\n\n const closeButton = onClose != null && <CloseButton size=\"lg\" onClick={onClose} />;\n
|
|
1
|
+
{"version":3,"file":"FlowNavigation.js","sources":["../../src/FlowNavigation/FlowNavigation.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useIntl } from 'react-intl';\nimport { Breakpoint } from '@transferwise/neptune-tokens';\n\nimport { Layout } from '../common';\nimport { CloseButton } from '../common/CloseButton';\nimport FlowHeader from '../common/FlowHeader/FlowHeader';\nimport Logo from '../Logo';\nimport Stepper, { type Step } from '../Stepper/Stepper';\nimport Container from '../Container';\n\nimport { useScreenSize } from '../common/hooks/useScreenSize';\nimport messages from './FlowNavigation.messages';\nimport AnimatedLabel from './AnimatedLabel';\nimport IconButton from '../IconButton';\nimport { ArrowLeft } from '@transferwise/icons';\n\nconst defaultLogo = <Logo />;\n\nexport interface FlowNavigationProps {\n /** @default 0 */\n activeStep?: number;\n avatar?: React.ReactNode;\n /** @default <Logo /> */\n logo?: React.ReactNode;\n /** @default false */\n done?: boolean;\n /** Called when the close button is clicked. If not provided the close button won't show */\n onClose?: (() => void) | React.MouseEventHandler<HTMLButtonElement>;\n /** Called when the back button is clicked. If not provided the back button won't show. The back button only shows on small screens */\n onGoBack?: () => void;\n /** Steps to be displayed in stepper. If not provided, the stepper won't show. */\n steps?: readonly Step[];\n /**\n * Controls whether the bottom border is displayed.\n * @default true\n */\n showBottomBorder?: boolean;\n}\n\nconst FlowNavigation = ({\n activeStep = 0,\n avatar,\n logo = defaultLogo,\n done = false,\n onClose,\n onGoBack,\n steps,\n showBottomBorder = true,\n}: FlowNavigationProps) => {\n const intl = useIntl();\n const screenSm = useScreenSize(Breakpoint.SMALL);\n const screenLg = useScreenSize(Breakpoint.LARGE);\n\n const hasSteps = steps && steps.length > 0;\n const displayGoBack = onGoBack != null && activeStep > 0;\n\n const closeButton = onClose != null && <CloseButton size=\"lg\" onClick={onClose} />;\n const newAvatar = done ? null : avatar;\n\n const flowHeaderContent = (\n <FlowHeader\n className={clsx(\n 'np-flow-navigation__content',\n screenSm == null\n ? 'np-flow-navigation--hidden'\n : {\n 'np-flow-navigation--xs-max': !screenSm,\n // Size switches on parent container which may or may not have the same size as the window.\n 'np-flow-navigation--sm': screenSm,\n 'np-flow-navigation--lg': screenLg,\n },\n )}\n leftContent={\n <>\n {!screenSm && displayGoBack ? (\n <IconButton\n size={40}\n priority=\"tertiary\"\n type=\"default\"\n aria-label={intl.formatMessage(messages.back)}\n onClick={onGoBack}\n >\n <ArrowLeft />\n </IconButton>\n ) : (\n <div className=\"np-flow-header__left\">{logo}</div>\n )}\n {!screenSm && !done && hasSteps && (\n <AnimatedLabel className=\"m-x-1\" steps={steps} activeLabel={activeStep} />\n )}\n </>\n }\n rightContent={\n <div className=\"np-flow-header__right d-flex align-items-center justify-content-end order-2--lg\">\n {newAvatar}\n {newAvatar && closeButton && <span className=\"m-x-1\" />}\n {closeButton}\n </div>\n }\n bottomContent={\n !done && hasSteps ? (\n <Stepper\n activeStep={activeStep}\n steps={steps}\n className={clsx('np-flow-navigation__stepper')}\n />\n ) : null\n }\n layout={!screenLg ? Layout.VERTICAL : Layout.HORIZONTAL}\n />\n );\n\n return (\n <Container\n size=\"fluid\"\n className={clsx('np-flow-navigation', {\n 'np-flow-navigation--border-bottom': showBottomBorder,\n 'np-flow-navigation--no-steps': !hasSteps || done,\n })}\n >\n {flowHeaderContent}\n </Container>\n );\n};\n\nexport default FlowNavigation;\n"],"names":["defaultLogo","_jsx","Logo","FlowNavigation","activeStep","avatar","logo","done","onClose","onGoBack","steps","showBottomBorder","intl","useIntl","screenSm","useScreenSize","Breakpoint","SMALL","screenLg","LARGE","hasSteps","length","displayGoBack","closeButton","CloseButton","size","onClick","newAvatar","flowHeaderContent","FlowHeader","className","clsx","leftContent","_jsxs","_Fragment","children","IconButton","priority","type","formatMessage","messages","back","ArrowLeft","AnimatedLabel","activeLabel","rightContent","bottomContent","Stepper","layout","Layout","VERTICAL","HORIZONTAL","Container"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,MAAMA,WAAW,gBAAGC,cAAA,CAACC,YAAI,KAAG;AAuB5B,MAAMC,cAAc,GAAGA,CAAC;AACtBC,EAAAA,UAAU,GAAG,CAAC;EACdC,MAAM;AACNC,EAAAA,IAAI,GAAGN,WAAW;AAClBO,EAAAA,IAAI,GAAG,KAAK;EACZC,OAAO;EACPC,QAAQ;EACRC,KAAK;AACLC,EAAAA,gBAAgB,GAAG;AAAI,CACH,KAAI;AACxB,EAAA,MAAMC,IAAI,GAAGC,iBAAO,EAAE;AACtB,EAAA,MAAMC,QAAQ,GAAGC,2BAAa,CAACC,wBAAU,CAACC,KAAK,CAAC;AAChD,EAAA,MAAMC,QAAQ,GAAGH,2BAAa,CAACC,wBAAU,CAACG,KAAK,CAAC;EAEhD,MAAMC,QAAQ,GAAGV,KAAK,IAAIA,KAAK,CAACW,MAAM,GAAG,CAAC;EAC1C,MAAMC,aAAa,GAAGb,QAAQ,IAAI,IAAI,IAAIL,UAAU,GAAG,CAAC;EAExD,MAAMmB,WAAW,GAAGf,OAAO,IAAI,IAAI,iBAAIP,cAAA,CAACuB,uBAAW,EAAA;AAACC,IAAAA,IAAI,EAAC,IAAI;AAACC,IAAAA,OAAO,EAAElB;AAAQ,IAAG;AAClF,EAAA,MAAMmB,SAAS,GAAGpB,IAAI,GAAG,IAAI,GAAGF,MAAM;AAEtC,EAAA,MAAMuB,iBAAiB,gBACrB3B,cAAA,CAAC4B,kBAAU,EAAA;IACTC,SAAS,EAAEC,SAAI,CACb,6BAA6B,EAC7BjB,QAAQ,IAAI,IAAI,GACZ,4BAA4B,GAC5B;MACE,4BAA4B,EAAE,CAACA,QAAQ;AACvC;AACA,MAAA,wBAAwB,EAAEA,QAAQ;AAClC,MAAA,wBAAwB,EAAEI;AAC3B,KAAA,CACL;IACFc,WAAW,eACTC,eAAA,CAAAC,mBAAA,EAAA;MAAAC,QAAA,EAAA,CACG,CAACrB,QAAQ,IAAIQ,aAAa,gBACzBrB,cAAA,CAACmC,kBAAU,EAAA;AACTX,QAAAA,IAAI,EAAE,EAAG;AACTY,QAAAA,QAAQ,EAAC,UAAU;AACnBC,QAAAA,IAAI,EAAC,SAAS;AACd,QAAA,YAAA,EAAY1B,IAAI,CAAC2B,aAAa,CAACC,+BAAQ,CAACC,IAAI,CAAE;AAC9Cf,QAAAA,OAAO,EAAEjB,QAAS;AAAA0B,QAAAA,QAAA,eAElBlC,cAAA,CAACyC,eAAS,EAAA,EAAA;OACA,CAAC,gBAEbzC,cAAA,CAAA,KAAA,EAAA;AAAK6B,QAAAA,SAAS,EAAC,sBAAsB;AAAAK,QAAAA,QAAA,EAAE7B;AAAI,OAAM,CAClD,EACA,CAACQ,QAAQ,IAAI,CAACP,IAAI,IAAIa,QAAQ,iBAC7BnB,cAAA,CAAC0C,qBAAa,EAAA;AAACb,QAAAA,SAAS,EAAC,OAAO;AAACpB,QAAAA,KAAK,EAAEA,KAAM;AAACkC,QAAAA,WAAW,EAAExC;AAAW,OAAA,CACxE;AAAA,KACH,CACD;AACDyC,IAAAA,YAAY,eACVZ,eAAA,CAAA,KAAA,EAAA;AAAKH,MAAAA,SAAS,EAAC,iFAAiF;AAAAK,MAAAA,QAAA,GAC7FR,SAAS,EACTA,SAAS,IAAIJ,WAAW,iBAAItB,cAAA,CAAA,MAAA,EAAA;AAAM6B,QAAAA,SAAS,EAAC;OAAO,CAAG,EACtDP,WAAW;AAAA,KACT,CACN;IACDuB,aAAa,EACX,CAACvC,IAAI,IAAIa,QAAQ,gBACfnB,cAAA,CAAC8C,eAAO,EAAA;AACN3C,MAAAA,UAAU,EAAEA,UAAW;AACvBM,MAAAA,KAAK,EAAEA,KAAM;MACboB,SAAS,EAAEC,SAAI,CAAC,6BAA6B;KAAE,CAC/C,GACA,IACL;IACDiB,MAAM,EAAE,CAAC9B,QAAQ,GAAG+B,cAAM,CAACC,QAAQ,GAAGD,cAAM,CAACE;AAAW,GAAA,CAE3D;EAED,oBACElD,cAAA,CAACmD,iBAAS,EAAA;AACR3B,IAAAA,IAAI,EAAC,OAAO;AACZK,IAAAA,SAAS,EAAEC,SAAI,CAAC,oBAAoB,EAAE;AACpC,MAAA,mCAAmC,EAAEpB,gBAAgB;MACrD,8BAA8B,EAAE,CAACS,QAAQ,IAAIb;AAC9C,KAAA,CAAE;AAAA4B,IAAAA,QAAA,EAEFP;AAAiB,GACT,CAAC;AAEhB;;;;"}
|
|
@@ -47,12 +47,13 @@ const FlowNavigation = ({
|
|
|
47
47
|
const intl = useIntl();
|
|
48
48
|
const screenSm = useScreenSize(Breakpoint.SMALL);
|
|
49
49
|
const screenLg = useScreenSize(Breakpoint.LARGE);
|
|
50
|
+
const hasSteps = steps && steps.length > 0;
|
|
51
|
+
const displayGoBack = onGoBack != null && activeStep > 0;
|
|
50
52
|
const closeButton = onClose != null && /*#__PURE__*/jsx(CloseButton, {
|
|
51
53
|
size: "lg",
|
|
52
54
|
onClick: onClose
|
|
53
55
|
});
|
|
54
56
|
const newAvatar = done ? null : avatar;
|
|
55
|
-
const displayGoBack = onGoBack != null && activeStep > 0;
|
|
56
57
|
const flowHeaderContent = /*#__PURE__*/jsx(FlowHeader, {
|
|
57
58
|
className: clsx('np-flow-navigation__content', screenSm == null ? 'np-flow-navigation--hidden' : {
|
|
58
59
|
'np-flow-navigation--xs-max': !screenSm,
|
|
@@ -71,7 +72,7 @@ const FlowNavigation = ({
|
|
|
71
72
|
}) : /*#__PURE__*/jsx("div", {
|
|
72
73
|
className: "np-flow-header__left",
|
|
73
74
|
children: logo
|
|
74
|
-
}), !screenSm && !done &&
|
|
75
|
+
}), !screenSm && !done && hasSteps && /*#__PURE__*/jsx(AnimatedLabel, {
|
|
75
76
|
className: "m-x-1",
|
|
76
77
|
steps: steps,
|
|
77
78
|
activeLabel: activeStep
|
|
@@ -83,7 +84,7 @@ const FlowNavigation = ({
|
|
|
83
84
|
className: "m-x-1"
|
|
84
85
|
}), closeButton]
|
|
85
86
|
}),
|
|
86
|
-
bottomContent: !done &&
|
|
87
|
+
bottomContent: !done && hasSteps ? /*#__PURE__*/jsx(Stepper, {
|
|
87
88
|
activeStep: activeStep,
|
|
88
89
|
steps: steps,
|
|
89
90
|
className: clsx('np-flow-navigation__stepper')
|
|
@@ -93,7 +94,8 @@ const FlowNavigation = ({
|
|
|
93
94
|
return /*#__PURE__*/jsx(Container, {
|
|
94
95
|
size: "fluid",
|
|
95
96
|
className: clsx('np-flow-navigation', {
|
|
96
|
-
'np-flow-navigation--border-bottom': showBottomBorder
|
|
97
|
+
'np-flow-navigation--border-bottom': showBottomBorder,
|
|
98
|
+
'np-flow-navigation--no-steps': !hasSteps || done
|
|
97
99
|
}),
|
|
98
100
|
children: flowHeaderContent
|
|
99
101
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlowNavigation.mjs","sources":["../../src/FlowNavigation/FlowNavigation.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useIntl } from 'react-intl';\nimport { Breakpoint } from '@transferwise/neptune-tokens';\n\nimport { Layout } from '../common';\nimport { CloseButton } from '../common/CloseButton';\nimport FlowHeader from '../common/FlowHeader/FlowHeader';\nimport Logo from '../Logo';\nimport Stepper, { type Step } from '../Stepper/Stepper';\nimport Container from '../Container';\n\nimport { useScreenSize } from '../common/hooks/useScreenSize';\nimport messages from './FlowNavigation.messages';\nimport AnimatedLabel from './AnimatedLabel';\nimport IconButton from '../IconButton';\nimport { ArrowLeft } from '@transferwise/icons';\n\nconst defaultLogo = <Logo />;\n\nexport interface FlowNavigationProps {\n /** @default 0 */\n activeStep?: number;\n avatar?: React.ReactNode;\n /** @default <Logo /> */\n logo?: React.ReactNode;\n /** @default false */\n done?: boolean;\n /** Called when the close button is clicked. If not provided the close button won't show */\n onClose?: (() => void) | React.MouseEventHandler<HTMLButtonElement>;\n /** Called when the back button is clicked. If not provided the back button won't show. The back button only shows on small screens */\n onGoBack?: () => void;\n /** Steps to be displayed in stepper. If not provided, the stepper won't show. */\n steps?: readonly Step[];\n /**\n * Controls whether the bottom border is displayed.\n * @default true\n */\n showBottomBorder?: boolean;\n}\n\nconst FlowNavigation = ({\n activeStep = 0,\n avatar,\n logo = defaultLogo,\n done = false,\n onClose,\n onGoBack,\n steps,\n showBottomBorder = true,\n}: FlowNavigationProps) => {\n const intl = useIntl();\n const screenSm = useScreenSize(Breakpoint.SMALL);\n const screenLg = useScreenSize(Breakpoint.LARGE);\n\n const closeButton = onClose != null && <CloseButton size=\"lg\" onClick={onClose} />;\n
|
|
1
|
+
{"version":3,"file":"FlowNavigation.mjs","sources":["../../src/FlowNavigation/FlowNavigation.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { useIntl } from 'react-intl';\nimport { Breakpoint } from '@transferwise/neptune-tokens';\n\nimport { Layout } from '../common';\nimport { CloseButton } from '../common/CloseButton';\nimport FlowHeader from '../common/FlowHeader/FlowHeader';\nimport Logo from '../Logo';\nimport Stepper, { type Step } from '../Stepper/Stepper';\nimport Container from '../Container';\n\nimport { useScreenSize } from '../common/hooks/useScreenSize';\nimport messages from './FlowNavigation.messages';\nimport AnimatedLabel from './AnimatedLabel';\nimport IconButton from '../IconButton';\nimport { ArrowLeft } from '@transferwise/icons';\n\nconst defaultLogo = <Logo />;\n\nexport interface FlowNavigationProps {\n /** @default 0 */\n activeStep?: number;\n avatar?: React.ReactNode;\n /** @default <Logo /> */\n logo?: React.ReactNode;\n /** @default false */\n done?: boolean;\n /** Called when the close button is clicked. If not provided the close button won't show */\n onClose?: (() => void) | React.MouseEventHandler<HTMLButtonElement>;\n /** Called when the back button is clicked. If not provided the back button won't show. The back button only shows on small screens */\n onGoBack?: () => void;\n /** Steps to be displayed in stepper. If not provided, the stepper won't show. */\n steps?: readonly Step[];\n /**\n * Controls whether the bottom border is displayed.\n * @default true\n */\n showBottomBorder?: boolean;\n}\n\nconst FlowNavigation = ({\n activeStep = 0,\n avatar,\n logo = defaultLogo,\n done = false,\n onClose,\n onGoBack,\n steps,\n showBottomBorder = true,\n}: FlowNavigationProps) => {\n const intl = useIntl();\n const screenSm = useScreenSize(Breakpoint.SMALL);\n const screenLg = useScreenSize(Breakpoint.LARGE);\n\n const hasSteps = steps && steps.length > 0;\n const displayGoBack = onGoBack != null && activeStep > 0;\n\n const closeButton = onClose != null && <CloseButton size=\"lg\" onClick={onClose} />;\n const newAvatar = done ? null : avatar;\n\n const flowHeaderContent = (\n <FlowHeader\n className={clsx(\n 'np-flow-navigation__content',\n screenSm == null\n ? 'np-flow-navigation--hidden'\n : {\n 'np-flow-navigation--xs-max': !screenSm,\n // Size switches on parent container which may or may not have the same size as the window.\n 'np-flow-navigation--sm': screenSm,\n 'np-flow-navigation--lg': screenLg,\n },\n )}\n leftContent={\n <>\n {!screenSm && displayGoBack ? (\n <IconButton\n size={40}\n priority=\"tertiary\"\n type=\"default\"\n aria-label={intl.formatMessage(messages.back)}\n onClick={onGoBack}\n >\n <ArrowLeft />\n </IconButton>\n ) : (\n <div className=\"np-flow-header__left\">{logo}</div>\n )}\n {!screenSm && !done && hasSteps && (\n <AnimatedLabel className=\"m-x-1\" steps={steps} activeLabel={activeStep} />\n )}\n </>\n }\n rightContent={\n <div className=\"np-flow-header__right d-flex align-items-center justify-content-end order-2--lg\">\n {newAvatar}\n {newAvatar && closeButton && <span className=\"m-x-1\" />}\n {closeButton}\n </div>\n }\n bottomContent={\n !done && hasSteps ? (\n <Stepper\n activeStep={activeStep}\n steps={steps}\n className={clsx('np-flow-navigation__stepper')}\n />\n ) : null\n }\n layout={!screenLg ? Layout.VERTICAL : Layout.HORIZONTAL}\n />\n );\n\n return (\n <Container\n size=\"fluid\"\n className={clsx('np-flow-navigation', {\n 'np-flow-navigation--border-bottom': showBottomBorder,\n 'np-flow-navigation--no-steps': !hasSteps || done,\n })}\n >\n {flowHeaderContent}\n </Container>\n );\n};\n\nexport default FlowNavigation;\n"],"names":["defaultLogo","_jsx","Logo","FlowNavigation","activeStep","avatar","logo","done","onClose","onGoBack","steps","showBottomBorder","intl","useIntl","screenSm","useScreenSize","Breakpoint","SMALL","screenLg","LARGE","hasSteps","length","displayGoBack","closeButton","CloseButton","size","onClick","newAvatar","flowHeaderContent","FlowHeader","className","clsx","leftContent","_jsxs","_Fragment","children","IconButton","priority","type","formatMessage","messages","back","ArrowLeft","AnimatedLabel","activeLabel","rightContent","bottomContent","Stepper","layout","Layout","VERTICAL","HORIZONTAL","Container"],"mappings":"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"}
|
|
@@ -7,6 +7,8 @@ var React = require('react');
|
|
|
7
7
|
var reactIntl = require('react-intl');
|
|
8
8
|
var virtua = require('virtua');
|
|
9
9
|
var SearchInput = require('../../SearchInput/SearchInput.js');
|
|
10
|
+
var constants = require('../constants.js');
|
|
11
|
+
var useTypeahead = require('../hooks/useTypeahead.js');
|
|
10
12
|
var SelectInput_contexts = require('../SelectInput.contexts.js');
|
|
11
13
|
var SelectInput_utils = require('../SelectInput.utils.js');
|
|
12
14
|
var SelectInput_messages = require('../SelectInput.messages.js');
|
|
@@ -28,7 +30,9 @@ function SelectInputOptions({
|
|
|
28
30
|
searchInputRef,
|
|
29
31
|
listboxRef,
|
|
30
32
|
filterQuery,
|
|
33
|
+
initialTypeaheadKey,
|
|
31
34
|
onFilterChange,
|
|
35
|
+
onInitialTypeaheadHandled,
|
|
32
36
|
listBoxLabel,
|
|
33
37
|
listBoxLabelledBy,
|
|
34
38
|
autocomplete,
|
|
@@ -39,12 +43,35 @@ function SelectInputOptions({
|
|
|
39
43
|
const virtualiserHandlerRef = React.useRef(null);
|
|
40
44
|
const controllerRef = filterable ? searchInputRef : listboxRef;
|
|
41
45
|
const initialRenderRef = React.useRef(true);
|
|
46
|
+
const deferredFilterQuery = React.useDeferredValue(filterQuery);
|
|
47
|
+
const handleTypeahead = useTypeahead.useTypeahead({
|
|
48
|
+
disabled: filterable,
|
|
49
|
+
onMatch: onInitialTypeaheadHandled
|
|
50
|
+
});
|
|
51
|
+
React.useEffect(() => {
|
|
52
|
+
if (filterable || initialTypeaheadKey == null) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const animationFrame = requestAnimationFrame(() => {
|
|
56
|
+
if (listboxRef.current == null) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
listboxRef.current.focus({
|
|
60
|
+
preventScroll: true
|
|
61
|
+
});
|
|
62
|
+
listboxRef.current.dispatchEvent(new KeyboardEvent('keydown', {
|
|
63
|
+
key: initialTypeaheadKey,
|
|
64
|
+
bubbles: true
|
|
65
|
+
}));
|
|
66
|
+
});
|
|
67
|
+
return () => cancelAnimationFrame(animationFrame);
|
|
68
|
+
}, [filterable, initialTypeaheadKey, listboxRef]);
|
|
42
69
|
const needle = React.useMemo(() => {
|
|
43
70
|
if (filterable) {
|
|
44
|
-
return
|
|
71
|
+
return deferredFilterQuery ? SelectInput_utils.searchableString(deferredFilterQuery) : null;
|
|
45
72
|
}
|
|
46
73
|
return undefined;
|
|
47
|
-
}, [
|
|
74
|
+
}, [deferredFilterQuery, filterable]);
|
|
48
75
|
React.useEffect(() => {
|
|
49
76
|
if (needle) {
|
|
50
77
|
// Ensure having an active option while filtering.
|
|
@@ -102,13 +129,13 @@ function SelectInputOptions({
|
|
|
102
129
|
}
|
|
103
130
|
return item;
|
|
104
131
|
});
|
|
105
|
-
return SelectInput_utils.sortSelectInputItems(filtered, sortFilteredOptions,
|
|
132
|
+
return SelectInput_utils.sortSelectInputItems(filtered, sortFilteredOptions, deferredFilterQuery);
|
|
106
133
|
}
|
|
107
134
|
return SelectInput_utils.filterSelectInputItems(dedupedItems, item => SelectInput_utils.selectInputOptionItemIncludesNeedle(item, needle));
|
|
108
135
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
109
136
|
}, [needle, items, compareValues]);
|
|
110
137
|
const resultsEmpty = needle != null && filteredItems.length === 0;
|
|
111
|
-
const virtualized = filteredItems.length >
|
|
138
|
+
const virtualized = filteredItems.length > constants.MAX_ITEMS_WITHOUT_VIRTUALIZATION;
|
|
112
139
|
// Items shown once shall be kept mounted until the needle changes, otherwise
|
|
113
140
|
// the scroll position may jump around inadvertently. Pattern adopted from:
|
|
114
141
|
// https://inokawa.github.io/virtua/?path=/story/advanced-keep-offscreen-items--append-only
|
|
@@ -190,7 +217,7 @@ function SelectInputOptions({
|
|
|
190
217
|
shape: "rectangle",
|
|
191
218
|
placeholder: filterPlaceholder,
|
|
192
219
|
"aria-label": filterPlaceholder,
|
|
193
|
-
|
|
220
|
+
value: filterQuery,
|
|
194
221
|
"aria-autocomplete": "list",
|
|
195
222
|
"aria-expanded": true,
|
|
196
223
|
"aria-controls": listboxId,
|
|
@@ -251,6 +278,7 @@ function SelectInputOptions({
|
|
|
251
278
|
"aria-labelledby": listBoxLabelledBy,
|
|
252
279
|
tabIndex: 0,
|
|
253
280
|
className: "np-select-input-listbox",
|
|
281
|
+
onKeyDownCapture: handleTypeahead,
|
|
254
282
|
children: !virtualized ? filteredItems.map((_, index) => getItemNode(index)) : /*#__PURE__*/jsxRuntime.jsx(virtua.Virtualizer, {
|
|
255
283
|
ref: virtualiserHandlerRef,
|
|
256
284
|
data: filteredItems,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectInputOptions.js","sources":["../../../../src/Inputs/SelectInput/Options/SelectInputOptions.tsx"],"sourcesContent":["import { CrossCircle } from '@transferwise/icons';\nimport { ListboxOptions } from '@headlessui/react';\nimport { clsx } from 'clsx';\nimport { useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { Virtualizer, type VirtualizerHandle } from 'virtua';\n\nimport { SearchInput } from '../../SearchInput/SearchInput';\nimport {\n SelectInputItemsCountContext,\n SelectInputItemPositionContext,\n} from '../SelectInput.contexts';\nimport {\n dedupeSelectInputItems,\n filterSelectInputItems,\n MAX_ITEMS_WITHOUT_VIRTUALIZATION,\n searchableString,\n selectInputOptionItemIncludesNeedle,\n sortSelectInputItems,\n} from '../SelectInput.utils';\nimport { SelectInputOptionItem, SelectInputProps, SelectInputItem } from '../SelectInput.types';\nimport messages from '../SelectInput.messages';\n\nimport { SelectInputItemView } from '../ItemView';\nimport { SelectInputOptionsContainer } from './OptionsContainer';\n\n/**\n * Props for the SelectInputOptions component.\n */\nexport interface SelectInputOptionsProps<T = string> extends Pick<\n SelectInputProps<T>,\n | 'items'\n | 'renderValue'\n | 'renderFooter'\n | 'filterable'\n | 'filterPlaceholder'\n | 'id'\n | 'parentId'\n | 'compareValues'\n | 'sortFilteredOptions'\n> {\n searchInputRef: React.MutableRefObject<HTMLInputElement | null>;\n listboxRef: React.MutableRefObject<HTMLDivElement | null>;\n filterQuery: string;\n onFilterChange: (query: string) => void;\n listBoxLabel?: string;\n listBoxLabelledBy?: string;\n autocomplete?: string;\n name?: string;\n onAutocompleteSelect?: (value: T) => void;\n}\n\n/**\n * The main options container component for SelectInput.\n * Manages filtering, virtualisation, and rendering of options.\n */\nexport function SelectInputOptions<T = string>({\n id,\n parentId,\n items,\n compareValues: compareValuesProp,\n renderValue = String,\n renderFooter,\n filterable = false,\n filterPlaceholder,\n sortFilteredOptions,\n searchInputRef,\n listboxRef,\n filterQuery,\n onFilterChange,\n listBoxLabel,\n listBoxLabelledBy,\n autocomplete,\n name,\n onAutocompleteSelect,\n}: SelectInputOptionsProps<T>) {\n const intl = useIntl();\n const virtualiserHandlerRef = useRef<VirtualizerHandle>(null);\n const controllerRef = filterable ? searchInputRef : listboxRef;\n const initialRenderRef = useRef(true);\n\n const needle = useMemo(() => {\n if (filterable) {\n return filterQuery ? searchableString(filterQuery) : null;\n }\n return undefined;\n }, [filterQuery, filterable]);\n useEffect(() => {\n if (needle) {\n // Ensure having an active option while filtering.\n // Without `requestAnimationFrame` upon which React depends for scheduling\n // updates, the active status would only show for a split second and then\n // disappear inadvertently.\n requestAnimationFrame(() => {\n if (\n controllerRef.current != null &&\n !controllerRef.current.hasAttribute('aria-activedescendant')\n ) {\n // Activate first option via synthetic key press\n controllerRef.current.dispatchEvent(\n new KeyboardEvent('keydown', { key: 'Home', bubbles: true }),\n );\n }\n });\n }\n }, [controllerRef, needle]);\n\n const compareValues = useMemo(() => {\n if (!compareValuesProp) {\n return undefined;\n }\n\n if (typeof compareValuesProp === 'function') {\n return (a: NonNullable<T>, b: NonNullable<T>) => compareValuesProp(a, b);\n }\n\n const key = compareValuesProp;\n return (a: NonNullable<T>, b: NonNullable<T>) => {\n if (typeof a === 'object' && a != null && typeof b === 'object' && b != null) {\n return (a as Record<string, unknown>)[key] === (b as Record<string, unknown>)[key];\n }\n return a === b;\n };\n }, [compareValuesProp]);\n\n const filteredItems: readonly SelectInputItem<NonNullable<T> | undefined>[] = useMemo(() => {\n if (needle == null) {\n return items;\n }\n\n const dedupedItems = dedupeSelectInputItems(items, compareValues);\n\n if (sortFilteredOptions) {\n // When sorting, filter out non-matching items completely to avoid ghost items\n const filtered = dedupedItems.map((item) => {\n if (item.type === 'option') {\n return selectInputOptionItemIncludesNeedle(item, needle)\n ? item\n : { ...item, value: undefined };\n }\n if (item.type === 'group') {\n return {\n ...item,\n options: item.options.map((option) =>\n selectInputOptionItemIncludesNeedle(option, needle)\n ? option\n : { ...option, value: undefined },\n ),\n };\n }\n return item;\n });\n\n return sortSelectInputItems(filtered, sortFilteredOptions, filterQuery);\n }\n\n return filterSelectInputItems(dedupedItems, (item) =>\n selectInputOptionItemIncludesNeedle(item, needle),\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [needle, items, compareValues]);\n const resultsEmpty = needle != null && filteredItems.length === 0;\n\n const virtualized = filteredItems.length > MAX_ITEMS_WITHOUT_VIRTUALIZATION;\n\n // Items shown once shall be kept mounted until the needle changes, otherwise\n // the scroll position may jump around inadvertently. Pattern adopted from:\n // https://inokawa.github.io/virtua/?path=/story/advanced-keep-offscreen-items--append-only\n const [virtualState, setVirtualState] = useState<{\n needle: typeof needle;\n length: number;\n mountedIndexes: number[];\n }>({\n needle,\n length: filteredItems.length,\n mountedIndexes: [],\n });\n\n // Note: virtualState.mountedIndexes is in deps but only read in the guarded branch.\n // This means external updates to mountedIndexes will trigger this effect but hit the guard\n // and bail out early. This is intentional and harmless - the guard ensures no unnecessary work.\n useEffect(() => {\n if (virtualState.needle !== needle || virtualState.length !== filteredItems.length) {\n const needleChanged = virtualState.needle !== needle;\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Syncing virtual scroll state with filtered items\n setVirtualState({\n needle,\n length: filteredItems.length,\n mountedIndexes: needleChanged\n ? [] // Reset on needle change\n : filteredItems.length > 0\n ? [...new Set([...virtualState.mountedIndexes, filteredItems.length - 1])] // Add last index\n : virtualState.mountedIndexes,\n });\n }\n }, [\n needle,\n filteredItems.length,\n virtualState.needle,\n virtualState.length,\n virtualState.mountedIndexes,\n ]);\n\n const { mountedIndexes } = virtualState;\n\n const listboxContainerRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n if (listboxContainerRef.current != null) {\n listboxContainerRef.current.style.setProperty(\n '--initial-height',\n `${listboxContainerRef.current.offsetHeight}px`,\n );\n }\n }, []);\n\n useEffect(() => {\n initialRenderRef.current = false;\n }, []);\n\n const showStatus = resultsEmpty;\n const statusId = useId();\n const listboxId = useId();\n\n const getItemNode = (index: number) => {\n const item = filteredItems[index];\n return (\n <SelectInputItemView key={index} item={item} renderValue={renderValue} needle={needle} />\n );\n };\n\n const findMatchingItem = (autocompleteValue: string): T | null => {\n const flatOptions = items\n .flatMap((item) =>\n item.type === 'group' ? item.options : item.type === 'option' ? [item] : [],\n )\n .filter(\n (item): item is SelectInputOptionItem<NonNullable<T>> =>\n item.type === 'option' && item.value != null,\n );\n\n const exactMatch = flatOptions.find(\n (option) =>\n String(option.value) === autocompleteValue ||\n option.filterMatchers?.some((matcher) => matcher === autocompleteValue),\n );\n\n if (exactMatch) {\n return exactMatch.value;\n }\n\n const fuzzyMatch = flatOptions.find((option) =>\n option.filterMatchers?.some((matcher) =>\n matcher.toLowerCase().includes(autocompleteValue.toLowerCase()),\n ),\n );\n\n return fuzzyMatch ? fuzzyMatch.value : null;\n };\n\n return (\n <ListboxOptions\n modal\n as={SelectInputOptionsContainer}\n static\n className=\"np-select-input-options-container\"\n onAriaActiveDescendantChange={(value: React.AriaAttributes['aria-activedescendant']) => {\n if (controllerRef.current != null) {\n if (!initialRenderRef.current && value != null) {\n controllerRef.current.setAttribute('aria-activedescendant', value);\n } else {\n controllerRef.current.removeAttribute('aria-activedescendant');\n }\n }\n }}\n >\n {filterable ? (\n <div className=\"np-select-input-query-container\">\n <SearchInput\n ref={searchInputRef}\n id={id}\n name={name}\n autoComplete={autocomplete}\n role=\"combobox\"\n shape=\"rectangle\"\n placeholder={filterPlaceholder}\n aria-label={filterPlaceholder}\n defaultValue={filterQuery}\n aria-autocomplete=\"list\"\n aria-expanded\n aria-controls={listboxId}\n aria-describedby={showStatus ? statusId : undefined}\n onKeyDown={(event: React.KeyboardEvent<HTMLInputElement>) => {\n // Prevent interfering with the matcher of Headless UI\n // https://mathiasbynens.be/notes/javascript-unicode#regex\n if (/^.$/u.test(event.key)) {\n event.stopPropagation();\n }\n }}\n onChange={(event) => {\n // Free up resources and ensure not to go out of bounds when the\n // resulting item count is less than before\n const inputValue = event.currentTarget.value;\n\n // Free up resources and ensure not to go out of bounds\n setVirtualState((prev) => ({ ...prev, mountedIndexes: [] }));\n onFilterChange(inputValue);\n }}\n onInput={(event) => {\n const inputValue = event.currentTarget.value;\n const inputElement = event.currentTarget;\n\n if (autocomplete && onAutocompleteSelect && inputValue) {\n setTimeout(() => {\n if (inputElement.value === inputValue && inputValue.length > 2) {\n const matchedValue = findMatchingItem(inputValue);\n if (matchedValue !== null) {\n onAutocompleteSelect(matchedValue);\n }\n }\n }, 50);\n }\n }}\n />\n </div>\n ) : null}\n\n <section\n ref={listboxContainerRef}\n tabIndex={-1}\n className={clsx(\n 'np-select-input-listbox-container',\n virtualized && 'np-select-input-listbox-container--virtualized',\n needle == null && // Groups aren't shown when filtering\n items.some((item) => item.type === 'group') &&\n 'np-select-input-listbox-container--has-group',\n )}\n data-wds-parent={parentId ?? undefined}\n >\n {resultsEmpty ? (\n <div id={statusId} className=\"np-select-input-options-status\">\n <CrossCircle size={16} className=\"np-select-input-options-status-icon\" />\n {intl.formatMessage(messages.noResultsFound)}\n </div>\n ) : null}\n\n <div\n ref={listboxRef}\n id={listboxId}\n role=\"listbox\"\n aria-orientation=\"vertical\"\n aria-label={listBoxLabel}\n aria-labelledby={listBoxLabelledBy}\n tabIndex={0}\n className=\"np-select-input-listbox\"\n >\n {!virtualized ? (\n filteredItems.map((_, index) => getItemNode(index))\n ) : (\n <Virtualizer\n ref={virtualiserHandlerRef}\n data={filteredItems}\n keepMounted={mountedIndexes}\n scrollRef={listboxRef} // `VList` doesn't expose this\n onScroll={async () => {\n if (!virtualiserHandlerRef.current) return;\n\n const startIndex = virtualiserHandlerRef.current.findItemIndex(\n virtualiserHandlerRef.current.scrollOffset,\n );\n const endIndex = virtualiserHandlerRef.current.findItemIndex(\n virtualiserHandlerRef.current.scrollOffset +\n virtualiserHandlerRef.current.viewportSize,\n );\n\n setVirtualState((prev) => {\n // Create an array of all indexes that should be visible\n\n const visibleIndexes = [];\n for (let index = startIndex; index <= endIndex; index += 1) {\n // eslint-disable-next-line functional/immutable-data\n visibleIndexes.push(index);\n }\n\n // Combine with previous indexes and sort\n const newMountedIndexes = [\n ...new Set([...prev.mountedIndexes, ...visibleIndexes]),\n ].sort((a, b) => a - b);\n\n return { ...prev, mountedIndexes: newMountedIndexes };\n });\n }}\n >\n {(item, index) => (\n // The position of each item can't be inferred by browsers when\n // virtualizing, as some of the items may not be in the DOM\n <SelectInputItemsCountContext.Provider value={filteredItems.length}>\n <SelectInputItemPositionContext.Provider value={index + 1}>\n {getItemNode(index)}\n </SelectInputItemPositionContext.Provider>\n </SelectInputItemsCountContext.Provider>\n )}\n </Virtualizer>\n )}\n </div>\n\n {renderFooter != null ? (\n <footer className=\"np-select-input-footer\">\n <div\n role=\"none\"\n onKeyDown={(event) => {\n // Prevent interfering with Headless UI\n if (event.key !== 'Escape') {\n event.stopPropagation();\n }\n }}\n >\n {renderFooter({\n resultsEmpty,\n queryNormalized: needle,\n })}\n </div>\n </footer>\n ) : null}\n </section>\n </ListboxOptions>\n );\n}\n"],"names":["SelectInputOptions","id","parentId","items","compareValues","compareValuesProp","renderValue","String","renderFooter","filterable","filterPlaceholder","sortFilteredOptions","searchInputRef","listboxRef","filterQuery","onFilterChange","listBoxLabel","listBoxLabelledBy","autocomplete","name","onAutocompleteSelect","intl","useIntl","virtualiserHandlerRef","useRef","controllerRef","initialRenderRef","needle","useMemo","searchableString","undefined","useEffect","requestAnimationFrame","current","hasAttribute","dispatchEvent","KeyboardEvent","key","bubbles","a","b","filteredItems","dedupedItems","dedupeSelectInputItems","filtered","map","item","type","selectInputOptionItemIncludesNeedle","value","options","option","sortSelectInputItems","filterSelectInputItems","resultsEmpty","length","virtualized","MAX_ITEMS_WITHOUT_VIRTUALIZATION","virtualState","setVirtualState","useState","mountedIndexes","needleChanged","Set","listboxContainerRef","style","setProperty","offsetHeight","showStatus","statusId","useId","listboxId","getItemNode","index","_jsx","SelectInputItemView","findMatchingItem","autocompleteValue","flatOptions","flatMap","filter","exactMatch","find","filterMatchers","some","matcher","fuzzyMatch","toLowerCase","includes","_jsxs","ListboxOptions","modal","as","SelectInputOptionsContainer","static","className","onAriaActiveDescendantChange","setAttribute","removeAttribute","children","SearchInput","ref","autoComplete","role","shape","placeholder","defaultValue","onKeyDown","event","test","stopPropagation","onChange","inputValue","currentTarget","prev","onInput","inputElement","setTimeout","matchedValue","tabIndex","clsx","CrossCircle","size","formatMessage","messages","noResultsFound","_","Virtualizer","data","keepMounted","scrollRef","onScroll","startIndex","findItemIndex","scrollOffset","endIndex","viewportSize","visibleIndexes","push","newMountedIndexes","sort","SelectInputItemsCountContext","Provider","SelectInputItemPositionContext","queryNormalized"],"mappings":";;;;;;;;;;;;;;;;;AAwDM,SAAUA,kBAAkBA,CAAa;EAC7CC,EAAE;EACFC,QAAQ;EACRC,KAAK;AACLC,EAAAA,aAAa,EAAEC,iBAAiB;AAChCC,EAAAA,WAAW,GAAGC,MAAM;EACpBC,YAAY;AACZC,EAAAA,UAAU,GAAG,KAAK;EAClBC,iBAAiB;EACjBC,mBAAmB;EACnBC,cAAc;EACdC,UAAU;EACVC,WAAW;EACXC,cAAc;EACdC,YAAY;EACZC,iBAAiB;EACjBC,YAAY;EACZC,IAAI;AACJC,EAAAA;AAAoB,CACO,EAAA;AAC3B,EAAA,MAAMC,IAAI,GAAGC,iBAAO,EAAE;AACtB,EAAA,MAAMC,qBAAqB,GAAGC,YAAM,CAAoB,IAAI,CAAC;AAC7D,EAAA,MAAMC,aAAa,GAAGhB,UAAU,GAAGG,cAAc,GAAGC,UAAU;AAC9D,EAAA,MAAMa,gBAAgB,GAAGF,YAAM,CAAC,IAAI,CAAC;AAErC,EAAA,MAAMG,MAAM,GAAGC,aAAO,CAAC,MAAK;AAC1B,IAAA,IAAInB,UAAU,EAAE;AACd,MAAA,OAAOK,WAAW,GAAGe,kCAAgB,CAACf,WAAW,CAAC,GAAG,IAAI;AAC3D,IAAA;AACA,IAAA,OAAOgB,SAAS;AAClB,EAAA,CAAC,EAAE,CAAChB,WAAW,EAAEL,UAAU,CAAC,CAAC;AAC7BsB,EAAAA,eAAS,CAAC,MAAK;AACb,IAAA,IAAIJ,MAAM,EAAE;AACV;AACA;AACA;AACA;AACAK,MAAAA,qBAAqB,CAAC,MAAK;AACzB,QAAA,IACEP,aAAa,CAACQ,OAAO,IAAI,IAAI,IAC7B,CAACR,aAAa,CAACQ,OAAO,CAACC,YAAY,CAAC,uBAAuB,CAAC,EAC5D;AACA;UACAT,aAAa,CAACQ,OAAO,CAACE,aAAa,CACjC,IAAIC,aAAa,CAAC,SAAS,EAAE;AAAEC,YAAAA,GAAG,EAAE,MAAM;AAAEC,YAAAA,OAAO,EAAE;AAAI,WAAE,CAAC,CAC7D;AACH,QAAA;AACF,MAAA,CAAC,CAAC;AACJ,IAAA;AACF,EAAA,CAAC,EAAE,CAACb,aAAa,EAAEE,MAAM,CAAC,CAAC;AAE3B,EAAA,MAAMvB,aAAa,GAAGwB,aAAO,CAAC,MAAK;IACjC,IAAI,CAACvB,iBAAiB,EAAE;AACtB,MAAA,OAAOyB,SAAS;AAClB,IAAA;AAEA,IAAA,IAAI,OAAOzB,iBAAiB,KAAK,UAAU,EAAE;MAC3C,OAAO,CAACkC,CAAiB,EAAEC,CAAiB,KAAKnC,iBAAiB,CAACkC,CAAC,EAAEC,CAAC,CAAC;AAC1E,IAAA;IAEA,MAAMH,GAAG,GAAGhC,iBAAiB;AAC7B,IAAA,OAAO,CAACkC,CAAiB,EAAEC,CAAiB,KAAI;AAC9C,MAAA,IAAI,OAAOD,CAAC,KAAK,QAAQ,IAAIA,CAAC,IAAI,IAAI,IAAI,OAAOC,CAAC,KAAK,QAAQ,IAAIA,CAAC,IAAI,IAAI,EAAE;QAC5E,OAAQD,CAA6B,CAACF,GAAG,CAAC,KAAMG,CAA6B,CAACH,GAAG,CAAC;AACpF,MAAA;MACA,OAAOE,CAAC,KAAKC,CAAC;IAChB,CAAC;AACH,EAAA,CAAC,EAAE,CAACnC,iBAAiB,CAAC,CAAC;AAEvB,EAAA,MAAMoC,aAAa,GAA2Db,aAAO,CAAC,MAAK;IACzF,IAAID,MAAM,IAAI,IAAI,EAAE;AAClB,MAAA,OAAOxB,KAAK;AACd,IAAA;AAEA,IAAA,MAAMuC,YAAY,GAAGC,wCAAsB,CAACxC,KAAK,EAAEC,aAAa,CAAC;AAEjE,IAAA,IAAIO,mBAAmB,EAAE;AACvB;AACA,MAAA,MAAMiC,QAAQ,GAAGF,YAAY,CAACG,GAAG,CAAEC,IAAI,IAAI;AACzC,QAAA,IAAIA,IAAI,CAACC,IAAI,KAAK,QAAQ,EAAE;UAC1B,OAAOC,qDAAmC,CAACF,IAAI,EAAEnB,MAAM,CAAC,GACpDmB,IAAI,GACJ;AAAE,YAAA,GAAGA,IAAI;AAAEG,YAAAA,KAAK,EAAEnB;WAAW;AACnC,QAAA;AACA,QAAA,IAAIgB,IAAI,CAACC,IAAI,KAAK,OAAO,EAAE;UACzB,OAAO;AACL,YAAA,GAAGD,IAAI;AACPI,YAAAA,OAAO,EAAEJ,IAAI,CAACI,OAAO,CAACL,GAAG,CAAEM,MAAM,IAC/BH,qDAAmC,CAACG,MAAM,EAAExB,MAAM,CAAC,GAC/CwB,MAAM,GACN;AAAE,cAAA,GAAGA,MAAM;AAAEF,cAAAA,KAAK,EAAEnB;aAAW;WAEtC;AACH,QAAA;AACA,QAAA,OAAOgB,IAAI;AACb,MAAA,CAAC,CAAC;AAEF,MAAA,OAAOM,sCAAoB,CAACR,QAAQ,EAAEjC,mBAAmB,EAAEG,WAAW,CAAC;AACzE,IAAA;AAEA,IAAA,OAAOuC,wCAAsB,CAACX,YAAY,EAAGI,IAAI,IAC/CE,qDAAmC,CAACF,IAAI,EAAEnB,MAAM,CAAC,CAClD;AACD;EACF,CAAC,EAAE,CAACA,MAAM,EAAExB,KAAK,EAAEC,aAAa,CAAC,CAAC;EAClC,MAAMkD,YAAY,GAAG3B,MAAM,IAAI,IAAI,IAAIc,aAAa,CAACc,MAAM,KAAK,CAAC;AAEjE,EAAA,MAAMC,WAAW,GAAGf,aAAa,CAACc,MAAM,GAAGE,kDAAgC;AAE3E;AACA;AACA;AACA,EAAA,MAAM,CAACC,YAAY,EAAEC,eAAe,CAAC,GAAGC,cAAQ,CAI7C;IACDjC,MAAM;IACN4B,MAAM,EAAEd,aAAa,CAACc,MAAM;AAC5BM,IAAAA,cAAc,EAAE;AACjB,GAAA,CAAC;AAEF;AACA;AACA;AACA9B,EAAAA,eAAS,CAAC,MAAK;AACb,IAAA,IAAI2B,YAAY,CAAC/B,MAAM,KAAKA,MAAM,IAAI+B,YAAY,CAACH,MAAM,KAAKd,aAAa,CAACc,MAAM,EAAE;AAClF,MAAA,MAAMO,aAAa,GAAGJ,YAAY,CAAC/B,MAAM,KAAKA,MAAM;AACpD;AACAgC,MAAAA,eAAe,CAAC;QACdhC,MAAM;QACN4B,MAAM,EAAEd,aAAa,CAACc,MAAM;AAC5BM,QAAAA,cAAc,EAAEC,aAAa,GACzB,EAAE;UACFrB,aAAa,CAACc,MAAM,GAAG,CAAC,GACtB,CAAC,GAAG,IAAIQ,GAAG,CAAC,CAAC,GAAGL,YAAY,CAACG,cAAc,EAAEpB,aAAa,CAACc,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;AAAC,UACzEG,YAAY,CAACG;AACpB,OAAA,CAAC;AACJ,IAAA;EACF,CAAC,EAAE,CACDlC,MAAM,EACNc,aAAa,CAACc,MAAM,EACpBG,YAAY,CAAC/B,MAAM,EACnB+B,YAAY,CAACH,MAAM,EACnBG,YAAY,CAACG,cAAc,CAC5B,CAAC;EAEF,MAAM;AAAEA,IAAAA;AAAc,GAAE,GAAGH,YAAY;AAEvC,EAAA,MAAMM,mBAAmB,GAAGxC,YAAM,CAAiB,IAAI,CAAC;AACxDO,EAAAA,eAAS,CAAC,MAAK;AACb,IAAA,IAAIiC,mBAAmB,CAAC/B,OAAO,IAAI,IAAI,EAAE;AACvC+B,MAAAA,mBAAmB,CAAC/B,OAAO,CAACgC,KAAK,CAACC,WAAW,CAC3C,kBAAkB,EAClB,CAAA,EAAGF,mBAAmB,CAAC/B,OAAO,CAACkC,YAAY,IAAI,CAChD;AACH,IAAA;EACF,CAAC,EAAE,EAAE,CAAC;AAENpC,EAAAA,eAAS,CAAC,MAAK;IACbL,gBAAgB,CAACO,OAAO,GAAG,KAAK;EAClC,CAAC,EAAE,EAAE,CAAC;EAEN,MAAMmC,UAAU,GAAGd,YAAY;AAC/B,EAAA,MAAMe,QAAQ,GAAGC,WAAK,EAAE;AACxB,EAAA,MAAMC,SAAS,GAAGD,WAAK,EAAE;EAEzB,MAAME,WAAW,GAAIC,KAAa,IAAI;AACpC,IAAA,MAAM3B,IAAI,GAAGL,aAAa,CAACgC,KAAK,CAAC;IACjC,oBACEC,cAAA,CAACC,uCAAmB,EAAA;AAAa7B,MAAAA,IAAI,EAAEA,IAAK;AAACxC,MAAAA,WAAW,EAAEA,WAAY;AAACqB,MAAAA,MAAM,EAAEA;AAAO,KAAA,EAA5D8C,KAA4D,CAAG;EAE7F,CAAC;EAED,MAAMG,gBAAgB,GAAIC,iBAAyB,IAAc;IAC/D,MAAMC,WAAW,GAAG3E,KAAK,CACtB4E,OAAO,CAAEjC,IAAI,IACZA,IAAI,CAACC,IAAI,KAAK,OAAO,GAAGD,IAAI,CAACI,OAAO,GAAGJ,IAAI,CAACC,IAAI,KAAK,QAAQ,GAAG,CAACD,IAAI,CAAC,GAAG,EAAE,CAC5E,CACAkC,MAAM,CACJlC,IAAI,IACHA,IAAI,CAACC,IAAI,KAAK,QAAQ,IAAID,IAAI,CAACG,KAAK,IAAI,IAAI,CAC/C;AAEH,IAAA,MAAMgC,UAAU,GAAGH,WAAW,CAACI,IAAI,CAChC/B,MAAM,IACL5C,MAAM,CAAC4C,MAAM,CAACF,KAAK,CAAC,KAAK4B,iBAAiB,IAC1C1B,MAAM,CAACgC,cAAc,EAAEC,IAAI,CAAEC,OAAO,IAAKA,OAAO,KAAKR,iBAAiB,CAAC,CAC1E;AAED,IAAA,IAAII,UAAU,EAAE;MACd,OAAOA,UAAU,CAAChC,KAAK;AACzB,IAAA;AAEA,IAAA,MAAMqC,UAAU,GAAGR,WAAW,CAACI,IAAI,CAAE/B,MAAM,IACzCA,MAAM,CAACgC,cAAc,EAAEC,IAAI,CAAEC,OAAO,IAClCA,OAAO,CAACE,WAAW,EAAE,CAACC,QAAQ,CAACX,iBAAiB,CAACU,WAAW,EAAE,CAAC,CAChE,CACF;AAED,IAAA,OAAOD,UAAU,GAAGA,UAAU,CAACrC,KAAK,GAAG,IAAI;EAC7C,CAAC;EAED,oBACEwC,eAAA,CAACC,oBAAc,EAAA;IACbC,KAAK,EAAA,IAAA;AACLC,IAAAA,EAAE,EAAEC,uDAA4B;IAChCC,MAAM,EAAA,IAAA;AACNC,IAAAA,SAAS,EAAC,mCAAmC;IAC7CC,4BAA4B,EAAG/C,KAAoD,IAAI;AACrF,MAAA,IAAIxB,aAAa,CAACQ,OAAO,IAAI,IAAI,EAAE;QACjC,IAAI,CAACP,gBAAgB,CAACO,OAAO,IAAIgB,KAAK,IAAI,IAAI,EAAE;UAC9CxB,aAAa,CAACQ,OAAO,CAACgE,YAAY,CAAC,uBAAuB,EAAEhD,KAAK,CAAC;AACpE,QAAA,CAAC,MAAM;AACLxB,UAAAA,aAAa,CAACQ,OAAO,CAACiE,eAAe,CAAC,uBAAuB,CAAC;AAChE,QAAA;AACF,MAAA;IACF,CAAE;IAAAC,QAAA,EAAA,CAED1F,UAAU,gBACTiE,cAAA,CAAA,KAAA,EAAA;AAAKqB,MAAAA,SAAS,EAAC,iCAAiC;MAAAI,QAAA,eAC9CzB,cAAA,CAAC0B,uBAAW,EAAA;AACVC,QAAAA,GAAG,EAAEzF,cAAe;AACpBX,QAAAA,EAAE,EAAEA,EAAG;AACPkB,QAAAA,IAAI,EAAEA,IAAK;AACXmF,QAAAA,YAAY,EAAEpF,YAAa;AAC3BqF,QAAAA,IAAI,EAAC,UAAU;AACfC,QAAAA,KAAK,EAAC,WAAW;AACjBC,QAAAA,WAAW,EAAE/F,iBAAkB;AAC/B,QAAA,YAAA,EAAYA,iBAAkB;AAC9BgG,QAAAA,YAAY,EAAE5F,WAAY;AAC1B,QAAA,mBAAA,EAAkB,MAAM;QACxB,eAAA,EAAA,IAAa;AACb,QAAA,eAAA,EAAeyD,SAAU;AACzB,QAAA,kBAAA,EAAkBH,UAAU,GAAGC,QAAQ,GAAGvC,SAAU;QACpD6E,SAAS,EAAGC,KAA4C,IAAI;AAC1D;AACA;UACA,IAAI,MAAM,CAACC,IAAI,CAACD,KAAK,CAACvE,GAAG,CAAC,EAAE;YAC1BuE,KAAK,CAACE,eAAe,EAAE;AACzB,UAAA;QACF,CAAE;QACFC,QAAQ,EAAGH,KAAK,IAAI;AAClB;AACA;AACA,UAAA,MAAMI,UAAU,GAAGJ,KAAK,CAACK,aAAa,CAAChE,KAAK;AAE5C;UACAU,eAAe,CAAEuD,IAAI,KAAM;AAAE,YAAA,GAAGA,IAAI;AAAErD,YAAAA,cAAc,EAAE;AAAE,WAAE,CAAC,CAAC;UAC5D9C,cAAc,CAACiG,UAAU,CAAC;QAC5B,CAAE;QACFG,OAAO,EAAGP,KAAK,IAAI;AACjB,UAAA,MAAMI,UAAU,GAAGJ,KAAK,CAACK,aAAa,CAAChE,KAAK;AAC5C,UAAA,MAAMmE,YAAY,GAAGR,KAAK,CAACK,aAAa;AAExC,UAAA,IAAI/F,YAAY,IAAIE,oBAAoB,IAAI4F,UAAU,EAAE;AACtDK,YAAAA,UAAU,CAAC,MAAK;cACd,IAAID,YAAY,CAACnE,KAAK,KAAK+D,UAAU,IAAIA,UAAU,CAACzD,MAAM,GAAG,CAAC,EAAE;AAC9D,gBAAA,MAAM+D,YAAY,GAAG1C,gBAAgB,CAACoC,UAAU,CAAC;gBACjD,IAAIM,YAAY,KAAK,IAAI,EAAE;kBACzBlG,oBAAoB,CAACkG,YAAY,CAAC;AACpC,gBAAA;AACF,cAAA;YACF,CAAC,EAAE,EAAE,CAAC;AACR,UAAA;AACF,QAAA;OAAE;AAEN,KAAK,CAAC,GACJ,IAAI,eAER7B,eAAA,CAAA,SAAA,EAAA;AACEY,MAAAA,GAAG,EAAErC,mBAAoB;MACzBuD,QAAQ,EAAE,EAAG;MACbxB,SAAS,EAAEyB,SAAI,CACb,mCAAmC,EACnChE,WAAW,IAAI,gDAAgD,EAC/D7B,MAAM,IAAI,IAAI;AAAI;AAChBxB,MAAAA,KAAK,CAACiF,IAAI,CAAEtC,IAAI,IAAKA,IAAI,CAACC,IAAI,KAAK,OAAO,CAAC,IAC3C,8CAA8C,CAChD;MACF,iBAAA,EAAiB7C,QAAQ,IAAI4B,SAAU;MAAAqE,QAAA,EAAA,CAEtC7C,YAAY,gBACXmC,eAAA,CAAA,KAAA,EAAA;AAAKxF,QAAAA,EAAE,EAAEoE,QAAS;AAAC0B,QAAAA,SAAS,EAAC,gCAAgC;QAAAI,QAAA,EAAA,cAC3DzB,cAAA,CAAC+C,iBAAW,EAAA;AAACC,UAAAA,IAAI,EAAE,EAAG;AAAC3B,UAAAA,SAAS,EAAC;SAAqC,CACtE,EAAC1E,IAAI,CAACsG,aAAa,CAACC,4BAAQ,CAACC,cAAc,CAAC;AAAA,OACzC,CAAC,GACJ,IAAI,eAERnD,cAAA,CAAA,KAAA,EAAA;AACE2B,QAAAA,GAAG,EAAExF,UAAW;AAChBZ,QAAAA,EAAE,EAAEsE,SAAU;AACdgC,QAAAA,IAAI,EAAC,SAAS;AACd,QAAA,kBAAA,EAAiB,UAAU;AAC3B,QAAA,YAAA,EAAYvF,YAAa;AACzB,QAAA,iBAAA,EAAiBC,iBAAkB;AACnCsG,QAAAA,QAAQ,EAAE,CAAE;AACZxB,QAAAA,SAAS,EAAC,yBAAyB;QAAAI,QAAA,EAElC,CAAC3C,WAAW,GACXf,aAAa,CAACI,GAAG,CAAC,CAACiF,CAAC,EAAErD,KAAK,KAAKD,WAAW,CAACC,KAAK,CAAC,CAAC,gBAEnDC,cAAA,CAACqD,kBAAW,EAAA;AACV1B,UAAAA,GAAG,EAAE9E,qBAAsB;AAC3ByG,UAAAA,IAAI,EAAEvF,aAAc;AACpBwF,UAAAA,WAAW,EAAEpE,cAAe;UAC5BqE,SAAS,EAAErH,UAAW;AAAC;UACvBsH,QAAQ,EAAE,YAAW;AACnB,YAAA,IAAI,CAAC5G,qBAAqB,CAACU,OAAO,EAAE;AAEpC,YAAA,MAAMmG,UAAU,GAAG7G,qBAAqB,CAACU,OAAO,CAACoG,aAAa,CAC5D9G,qBAAqB,CAACU,OAAO,CAACqG,YAAY,CAC3C;AACD,YAAA,MAAMC,QAAQ,GAAGhH,qBAAqB,CAACU,OAAO,CAACoG,aAAa,CAC1D9G,qBAAqB,CAACU,OAAO,CAACqG,YAAY,GACxC/G,qBAAqB,CAACU,OAAO,CAACuG,YAAY,CAC7C;YAED7E,eAAe,CAAEuD,IAAI,IAAI;AACvB;cAEA,MAAMuB,cAAc,GAAG,EAAE;AACzB,cAAA,KAAK,IAAIhE,KAAK,GAAG2D,UAAU,EAAE3D,KAAK,IAAI8D,QAAQ,EAAE9D,KAAK,IAAI,CAAC,EAAE;AAC1D;AACAgE,gBAAAA,cAAc,CAACC,IAAI,CAACjE,KAAK,CAAC;AAC5B,cAAA;AAEA;AACA,cAAA,MAAMkE,iBAAiB,GAAG,CACxB,GAAG,IAAI5E,GAAG,CAAC,CAAC,GAAGmD,IAAI,CAACrD,cAAc,EAAE,GAAG4E,cAAc,CAAC,CAAC,CACxD,CAACG,IAAI,CAAC,CAACrG,CAAC,EAAEC,CAAC,KAAKD,CAAC,GAAGC,CAAC,CAAC;cAEvB,OAAO;AAAE,gBAAA,GAAG0E,IAAI;AAAErD,gBAAAA,cAAc,EAAE8E;eAAmB;AACvD,YAAA,CAAC,CAAC;UACJ,CAAE;AAAAxC,UAAAA,QAAA,EAEDA,CAACrD,IAAI,EAAE2B,KAAK;AAAA;AACX;AACA;UACAC,cAAA,CAACmE,iDAA4B,CAACC,QAAQ,EAAA;YAAC7F,KAAK,EAAER,aAAa,CAACc,MAAO;AAAA4C,YAAAA,QAAA,eACjEzB,cAAA,CAACqE,mDAA8B,CAACD,QAAQ,EAAA;cAAC7F,KAAK,EAAEwB,KAAK,GAAG,CAAE;cAAA0B,QAAA,EACvD3B,WAAW,CAACC,KAAK;aACqB;WACJ;SAE9B;AACd,OACE,CAEL,EAACjE,YAAY,IAAI,IAAI,gBACnBkE,cAAA,CAAA,QAAA,EAAA;AAAQqB,QAAAA,SAAS,EAAC,wBAAwB;AAAAI,QAAAA,QAAA,eACxCzB,cAAA,CAAA,KAAA,EAAA;AACE6B,UAAAA,IAAI,EAAC,MAAM;UACXI,SAAS,EAAGC,KAAK,IAAI;AACnB;AACA,YAAA,IAAIA,KAAK,CAACvE,GAAG,KAAK,QAAQ,EAAE;cAC1BuE,KAAK,CAACE,eAAe,EAAE;AACzB,YAAA;UACF,CAAE;UAAAX,QAAA,EAED3F,YAAY,CAAC;YACZ8C,YAAY;AACZ0F,YAAAA,eAAe,EAAErH;WAClB;SACE;OACC,CAAC,GACP,IAAI;AAAA,KACD,CACX;AAAA,GAAgB,CAAC;AAErB;;;;"}
|
|
1
|
+
{"version":3,"file":"SelectInputOptions.js","sources":["../../../../src/Inputs/SelectInput/Options/SelectInputOptions.tsx"],"sourcesContent":["import { CrossCircle } from '@transferwise/icons';\nimport { ListboxOptions } from '@headlessui/react';\nimport { clsx } from 'clsx';\nimport { useDeferredValue, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { Virtualizer, type VirtualizerHandle } from 'virtua';\n\nimport { SearchInput } from '../../SearchInput/SearchInput';\nimport { MAX_ITEMS_WITHOUT_VIRTUALIZATION } from '../constants';\nimport { useTypeahead } from '../hooks/useTypeahead';\nimport {\n SelectInputItemsCountContext,\n SelectInputItemPositionContext,\n} from '../SelectInput.contexts';\nimport {\n dedupeSelectInputItems,\n filterSelectInputItems,\n searchableString,\n selectInputOptionItemIncludesNeedle,\n sortSelectInputItems,\n} from '../SelectInput.utils';\nimport { SelectInputOptionItem, SelectInputProps, SelectInputItem } from '../SelectInput.types';\nimport messages from '../SelectInput.messages';\n\nimport { SelectInputItemView } from '../ItemView';\nimport { SelectInputOptionsContainer } from './OptionsContainer';\n\n/**\n * Props for the SelectInputOptions component.\n */\nexport interface SelectInputOptionsProps<T = string> extends Pick<\n SelectInputProps<T>,\n | 'items'\n | 'renderValue'\n | 'renderFooter'\n | 'filterable'\n | 'filterPlaceholder'\n | 'id'\n | 'parentId'\n | 'compareValues'\n | 'sortFilteredOptions'\n> {\n searchInputRef: React.MutableRefObject<HTMLInputElement | null>;\n listboxRef: React.MutableRefObject<HTMLDivElement | null>;\n filterQuery: string;\n initialTypeaheadKey?: string | null;\n onFilterChange: (query: string) => void;\n onInitialTypeaheadHandled?: () => void;\n listBoxLabel?: string;\n listBoxLabelledBy?: string;\n autocomplete?: string;\n name?: string;\n onAutocompleteSelect?: (value: T) => void;\n}\n\n/**\n * The main options container component for SelectInput.\n * Manages filtering, virtualisation, and rendering of options.\n */\nexport function SelectInputOptions<T = string>({\n id,\n parentId,\n items,\n compareValues: compareValuesProp,\n renderValue = String,\n renderFooter,\n filterable = false,\n filterPlaceholder,\n sortFilteredOptions,\n searchInputRef,\n listboxRef,\n filterQuery,\n initialTypeaheadKey,\n onFilterChange,\n onInitialTypeaheadHandled,\n listBoxLabel,\n listBoxLabelledBy,\n autocomplete,\n name,\n onAutocompleteSelect,\n}: SelectInputOptionsProps<T>) {\n const intl = useIntl();\n const virtualiserHandlerRef = useRef<VirtualizerHandle>(null);\n const controllerRef = filterable ? searchInputRef : listboxRef;\n const initialRenderRef = useRef(true);\n const deferredFilterQuery = useDeferredValue(filterQuery);\n const handleTypeahead = useTypeahead({\n disabled: filterable,\n onMatch: onInitialTypeaheadHandled,\n });\n\n useEffect(() => {\n if (filterable || initialTypeaheadKey == null) {\n return;\n }\n\n const animationFrame = requestAnimationFrame(() => {\n if (listboxRef.current == null) {\n return;\n }\n\n listboxRef.current.focus({ preventScroll: true });\n listboxRef.current.dispatchEvent(\n new KeyboardEvent('keydown', { key: initialTypeaheadKey, bubbles: true }),\n );\n });\n\n return () => cancelAnimationFrame(animationFrame);\n }, [filterable, initialTypeaheadKey, listboxRef]);\n\n const needle = useMemo(() => {\n if (filterable) {\n return deferredFilterQuery ? searchableString(deferredFilterQuery) : null;\n }\n return undefined;\n }, [deferredFilterQuery, filterable]);\n useEffect(() => {\n if (needle) {\n // Ensure having an active option while filtering.\n // Without `requestAnimationFrame` upon which React depends for scheduling\n // updates, the active status would only show for a split second and then\n // disappear inadvertently.\n requestAnimationFrame(() => {\n if (\n controllerRef.current != null &&\n !controllerRef.current.hasAttribute('aria-activedescendant')\n ) {\n // Activate first option via synthetic key press\n controllerRef.current.dispatchEvent(\n new KeyboardEvent('keydown', { key: 'Home', bubbles: true }),\n );\n }\n });\n }\n }, [controllerRef, needle]);\n\n const compareValues = useMemo(() => {\n if (!compareValuesProp) {\n return undefined;\n }\n\n if (typeof compareValuesProp === 'function') {\n return (a: NonNullable<T>, b: NonNullable<T>) => compareValuesProp(a, b);\n }\n\n const key = compareValuesProp;\n return (a: NonNullable<T>, b: NonNullable<T>) => {\n if (typeof a === 'object' && a != null && typeof b === 'object' && b != null) {\n return (a as Record<string, unknown>)[key] === (b as Record<string, unknown>)[key];\n }\n return a === b;\n };\n }, [compareValuesProp]);\n\n const filteredItems: readonly SelectInputItem<NonNullable<T> | undefined>[] = useMemo(() => {\n if (needle == null) {\n return items;\n }\n\n const dedupedItems = dedupeSelectInputItems(items, compareValues);\n\n if (sortFilteredOptions) {\n // When sorting, filter out non-matching items completely to avoid ghost items\n const filtered = dedupedItems.map((item) => {\n if (item.type === 'option') {\n return selectInputOptionItemIncludesNeedle(item, needle)\n ? item\n : { ...item, value: undefined };\n }\n if (item.type === 'group') {\n return {\n ...item,\n options: item.options.map((option) =>\n selectInputOptionItemIncludesNeedle(option, needle)\n ? option\n : { ...option, value: undefined },\n ),\n };\n }\n return item;\n });\n\n return sortSelectInputItems(filtered, sortFilteredOptions, deferredFilterQuery);\n }\n\n return filterSelectInputItems(dedupedItems, (item) =>\n selectInputOptionItemIncludesNeedle(item, needle),\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [needle, items, compareValues]);\n const resultsEmpty = needle != null && filteredItems.length === 0;\n\n const virtualized = filteredItems.length > MAX_ITEMS_WITHOUT_VIRTUALIZATION;\n\n // Items shown once shall be kept mounted until the needle changes, otherwise\n // the scroll position may jump around inadvertently. Pattern adopted from:\n // https://inokawa.github.io/virtua/?path=/story/advanced-keep-offscreen-items--append-only\n const [virtualState, setVirtualState] = useState<{\n needle: typeof needle;\n length: number;\n mountedIndexes: number[];\n }>({\n needle,\n length: filteredItems.length,\n mountedIndexes: [],\n });\n\n // Note: virtualState.mountedIndexes is in deps but only read in the guarded branch.\n // This means external updates to mountedIndexes will trigger this effect but hit the guard\n // and bail out early. This is intentional and harmless - the guard ensures no unnecessary work.\n useEffect(() => {\n if (virtualState.needle !== needle || virtualState.length !== filteredItems.length) {\n const needleChanged = virtualState.needle !== needle;\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Syncing virtual scroll state with filtered items\n setVirtualState({\n needle,\n length: filteredItems.length,\n mountedIndexes: needleChanged\n ? [] // Reset on needle change\n : filteredItems.length > 0\n ? [...new Set([...virtualState.mountedIndexes, filteredItems.length - 1])] // Add last index\n : virtualState.mountedIndexes,\n });\n }\n }, [\n needle,\n filteredItems.length,\n virtualState.needle,\n virtualState.length,\n virtualState.mountedIndexes,\n ]);\n\n const { mountedIndexes } = virtualState;\n\n const listboxContainerRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n if (listboxContainerRef.current != null) {\n listboxContainerRef.current.style.setProperty(\n '--initial-height',\n `${listboxContainerRef.current.offsetHeight}px`,\n );\n }\n }, []);\n\n useEffect(() => {\n initialRenderRef.current = false;\n }, []);\n\n const showStatus = resultsEmpty;\n const statusId = useId();\n const listboxId = useId();\n\n const getItemNode = (index: number) => {\n const item = filteredItems[index];\n return (\n <SelectInputItemView key={index} item={item} renderValue={renderValue} needle={needle} />\n );\n };\n\n const findMatchingItem = (autocompleteValue: string): T | null => {\n const flatOptions = items\n .flatMap((item) =>\n item.type === 'group' ? item.options : item.type === 'option' ? [item] : [],\n )\n .filter(\n (item): item is SelectInputOptionItem<NonNullable<T>> =>\n item.type === 'option' && item.value != null,\n );\n\n const exactMatch = flatOptions.find(\n (option) =>\n String(option.value) === autocompleteValue ||\n option.filterMatchers?.some((matcher) => matcher === autocompleteValue),\n );\n\n if (exactMatch) {\n return exactMatch.value;\n }\n\n const fuzzyMatch = flatOptions.find((option) =>\n option.filterMatchers?.some((matcher) =>\n matcher.toLowerCase().includes(autocompleteValue.toLowerCase()),\n ),\n );\n\n return fuzzyMatch ? fuzzyMatch.value : null;\n };\n\n return (\n <ListboxOptions\n modal\n as={SelectInputOptionsContainer}\n static\n className=\"np-select-input-options-container\"\n onAriaActiveDescendantChange={(value: React.AriaAttributes['aria-activedescendant']) => {\n if (controllerRef.current != null) {\n if (!initialRenderRef.current && value != null) {\n controllerRef.current.setAttribute('aria-activedescendant', value);\n } else {\n controllerRef.current.removeAttribute('aria-activedescendant');\n }\n }\n }}\n >\n {filterable ? (\n <div className=\"np-select-input-query-container\">\n <SearchInput\n ref={searchInputRef}\n id={id}\n name={name}\n autoComplete={autocomplete}\n role=\"combobox\"\n shape=\"rectangle\"\n placeholder={filterPlaceholder}\n aria-label={filterPlaceholder}\n value={filterQuery}\n aria-autocomplete=\"list\"\n aria-expanded\n aria-controls={listboxId}\n aria-describedby={showStatus ? statusId : undefined}\n onKeyDown={(event: React.KeyboardEvent<HTMLInputElement>) => {\n // Prevent interfering with the matcher of Headless UI\n // https://mathiasbynens.be/notes/javascript-unicode#regex\n if (/^.$/u.test(event.key)) {\n event.stopPropagation();\n }\n }}\n onChange={(event) => {\n // Free up resources and ensure not to go out of bounds when the\n // resulting item count is less than before\n const inputValue = event.currentTarget.value;\n\n // Free up resources and ensure not to go out of bounds\n setVirtualState((prev) => ({ ...prev, mountedIndexes: [] }));\n onFilterChange(inputValue);\n }}\n onInput={(event) => {\n const inputValue = event.currentTarget.value;\n const inputElement = event.currentTarget;\n\n if (autocomplete && onAutocompleteSelect && inputValue) {\n setTimeout(() => {\n if (inputElement.value === inputValue && inputValue.length > 2) {\n const matchedValue = findMatchingItem(inputValue);\n if (matchedValue !== null) {\n onAutocompleteSelect(matchedValue);\n }\n }\n }, 50);\n }\n }}\n />\n </div>\n ) : null}\n\n <section\n ref={listboxContainerRef}\n tabIndex={-1}\n className={clsx(\n 'np-select-input-listbox-container',\n virtualized && 'np-select-input-listbox-container--virtualized',\n needle == null && // Groups aren't shown when filtering\n items.some((item) => item.type === 'group') &&\n 'np-select-input-listbox-container--has-group',\n )}\n data-wds-parent={parentId ?? undefined}\n >\n {resultsEmpty ? (\n <div id={statusId} className=\"np-select-input-options-status\">\n <CrossCircle size={16} className=\"np-select-input-options-status-icon\" />\n {intl.formatMessage(messages.noResultsFound)}\n </div>\n ) : null}\n\n <div\n ref={listboxRef}\n id={listboxId}\n role=\"listbox\"\n aria-orientation=\"vertical\"\n aria-label={listBoxLabel}\n aria-labelledby={listBoxLabelledBy}\n tabIndex={0}\n className=\"np-select-input-listbox\"\n onKeyDownCapture={handleTypeahead}\n >\n {!virtualized ? (\n filteredItems.map((_, index) => getItemNode(index))\n ) : (\n <Virtualizer\n ref={virtualiserHandlerRef}\n data={filteredItems}\n keepMounted={mountedIndexes}\n scrollRef={listboxRef} // `VList` doesn't expose this\n onScroll={async () => {\n if (!virtualiserHandlerRef.current) return;\n\n const startIndex = virtualiserHandlerRef.current.findItemIndex(\n virtualiserHandlerRef.current.scrollOffset,\n );\n const endIndex = virtualiserHandlerRef.current.findItemIndex(\n virtualiserHandlerRef.current.scrollOffset +\n virtualiserHandlerRef.current.viewportSize,\n );\n\n setVirtualState((prev) => {\n // Create an array of all indexes that should be visible\n\n const visibleIndexes = [];\n for (let index = startIndex; index <= endIndex; index += 1) {\n // eslint-disable-next-line functional/immutable-data\n visibleIndexes.push(index);\n }\n\n // Combine with previous indexes and sort\n const newMountedIndexes = [\n ...new Set([...prev.mountedIndexes, ...visibleIndexes]),\n ].sort((a, b) => a - b);\n\n return { ...prev, mountedIndexes: newMountedIndexes };\n });\n }}\n >\n {(item, index) => (\n // The position of each item can't be inferred by browsers when\n // virtualizing, as some of the items may not be in the DOM\n <SelectInputItemsCountContext.Provider value={filteredItems.length}>\n <SelectInputItemPositionContext.Provider value={index + 1}>\n {getItemNode(index)}\n </SelectInputItemPositionContext.Provider>\n </SelectInputItemsCountContext.Provider>\n )}\n </Virtualizer>\n )}\n </div>\n\n {renderFooter != null ? (\n <footer className=\"np-select-input-footer\">\n <div\n role=\"none\"\n onKeyDown={(event) => {\n // Prevent interfering with Headless UI\n if (event.key !== 'Escape') {\n event.stopPropagation();\n }\n }}\n >\n {renderFooter({\n resultsEmpty,\n queryNormalized: needle,\n })}\n </div>\n </footer>\n ) : null}\n </section>\n </ListboxOptions>\n );\n}\n"],"names":["SelectInputOptions","id","parentId","items","compareValues","compareValuesProp","renderValue","String","renderFooter","filterable","filterPlaceholder","sortFilteredOptions","searchInputRef","listboxRef","filterQuery","initialTypeaheadKey","onFilterChange","onInitialTypeaheadHandled","listBoxLabel","listBoxLabelledBy","autocomplete","name","onAutocompleteSelect","intl","useIntl","virtualiserHandlerRef","useRef","controllerRef","initialRenderRef","deferredFilterQuery","useDeferredValue","handleTypeahead","useTypeahead","disabled","onMatch","useEffect","animationFrame","requestAnimationFrame","current","focus","preventScroll","dispatchEvent","KeyboardEvent","key","bubbles","cancelAnimationFrame","needle","useMemo","searchableString","undefined","hasAttribute","a","b","filteredItems","dedupedItems","dedupeSelectInputItems","filtered","map","item","type","selectInputOptionItemIncludesNeedle","value","options","option","sortSelectInputItems","filterSelectInputItems","resultsEmpty","length","virtualized","MAX_ITEMS_WITHOUT_VIRTUALIZATION","virtualState","setVirtualState","useState","mountedIndexes","needleChanged","Set","listboxContainerRef","style","setProperty","offsetHeight","showStatus","statusId","useId","listboxId","getItemNode","index","_jsx","SelectInputItemView","findMatchingItem","autocompleteValue","flatOptions","flatMap","filter","exactMatch","find","filterMatchers","some","matcher","fuzzyMatch","toLowerCase","includes","_jsxs","ListboxOptions","modal","as","SelectInputOptionsContainer","static","className","onAriaActiveDescendantChange","setAttribute","removeAttribute","children","SearchInput","ref","autoComplete","role","shape","placeholder","onKeyDown","event","test","stopPropagation","onChange","inputValue","currentTarget","prev","onInput","inputElement","setTimeout","matchedValue","tabIndex","clsx","CrossCircle","size","formatMessage","messages","noResultsFound","onKeyDownCapture","_","Virtualizer","data","keepMounted","scrollRef","onScroll","startIndex","findItemIndex","scrollOffset","endIndex","viewportSize","visibleIndexes","push","newMountedIndexes","sort","SelectInputItemsCountContext","Provider","SelectInputItemPositionContext","queryNormalized"],"mappings":"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"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { CrossCircle } from '@transferwise/icons';
|
|
2
2
|
import { ListboxOptions } from '@headlessui/react';
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
|
-
import { useRef,
|
|
4
|
+
import { useRef, useDeferredValue, useEffect, useMemo, useState, useId } from 'react';
|
|
5
5
|
import { useIntl } from 'react-intl';
|
|
6
6
|
import { Virtualizer } from 'virtua';
|
|
7
7
|
import { SearchInput } from '../../SearchInput/SearchInput.mjs';
|
|
8
|
+
import { MAX_ITEMS_WITHOUT_VIRTUALIZATION } from '../constants.mjs';
|
|
9
|
+
import { useTypeahead } from '../hooks/useTypeahead.mjs';
|
|
8
10
|
import { SelectInputItemsCountContext, SelectInputItemPositionContext } from '../SelectInput.contexts.mjs';
|
|
9
|
-
import { searchableString, dedupeSelectInputItems, selectInputOptionItemIncludesNeedle, sortSelectInputItems, filterSelectInputItems
|
|
11
|
+
import { searchableString, dedupeSelectInputItems, selectInputOptionItemIncludesNeedle, sortSelectInputItems, filterSelectInputItems } from '../SelectInput.utils.mjs';
|
|
10
12
|
import messages from '../SelectInput.messages.mjs';
|
|
11
13
|
import { SelectInputItemView } from '../ItemView/SelectInputItemView.mjs';
|
|
12
14
|
import '../../../Header/Header.mjs';
|
|
@@ -26,7 +28,9 @@ function SelectInputOptions({
|
|
|
26
28
|
searchInputRef,
|
|
27
29
|
listboxRef,
|
|
28
30
|
filterQuery,
|
|
31
|
+
initialTypeaheadKey,
|
|
29
32
|
onFilterChange,
|
|
33
|
+
onInitialTypeaheadHandled,
|
|
30
34
|
listBoxLabel,
|
|
31
35
|
listBoxLabelledBy,
|
|
32
36
|
autocomplete,
|
|
@@ -37,12 +41,35 @@ function SelectInputOptions({
|
|
|
37
41
|
const virtualiserHandlerRef = useRef(null);
|
|
38
42
|
const controllerRef = filterable ? searchInputRef : listboxRef;
|
|
39
43
|
const initialRenderRef = useRef(true);
|
|
44
|
+
const deferredFilterQuery = useDeferredValue(filterQuery);
|
|
45
|
+
const handleTypeahead = useTypeahead({
|
|
46
|
+
disabled: filterable,
|
|
47
|
+
onMatch: onInitialTypeaheadHandled
|
|
48
|
+
});
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (filterable || initialTypeaheadKey == null) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const animationFrame = requestAnimationFrame(() => {
|
|
54
|
+
if (listboxRef.current == null) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
listboxRef.current.focus({
|
|
58
|
+
preventScroll: true
|
|
59
|
+
});
|
|
60
|
+
listboxRef.current.dispatchEvent(new KeyboardEvent('keydown', {
|
|
61
|
+
key: initialTypeaheadKey,
|
|
62
|
+
bubbles: true
|
|
63
|
+
}));
|
|
64
|
+
});
|
|
65
|
+
return () => cancelAnimationFrame(animationFrame);
|
|
66
|
+
}, [filterable, initialTypeaheadKey, listboxRef]);
|
|
40
67
|
const needle = useMemo(() => {
|
|
41
68
|
if (filterable) {
|
|
42
|
-
return
|
|
69
|
+
return deferredFilterQuery ? searchableString(deferredFilterQuery) : null;
|
|
43
70
|
}
|
|
44
71
|
return undefined;
|
|
45
|
-
}, [
|
|
72
|
+
}, [deferredFilterQuery, filterable]);
|
|
46
73
|
useEffect(() => {
|
|
47
74
|
if (needle) {
|
|
48
75
|
// Ensure having an active option while filtering.
|
|
@@ -100,7 +127,7 @@ function SelectInputOptions({
|
|
|
100
127
|
}
|
|
101
128
|
return item;
|
|
102
129
|
});
|
|
103
|
-
return sortSelectInputItems(filtered, sortFilteredOptions,
|
|
130
|
+
return sortSelectInputItems(filtered, sortFilteredOptions, deferredFilterQuery);
|
|
104
131
|
}
|
|
105
132
|
return filterSelectInputItems(dedupedItems, item => selectInputOptionItemIncludesNeedle(item, needle));
|
|
106
133
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -188,7 +215,7 @@ function SelectInputOptions({
|
|
|
188
215
|
shape: "rectangle",
|
|
189
216
|
placeholder: filterPlaceholder,
|
|
190
217
|
"aria-label": filterPlaceholder,
|
|
191
|
-
|
|
218
|
+
value: filterQuery,
|
|
192
219
|
"aria-autocomplete": "list",
|
|
193
220
|
"aria-expanded": true,
|
|
194
221
|
"aria-controls": listboxId,
|
|
@@ -249,6 +276,7 @@ function SelectInputOptions({
|
|
|
249
276
|
"aria-labelledby": listBoxLabelledBy,
|
|
250
277
|
tabIndex: 0,
|
|
251
278
|
className: "np-select-input-listbox",
|
|
279
|
+
onKeyDownCapture: handleTypeahead,
|
|
252
280
|
children: !virtualized ? filteredItems.map((_, index) => getItemNode(index)) : /*#__PURE__*/jsx(Virtualizer, {
|
|
253
281
|
ref: virtualiserHandlerRef,
|
|
254
282
|
data: filteredItems,
|