@transferwise/components 46.73.0 → 46.74.1
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/common/bottomSheet/BottomSheet.js +3 -1
- package/build/common/bottomSheet/BottomSheet.js.map +1 -1
- package/build/common/bottomSheet/BottomSheet.mjs +3 -1
- package/build/common/bottomSheet/BottomSheet.mjs.map +1 -1
- package/build/common/responsivePanel/ResponsivePanel.js +7 -1
- package/build/common/responsivePanel/ResponsivePanel.js.map +1 -1
- package/build/common/responsivePanel/ResponsivePanel.mjs +7 -1
- package/build/common/responsivePanel/ResponsivePanel.mjs.map +1 -1
- package/build/dimmer/Dimmer.js +3 -1
- package/build/dimmer/Dimmer.js.map +1 -1
- package/build/dimmer/Dimmer.mjs +3 -1
- package/build/dimmer/Dimmer.mjs.map +1 -1
- package/build/drawer/Drawer.js +2 -0
- package/build/drawer/Drawer.js.map +1 -1
- package/build/drawer/Drawer.mjs +2 -0
- package/build/drawer/Drawer.mjs.map +1 -1
- package/build/modal/Modal.js +3 -0
- package/build/modal/Modal.js.map +1 -1
- package/build/modal/Modal.mjs +3 -0
- package/build/modal/Modal.mjs.map +1 -1
- package/build/popover/Popover.js +6 -1
- package/build/popover/Popover.js.map +1 -1
- package/build/popover/Popover.mjs +7 -2
- package/build/popover/Popover.mjs.map +1 -1
- package/build/types/common/bottomSheet/BottomSheet.d.ts +1 -1
- package/build/types/common/bottomSheet/BottomSheet.d.ts.map +1 -1
- package/build/types/common/responsivePanel/ResponsivePanel.d.ts.map +1 -1
- package/build/types/dimmer/Dimmer.d.ts +2 -1
- package/build/types/dimmer/Dimmer.d.ts.map +1 -1
- package/build/types/drawer/Drawer.d.ts +2 -1
- package/build/types/drawer/Drawer.d.ts.map +1 -1
- package/build/types/modal/Modal.d.ts +2 -1
- package/build/types/modal/Modal.d.ts.map +1 -1
- package/build/types/popover/Popover.d.ts +6 -4
- package/build/types/popover/Popover.d.ts.map +1 -1
- package/build/types/uploadInput/UploadInput.d.ts +9 -0
- package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts +16 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItemLink.d.ts.map +1 -1
- package/build/uploadInput/UploadInput.js +71 -66
- package/build/uploadInput/UploadInput.js.map +1 -1
- package/build/uploadInput/UploadInput.mjs +72 -67
- package/build/uploadInput/UploadInput.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.js +13 -4
- package/build/uploadInput/uploadItem/UploadItem.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.mjs +13 -4
- package/build/uploadInput/uploadItem/UploadItem.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.js +1 -0
- package/build/uploadInput/uploadItem/UploadItemLink.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.mjs +1 -0
- package/build/uploadInput/uploadItem/UploadItemLink.mjs.map +1 -1
- package/package.json +3 -3
- package/src/common/bottomSheet/BottomSheet.tsx +4 -2
- package/src/common/responsivePanel/ResponsivePanel.tsx +13 -3
- package/src/dimmer/Dimmer.spec.js +8 -0
- package/src/dimmer/Dimmer.tsx +4 -0
- package/src/drawer/Drawer.spec.js +25 -6
- package/src/drawer/Drawer.tsx +3 -1
- package/src/modal/Modal.spec.js +19 -1
- package/src/modal/Modal.tsx +4 -0
- package/src/popover/Popover.spec.tsx +64 -21
- package/src/popover/Popover.story.tsx +54 -42
- package/src/popover/Popover.tsx +12 -5
- package/src/popover/__snapshots__/Popover.spec.tsx.snap +2 -0
- package/src/uploadInput/UploadInput.spec.tsx +121 -9
- package/src/uploadInput/UploadInput.tests.story.tsx +207 -140
- package/src/uploadInput/UploadInput.tsx +110 -77
- package/src/uploadInput/uploadItem/UploadItem.spec.tsx +1 -0
- package/src/uploadInput/uploadItem/UploadItem.tsx +30 -6
- package/src/uploadInput/uploadItem/UploadItemLink.tsx +9 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UploadItem.mjs","sources":["../../../src/uploadInput/uploadItem/UploadItem.tsx"],"sourcesContent":["import { Bin, CheckCircleFill, CrossCircleFill } from '@transferwise/icons';\nimport { clsx } from 'clsx';\nimport { forwardRef, useImperativeHandle, useRef } from 'react';\nimport { useIntl } from 'react-intl';\n\nimport Body from '../../body';\nimport { Size, Status, Typography, Sentiment } from '../../common';\nimport ProcessIndicator from '../../processIndicator/ProcessIndicator';\nimport StatusIcon from '../../statusIcon/StatusIcon';\nimport { UploadedFile, UploadError } from '../types';\n\nimport MESSAGES from './UploadItem.messages';\nimport { UploadItemLink } from './UploadItemLink';\n\nexport type UploadItemProps = React.JSX.IntrinsicAttributes & {\n file: UploadedFile;\n /**\n * Is this Item part of a multiple- or single-file UploadInput\n */\n singleFileUpload: boolean;\n canDelete: boolean;\n onDelete: () => void;\n\n /**\n * Callback to be called when the file link is clicked.\n * When provided, you need to manually trigger actions to load/download the file.\n *\n * @param file\n */\n onDownload?: (file: UploadedFile) => void;\n ref?: React.Ref<UploadItemRef>;\n};\n\ninterface UploadItemRef {\n focus: () => void;\n}\n\nexport enum TEST_IDS {\n uploadItem = 'uploadItem',\n mediaBody = 'mediaBody',\n}\n\nconst UploadItem = forwardRef<UploadItemRef, UploadItemProps>(\n ({ file, canDelete, onDelete, onDownload, singleFileUpload }, ref) => {\n const { formatMessage } = useIntl();\n const { status, filename, error, errors, url } = file;\n const linkRef = useRef<HTMLAnchorElement>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n\n useImperativeHandle<UploadItemRef, UploadItemRef>(ref, () => ({\n focus: (): void => {\n if (url) {\n linkRef.current?.focus();\n } else {\n buttonRef.current?.focus();\n }\n },\n }));\n\n const isSucceeded = [Status.SUCCEEDED, undefined].includes(status) && !!url;\n\n /**\n * We're temporarily reverting to the regular icon components,\n * until the StatusIcon receives 24px sizing. Some misalignment\n * to be expected.\n */\n const getIcon = () => {\n if (error || errors?.length || status === Status.FAILED) {\n return <CrossCircleFill size={24} className=\"emphasis--negative\" />;\n }\n\n let processIndicator: React.ReactNode;\n\n switch (status) {\n case Status.PROCESSING:\n case Status.PENDING:\n processIndicator = (\n <ProcessIndicator size={Size.EXTRA_SMALL} status={Status.PROCESSING} />\n );\n break;\n case Status.SUCCEEDED:\n case Status.DONE:\n default:\n processIndicator = <CheckCircleFill size={24} className=\"emphasis--positive\" />;\n }\n\n return processIndicator;\n };\n\n const getErrorMessage = (error?: UploadError) =>\n typeof error === 'object' ? error.message : error || formatMessage(MESSAGES.uploadingFailed);\n\n const getMultipleErrors = (errors?: UploadError[]) => {\n if (!errors?.length) {\n return null;\n }\n\n if (errors?.length === 1) {\n return getErrorMessage(errors[0]);\n }\n\n return (\n <ul className=\"np-upload-input-errors m-b-0\">\n {errors.map((error, index) => {\n // eslint-disable-next-line react/no-array-index-key\n return <li key={index}>{getErrorMessage(error)}</li>;\n })}\n </ul>\n );\n };\n\n const getDescription = () => {\n if (error || errors?.length || status === Status.FAILED) {\n return (\n <Body type={Typography.BODY_DEFAULT_BOLD} className=\"np-upload-input__text text-negative\">\n {errors?.length ? getMultipleErrors(errors) : getErrorMessage(error)}\n </Body>\n );\n }\n\n switch (status) {\n case Status.PENDING:\n return (\n <Body type={Typography.BODY_DEFAULT} className=\"np-upload-input__text\">\n {formatMessage(MESSAGES.uploading)}\n </Body>\n );\n case Status.PROCESSING:\n return <Body className=\"np-upload-input__text\">{formatMessage(MESSAGES.deleting)}</Body>;\n case Status.SUCCEEDED:\n case Status.DONE:\n default:\n return (\n <Body type={Typography.BODY_DEFAULT_BOLD} className=\"np-upload-input__text\">\n {formatMessage(MESSAGES.uploaded)}\n </Body>\n );\n }\n };\n\n const getTitle = () => {\n return filename || formatMessage(MESSAGES.uploadedFile);\n };\n\n const onDownloadFile = (event: React.MouseEvent): void => {\n if (onDownload) {\n event.preventDefault();\n onDownload(file);\n }\n };\n\n return (\n <div\n className={clsx('np-upload-input__item', { 'is-interactive': isSucceeded && url })}\n data-testid={TEST_IDS.uploadItem}\n >\n <UploadItemLink\n ref={linkRef}\n url={isSucceeded ? url : undefined}\n singleFileUpload={singleFileUpload}\n onDownload={onDownloadFile}\n >\n <span className=\"np-upload-input__icon\">{getIcon()}</span>\n <div className=\"np-upload-input__item-content\" data-testid={TEST_IDS.mediaBody}>\n <Body type={Typography.BODY_LARGE} className=\"np-upload-input__title text-word-break\">\n {getTitle()}\n </Body>\n {getDescription()}\n </div>\n </UploadItemLink>\n {canDelete && (\n <div className=\"np-upload-input__item-action\">\n <button\n ref={buttonRef}\n aria-label={formatMessage(MESSAGES.removeFile, { filename })}\n className=\"np-upload-input__item-button\"\n type=\"button\"\n onClick={() => onDelete()}\n >\n <Bin size={16} />\n </button>\n </div>\n )}\n </div>\n );\n },\n);\n\nUploadItem.displayName = 'UploadItem';\n\nexport default UploadItem;\n"],"names":["TEST_IDS","UploadItem","forwardRef","file","canDelete","onDelete","onDownload","singleFileUpload","ref","formatMessage","useIntl","status","filename","error","errors","url","linkRef","useRef","buttonRef","useImperativeHandle","focus","current","isSucceeded","Status","SUCCEEDED","undefined","includes","getIcon","length","FAILED","_jsx","CrossCircleFill","size","className","processIndicator","PROCESSING","PENDING","ProcessIndicator","Size","EXTRA_SMALL","DONE","CheckCircleFill","getErrorMessage","message","MESSAGES","uploadingFailed","getMultipleErrors","children","map","index","getDescription","Body","type","Typography","BODY_DEFAULT_BOLD","BODY_DEFAULT","uploading","deleting","uploaded","getTitle","uploadedFile","onDownloadFile","event","preventDefault","_jsxs","clsx","uploadItem","UploadItemLink","mediaBody","BODY_LARGE","removeFile","onClick","Bin","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UploadItem.mjs","sources":["../../../src/uploadInput/uploadItem/UploadItem.tsx"],"sourcesContent":["import { Bin, CheckCircleFill, CrossCircleFill } from '@transferwise/icons';\nimport { clsx } from 'clsx';\nimport { forwardRef, useImperativeHandle, useRef } from 'react';\nimport { useIntl } from 'react-intl';\n\nimport Body from '../../body';\nimport { Size, Status, Typography } from '../../common';\nimport ProcessIndicator from '../../processIndicator/ProcessIndicator';\nimport { UploadedFile, UploadError } from '../types';\n\nimport MESSAGES from './UploadItem.messages';\nimport { UploadItemLink } from './UploadItemLink';\n\nexport type UploadItemProps = React.JSX.IntrinsicAttributes & {\n file: UploadedFile;\n /**\n * Is this Item part of a multiple- or single-file UploadInput\n */\n singleFileUpload: boolean;\n canDelete: boolean;\n onDelete: () => void;\n onFocus: () => void;\n\n /**\n * Callback to be called when the file link is clicked.\n * When provided, you need to manually trigger actions to load/download the file.\n *\n * @param file\n */\n onDownload?: (file: UploadedFile) => void;\n ref?: React.Ref<UploadItemRef>;\n};\ninterface UploadItemRef {\n /**\n * A method to set focus on the upload item.\n * @returns {void}\n */\n focus: () => void;\n\n /**\n * A required unique identifier for the upload item.\n */\n id: string | number;\n\n /**\n * An optional status of the upload item.\n */\n status?: string;\n}\n\nexport enum TEST_IDS {\n uploadItem = 'uploadItem',\n mediaBody = 'mediaBody',\n link = 'link',\n action = 'action',\n}\n\nconst UploadItem = forwardRef<UploadItemRef, UploadItemProps>(\n ({ file, canDelete, onDelete, onDownload, singleFileUpload, onFocus: handleFocus }, ref) => {\n const { formatMessage } = useIntl();\n const { status, filename, error, errors, url } = file;\n const linkRef = useRef<HTMLAnchorElement>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n\n useImperativeHandle<UploadItemRef, UploadItemRef>(ref, () => ({\n focus: (): void => {\n if (url) {\n linkRef.current?.focus();\n } else {\n buttonRef.current?.focus();\n }\n },\n id: file.id,\n status: file.status,\n }));\n\n const isSucceeded = [Status.SUCCEEDED, undefined].includes(status) && !!url;\n\n /**\n * We're temporarily reverting to the regular icon components,\n * until the StatusIcon receives 24px sizing. Some misalignment\n * to be expected.\n */\n const getIcon = () => {\n if (error || errors?.length || status === Status.FAILED) {\n return <CrossCircleFill size={24} className=\"emphasis--negative\" />;\n }\n\n let processIndicator: React.ReactNode;\n\n switch (status) {\n case Status.PROCESSING:\n case Status.PENDING:\n processIndicator = (\n <ProcessIndicator size={Size.EXTRA_SMALL} status={Status.PROCESSING} />\n );\n break;\n case Status.SUCCEEDED:\n case Status.DONE:\n default:\n processIndicator = <CheckCircleFill size={24} className=\"emphasis--positive\" />;\n }\n\n return processIndicator;\n };\n\n const getErrorMessage = (error?: UploadError) =>\n typeof error === 'object' ? error.message : error || formatMessage(MESSAGES.uploadingFailed);\n\n const getMultipleErrors = (errors?: UploadError[]) => {\n if (!errors?.length) {\n return null;\n }\n\n if (errors?.length === 1) {\n return getErrorMessage(errors[0]);\n }\n\n return (\n <ul className=\"np-upload-input-errors m-b-0\">\n {errors.map((error, index) => {\n // eslint-disable-next-line react/no-array-index-key\n return <li key={index}>{getErrorMessage(error)}</li>;\n })}\n </ul>\n );\n };\n\n const getDescription = () => {\n if (error || errors?.length || status === Status.FAILED) {\n return (\n <Body type={Typography.BODY_DEFAULT_BOLD} className=\"np-upload-input__text text-negative\">\n {errors?.length ? getMultipleErrors(errors) : getErrorMessage(error)}\n </Body>\n );\n }\n\n switch (status) {\n case Status.PENDING:\n return (\n <Body type={Typography.BODY_DEFAULT} className=\"np-upload-input__text\">\n {formatMessage(MESSAGES.uploading)}\n </Body>\n );\n case Status.PROCESSING:\n return <Body className=\"np-upload-input__text\">{formatMessage(MESSAGES.deleting)}</Body>;\n case Status.SUCCEEDED:\n case Status.DONE:\n default:\n return (\n <Body type={Typography.BODY_DEFAULT_BOLD} className=\"np-upload-input__text\">\n {formatMessage(MESSAGES.uploaded)}\n </Body>\n );\n }\n };\n\n const getTitle = () => {\n return filename || formatMessage(MESSAGES.uploadedFile);\n };\n\n const onDownloadFile = (event: React.MouseEvent): void => {\n if (onDownload) {\n event.preventDefault();\n onDownload(file);\n }\n };\n\n return (\n <div\n className={clsx('np-upload-input__item', { 'is-interactive': isSucceeded && url })}\n data-testid={`${file.id}-${TEST_IDS.uploadItem}`}\n >\n <UploadItemLink\n ref={linkRef}\n url={isSucceeded ? url : undefined}\n singleFileUpload={singleFileUpload}\n data-testid={`${file.id}-${TEST_IDS.link}`}\n onDownload={onDownloadFile}\n >\n <span className=\"np-upload-input__icon\">{getIcon()}</span>\n <div\n className=\"np-upload-input__item-content\"\n data-testid={`${file.id}-${TEST_IDS.mediaBody}`}\n >\n <Body type={Typography.BODY_LARGE} className=\"np-upload-input__title text-word-break\">\n {getTitle()}\n </Body>\n {getDescription()}\n </div>\n </UploadItemLink>\n {canDelete && (\n <div className=\"np-upload-input__item-action\">\n <button\n ref={buttonRef}\n aria-label={formatMessage(MESSAGES.removeFile, { filename })}\n className=\"np-upload-input__item-button\"\n type=\"button\"\n tabIndex={0}\n data-testid={`${file.id}-${TEST_IDS.action}`}\n onClick={() => onDelete()}\n onFocus={handleFocus}\n >\n <Bin size={16} />\n </button>\n </div>\n )}\n </div>\n );\n },\n);\n\nUploadItem.displayName = 'UploadItem';\n\nexport default UploadItem;\n"],"names":["TEST_IDS","UploadItem","forwardRef","file","canDelete","onDelete","onDownload","singleFileUpload","onFocus","handleFocus","ref","formatMessage","useIntl","status","filename","error","errors","url","linkRef","useRef","buttonRef","useImperativeHandle","focus","current","id","isSucceeded","Status","SUCCEEDED","undefined","includes","getIcon","length","FAILED","_jsx","CrossCircleFill","size","className","processIndicator","PROCESSING","PENDING","ProcessIndicator","Size","EXTRA_SMALL","DONE","CheckCircleFill","getErrorMessage","message","MESSAGES","uploadingFailed","getMultipleErrors","children","map","index","getDescription","Body","type","Typography","BODY_DEFAULT_BOLD","BODY_DEFAULT","uploading","deleting","uploaded","getTitle","uploadedFile","onDownloadFile","event","preventDefault","_jsxs","clsx","uploadItem","UploadItemLink","link","mediaBody","BODY_LARGE","removeFile","tabIndex","action","onClick","Bin","displayName"],"mappings":"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"}
|
|
@@ -23,6 +23,7 @@ const UploadItemLink = /*#__PURE__*/React.forwardRef(({
|
|
|
23
23
|
target: "_blank",
|
|
24
24
|
rel: "noopener noreferrer",
|
|
25
25
|
className: clsx.clsx('np-upload-input__item-link', singleFileUpload ? 'np-upload-input__item-link--single-file' : ''),
|
|
26
|
+
tabIndex: 0,
|
|
26
27
|
onClick: onDownload,
|
|
27
28
|
children: children
|
|
28
29
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UploadItemLink.js","sources":["../../../src/uploadInput/uploadItem/UploadItemLink.tsx"],"sourcesContent":["import { PropsWithChildren, MouseEvent, forwardRef } from 'react';\nimport { clsx } from 'clsx';\n\ntype UploadItemLinkProps = PropsWithChildren<{\n url?: string;\n onDownload?: (event: MouseEvent) => void;\n singleFileUpload: boolean;\n}>;\n\nexport const UploadItemLink = forwardRef<HTMLAnchorElement | HTMLDivElement, UploadItemLinkProps>(\n ({ children, url, onDownload, singleFileUpload }, ref) => {\n if (!url) {\n return <div
|
|
1
|
+
{"version":3,"file":"UploadItemLink.js","sources":["../../../src/uploadInput/uploadItem/UploadItemLink.tsx"],"sourcesContent":["import { PropsWithChildren, MouseEvent, forwardRef } from 'react';\nimport { clsx } from 'clsx';\n\ntype UploadItemLinkProps = PropsWithChildren<{\n url?: string;\n onDownload?: (event: MouseEvent) => void;\n singleFileUpload: boolean;\n}>;\n\nexport const UploadItemLink = forwardRef<HTMLAnchorElement | HTMLDivElement, UploadItemLinkProps>(\n ({ children, url, onDownload, singleFileUpload }, ref) => {\n if (!url) {\n return (\n <div\n ref={ref as React.RefObject<HTMLDivElement>}\n className={clsx('np-upload-input__item-container')}\n >\n {children}\n </div>\n );\n }\n\n return (\n <a\n ref={ref as React.RefObject<HTMLAnchorElement>}\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={clsx(\n 'np-upload-input__item-link',\n singleFileUpload ? 'np-upload-input__item-link--single-file' : '',\n )}\n tabIndex={0}\n onClick={onDownload}\n >\n {children}\n </a>\n );\n },\n);\n"],"names":["UploadItemLink","forwardRef","children","url","onDownload","singleFileUpload","ref","_jsx","className","clsx","href","target","rel","tabIndex","onClick"],"mappings":";;;;;;AASaA,MAAAA,cAAc,gBAAGC,gBAAU,CACtC,CAAC;EAAEC,QAAQ;EAAEC,GAAG;EAAEC,UAAU;AAAEC,EAAAA,gBAAAA;CAAkB,EAAEC,GAAG,KAAI;EACvD,IAAI,CAACH,GAAG,EAAE;AACR,IAAA,oBACEI,cAAA,CAAA,KAAA,EAAA;AACED,MAAAA,GAAG,EAAEA,GAAuC;AAC5CE,MAAAA,SAAS,EAAEC,SAAI,CAAC,iCAAiC,CAAE;AAAAP,MAAAA,QAAA,EAElDA,QAAAA;AAAQ,KACN,CAAC,CAAA;AAEV,GAAA;AAEA,EAAA,oBACEK,cAAA,CAAA,GAAA,EAAA;AACED,IAAAA,GAAG,EAAEA,GAA0C;AAC/CI,IAAAA,IAAI,EAAEP,GAAI;AACVQ,IAAAA,MAAM,EAAC,QAAQ;AACfC,IAAAA,GAAG,EAAC,qBAAqB;IACzBJ,SAAS,EAAEC,SAAI,CACb,4BAA4B,EAC5BJ,gBAAgB,GAAG,yCAAyC,GAAG,EAAE,CACjE;AACFQ,IAAAA,QAAQ,EAAE,CAAE;AACZC,IAAAA,OAAO,EAAEV,UAAW;AAAAF,IAAAA,QAAA,EAEnBA,QAAAA;AAAQ,GACR,CAAC,CAAA;AAER,CAAC;;;;"}
|
|
@@ -21,6 +21,7 @@ const UploadItemLink = /*#__PURE__*/forwardRef(({
|
|
|
21
21
|
target: "_blank",
|
|
22
22
|
rel: "noopener noreferrer",
|
|
23
23
|
className: clsx('np-upload-input__item-link', singleFileUpload ? 'np-upload-input__item-link--single-file' : ''),
|
|
24
|
+
tabIndex: 0,
|
|
24
25
|
onClick: onDownload,
|
|
25
26
|
children: children
|
|
26
27
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UploadItemLink.mjs","sources":["../../../src/uploadInput/uploadItem/UploadItemLink.tsx"],"sourcesContent":["import { PropsWithChildren, MouseEvent, forwardRef } from 'react';\nimport { clsx } from 'clsx';\n\ntype UploadItemLinkProps = PropsWithChildren<{\n url?: string;\n onDownload?: (event: MouseEvent) => void;\n singleFileUpload: boolean;\n}>;\n\nexport const UploadItemLink = forwardRef<HTMLAnchorElement | HTMLDivElement, UploadItemLinkProps>(\n ({ children, url, onDownload, singleFileUpload }, ref) => {\n if (!url) {\n return <div
|
|
1
|
+
{"version":3,"file":"UploadItemLink.mjs","sources":["../../../src/uploadInput/uploadItem/UploadItemLink.tsx"],"sourcesContent":["import { PropsWithChildren, MouseEvent, forwardRef } from 'react';\nimport { clsx } from 'clsx';\n\ntype UploadItemLinkProps = PropsWithChildren<{\n url?: string;\n onDownload?: (event: MouseEvent) => void;\n singleFileUpload: boolean;\n}>;\n\nexport const UploadItemLink = forwardRef<HTMLAnchorElement | HTMLDivElement, UploadItemLinkProps>(\n ({ children, url, onDownload, singleFileUpload }, ref) => {\n if (!url) {\n return (\n <div\n ref={ref as React.RefObject<HTMLDivElement>}\n className={clsx('np-upload-input__item-container')}\n >\n {children}\n </div>\n );\n }\n\n return (\n <a\n ref={ref as React.RefObject<HTMLAnchorElement>}\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={clsx(\n 'np-upload-input__item-link',\n singleFileUpload ? 'np-upload-input__item-link--single-file' : '',\n )}\n tabIndex={0}\n onClick={onDownload}\n >\n {children}\n </a>\n );\n },\n);\n"],"names":["UploadItemLink","forwardRef","children","url","onDownload","singleFileUpload","ref","_jsx","className","clsx","href","target","rel","tabIndex","onClick"],"mappings":";;;;AASaA,MAAAA,cAAc,gBAAGC,UAAU,CACtC,CAAC;EAAEC,QAAQ;EAAEC,GAAG;EAAEC,UAAU;AAAEC,EAAAA,gBAAAA;CAAkB,EAAEC,GAAG,KAAI;EACvD,IAAI,CAACH,GAAG,EAAE;AACR,IAAA,oBACEI,GAAA,CAAA,KAAA,EAAA;AACED,MAAAA,GAAG,EAAEA,GAAuC;AAC5CE,MAAAA,SAAS,EAAEC,IAAI,CAAC,iCAAiC,CAAE;AAAAP,MAAAA,QAAA,EAElDA,QAAAA;AAAQ,KACN,CAAC,CAAA;AAEV,GAAA;AAEA,EAAA,oBACEK,GAAA,CAAA,GAAA,EAAA;AACED,IAAAA,GAAG,EAAEA,GAA0C;AAC/CI,IAAAA,IAAI,EAAEP,GAAI;AACVQ,IAAAA,MAAM,EAAC,QAAQ;AACfC,IAAAA,GAAG,EAAC,qBAAqB;IACzBJ,SAAS,EAAEC,IAAI,CACb,4BAA4B,EAC5BJ,gBAAgB,GAAG,yCAAyC,GAAG,EAAE,CACjE;AACFQ,IAAAA,QAAQ,EAAE,CAAE;AACZC,IAAAA,OAAO,EAAEV,UAAW;AAAAF,IAAAA,QAAA,EAEnBA,QAAAA;AAAQ,GACR,CAAC,CAAA;AAER,CAAC;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "46.
|
|
3
|
+
"version": "46.74.1",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -92,8 +92,8 @@
|
|
|
92
92
|
"rollup-preserve-directives": "^1.1.1",
|
|
93
93
|
"storybook": "^8.2.2",
|
|
94
94
|
"@transferwise/neptune-css": "14.19.1",
|
|
95
|
-
"@
|
|
96
|
-
"@
|
|
95
|
+
"@transferwise/less-config": "3.1.0",
|
|
96
|
+
"@wise/components-theming": "1.6.1"
|
|
97
97
|
},
|
|
98
98
|
"peerDependencies": {
|
|
99
99
|
"@transferwise/icons": "^3.13.1",
|
|
@@ -32,7 +32,7 @@ export type BottomSheetProps = PropsWithChildren<
|
|
|
32
32
|
onClose?: (event: Event | SyntheticEvent) => void;
|
|
33
33
|
open: boolean;
|
|
34
34
|
} & CommonProps &
|
|
35
|
-
Pick<HTMLAttributes<HTMLDivElement>, 'role' | 'aria-labelledby'>
|
|
35
|
+
Pick<HTMLAttributes<HTMLDivElement>, 'role' | 'aria-labelledby' | 'aria-label'>
|
|
36
36
|
>;
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -185,6 +185,7 @@ const BottomSheet = ({ role = 'dialog', ...props }: BottomSheetProps) => {
|
|
|
185
185
|
return is400Zoom ? (
|
|
186
186
|
<Drawer
|
|
187
187
|
aria-labelledby={props['aria-labelledby']}
|
|
188
|
+
aria-label={props['aria-label']}
|
|
188
189
|
role={role}
|
|
189
190
|
open={props.open}
|
|
190
191
|
className={props.className}
|
|
@@ -203,7 +204,8 @@ const BottomSheet = ({ role = 'dialog', ...props }: BottomSheetProps) => {
|
|
|
203
204
|
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}
|
|
204
205
|
<div
|
|
205
206
|
id={overlayId}
|
|
206
|
-
aria-labelledby={props['aria-labelledby']}
|
|
207
|
+
aria-labelledby={props['aria-labelledby'] || undefined}
|
|
208
|
+
aria-label={props['aria-label'] || undefined}
|
|
207
209
|
role={role}
|
|
208
210
|
aria-modal
|
|
209
211
|
onTouchStart={onSwipeStart}
|
|
@@ -3,8 +3,7 @@ import { forwardRef } from 'react';
|
|
|
3
3
|
import { Position } from '..';
|
|
4
4
|
import BottomSheet from '../bottomSheet';
|
|
5
5
|
import { useLayout } from '../hooks';
|
|
6
|
-
import Panel from '../panel';
|
|
7
|
-
import { PanelProps } from '../panel/Panel';
|
|
6
|
+
import Panel, { type PanelProps } from '../panel';
|
|
8
7
|
|
|
9
8
|
const ResponsivePanel = forwardRef<HTMLDivElement, PanelProps>(function ResponsivePanel(
|
|
10
9
|
{
|
|
@@ -17,13 +16,22 @@ const ResponsivePanel = forwardRef<HTMLDivElement, PanelProps>(function Responsi
|
|
|
17
16
|
open = false,
|
|
18
17
|
position = Position.BOTTOM,
|
|
19
18
|
anchorWidth = false,
|
|
19
|
+
'aria-label': ariaLabel,
|
|
20
|
+
'aria-labelledby': ariaLabelledBy,
|
|
20
21
|
}: PanelProps,
|
|
21
22
|
reference,
|
|
22
23
|
) {
|
|
23
24
|
const { isMobile } = useLayout();
|
|
24
25
|
if (isMobile) {
|
|
25
26
|
return (
|
|
26
|
-
<BottomSheet
|
|
27
|
+
<BottomSheet
|
|
28
|
+
key="bottomSheet"
|
|
29
|
+
aria-label={ariaLabel}
|
|
30
|
+
aria-labelledby={ariaLabelledBy}
|
|
31
|
+
open={open}
|
|
32
|
+
className={className}
|
|
33
|
+
onClose={onClose}
|
|
34
|
+
>
|
|
27
35
|
{children}
|
|
28
36
|
</BottomSheet>
|
|
29
37
|
);
|
|
@@ -38,6 +46,8 @@ const ResponsivePanel = forwardRef<HTMLDivElement, PanelProps>(function Responsi
|
|
|
38
46
|
position={position}
|
|
39
47
|
anchorWidth={anchorWidth}
|
|
40
48
|
anchorRef={anchorRef}
|
|
49
|
+
aria-label={ariaLabel}
|
|
50
|
+
aria-labelledby={ariaLabelledBy}
|
|
41
51
|
className={className}
|
|
42
52
|
onClose={onClose}
|
|
43
53
|
>
|
|
@@ -15,6 +15,7 @@ describe('Dimmer', () => {
|
|
|
15
15
|
children: <div />,
|
|
16
16
|
className: undefined,
|
|
17
17
|
onClose: undefined,
|
|
18
|
+
onExited: jest.fn(),
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
beforeEach(() => {
|
|
@@ -76,4 +77,11 @@ describe('Dimmer', () => {
|
|
|
76
77
|
exit: 'dimmer--exit dimmer--exit-fade',
|
|
77
78
|
});
|
|
78
79
|
});
|
|
80
|
+
|
|
81
|
+
it('calls onExited when the exit animation is finished', () => {
|
|
82
|
+
component.setProps({ fadeContentOnExit: true });
|
|
83
|
+
const transition = component.find('CSSTransition');
|
|
84
|
+
transition.prop('onExited')();
|
|
85
|
+
expect(props.onExited).toHaveBeenCalled();
|
|
86
|
+
});
|
|
79
87
|
});
|
package/src/dimmer/Dimmer.tsx
CHANGED
|
@@ -31,6 +31,7 @@ export type DimmerProps = CommonProps & {
|
|
|
31
31
|
scrollable?: boolean;
|
|
32
32
|
transparent?: boolean;
|
|
33
33
|
onClose?: (event: KeyboardEvent | MouseEvent) => void;
|
|
34
|
+
onExited?: () => void;
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
export const handleTouchMove = (event: Event) => {
|
|
@@ -56,6 +57,7 @@ const Dimmer = ({
|
|
|
56
57
|
scrollable = false,
|
|
57
58
|
transparent = false,
|
|
58
59
|
onClose,
|
|
60
|
+
onExited: handleExited,
|
|
59
61
|
}: DimmerProps) => {
|
|
60
62
|
const [hasNotExited, setHasNotExited] = useState(false);
|
|
61
63
|
const dimmerReference = useRef<HTMLDivElement>(null);
|
|
@@ -101,6 +103,8 @@ const Dimmer = ({
|
|
|
101
103
|
if (dimmerReference.current) {
|
|
102
104
|
dimmerManager.remove(dimmerReference.current);
|
|
103
105
|
}
|
|
106
|
+
|
|
107
|
+
handleExited?.();
|
|
104
108
|
};
|
|
105
109
|
|
|
106
110
|
useEffect(() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mount } from 'enzyme';
|
|
2
2
|
|
|
3
3
|
import { mockMatchMedia } from '../test-utils';
|
|
4
4
|
import Title from '../title/Title';
|
|
@@ -12,7 +12,7 @@ jest.useFakeTimers();
|
|
|
12
12
|
jest.mock(
|
|
13
13
|
'../dimmer',
|
|
14
14
|
() =>
|
|
15
|
-
function ({ open, children }) {
|
|
15
|
+
function Dimmer({ open, children }) {
|
|
16
16
|
return open ? <div className="dimmer">{children}</div> : null;
|
|
17
17
|
},
|
|
18
18
|
);
|
|
@@ -20,7 +20,7 @@ jest.mock(
|
|
|
20
20
|
jest.mock(
|
|
21
21
|
'../slidingPanel',
|
|
22
22
|
() =>
|
|
23
|
-
function ({ open, children }) {
|
|
23
|
+
function SlidingPanel({ open, children }) {
|
|
24
24
|
return open ? <div className="sliding-panel">{children}</div> : null;
|
|
25
25
|
},
|
|
26
26
|
);
|
|
@@ -29,10 +29,10 @@ const defaultLocale = 'en-GB';
|
|
|
29
29
|
|
|
30
30
|
jest.mock('react-intl', () => ({
|
|
31
31
|
injectIntl: (Component) =>
|
|
32
|
-
function (props) {
|
|
32
|
+
function InjectedComponent(props) {
|
|
33
33
|
return <Component {...props} intl={{ locale: defaultLocale }} />;
|
|
34
34
|
},
|
|
35
|
-
useIntl: () => ({ locale: defaultLocale, formatMessage: (id) =>
|
|
35
|
+
useIntl: () => ({ locale: defaultLocale, formatMessage: (id) => String(id) }),
|
|
36
36
|
defineMessages: (translations) => translations,
|
|
37
37
|
}));
|
|
38
38
|
|
|
@@ -48,11 +48,12 @@ describe('Drawer', () => {
|
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
beforeEach(() => {
|
|
51
|
-
component =
|
|
51
|
+
component = mount(<Drawer {...props} />);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
afterEach(() => {
|
|
55
55
|
jest.clearAllMocks();
|
|
56
|
+
component.unmount();
|
|
56
57
|
});
|
|
57
58
|
|
|
58
59
|
it('renders drawer header if title is provided', () => {
|
|
@@ -79,4 +80,22 @@ describe('Drawer', () => {
|
|
|
79
80
|
component.setProps({ footerContent: 'SomeContent' });
|
|
80
81
|
expect(component.find('.np-drawer-footer')).toHaveLength(1);
|
|
81
82
|
});
|
|
83
|
+
|
|
84
|
+
it('passes onUnmount to Dimmer onExited prop', () => {
|
|
85
|
+
const onUnmount = jest.fn();
|
|
86
|
+
component.setProps({ onUnmount });
|
|
87
|
+
component.setProps({ open: true });
|
|
88
|
+
expect(component.find('Dimmer').prop('onExited')).toBe(onUnmount);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('calls onUnmount when the component unmounts', () => {
|
|
92
|
+
const onUnmount = jest.fn();
|
|
93
|
+
component.setProps({ onUnmount });
|
|
94
|
+
component.setProps({ open: true });
|
|
95
|
+
expect(onUnmount).not.toHaveBeenCalled();
|
|
96
|
+
jest.runAllTimers();
|
|
97
|
+
component.setProps({ open: false });
|
|
98
|
+
component.find('Dimmer').prop('onExited')();
|
|
99
|
+
expect(onUnmount).toHaveBeenCalledTimes(1);
|
|
100
|
+
});
|
|
82
101
|
});
|
package/src/drawer/Drawer.tsx
CHANGED
|
@@ -24,6 +24,7 @@ export type DrawerProps = {
|
|
|
24
24
|
position?: `${Position.LEFT | Position.RIGHT | Position.BOTTOM}`;
|
|
25
25
|
/** The action to perform on close click. */
|
|
26
26
|
onClose?: (event: KeyboardEvent | React.MouseEvent) => void;
|
|
27
|
+
onUnmount?: () => void;
|
|
27
28
|
} & Pick<HTMLAttributes<HTMLDivElement>, 'role' | 'aria-labelledby'>;
|
|
28
29
|
|
|
29
30
|
export default function Drawer({
|
|
@@ -32,6 +33,7 @@ export default function Drawer({
|
|
|
32
33
|
footerContent,
|
|
33
34
|
headerTitle,
|
|
34
35
|
onClose,
|
|
36
|
+
onUnmount,
|
|
35
37
|
open = false,
|
|
36
38
|
position = 'right',
|
|
37
39
|
role = 'dialog',
|
|
@@ -48,7 +50,7 @@ export default function Drawer({
|
|
|
48
50
|
const overlayId = useContext(OverlayIdContext);
|
|
49
51
|
|
|
50
52
|
return (
|
|
51
|
-
<Dimmer open={open} onClose={onClose}>
|
|
53
|
+
<Dimmer open={open} onClose={onClose} onExited={onUnmount}>
|
|
52
54
|
<SlidingPanel open={open} position={isMobile ? Position.BOTTOM : position}>
|
|
53
55
|
<div
|
|
54
56
|
id={overlayId}
|
package/src/modal/Modal.spec.js
CHANGED
|
@@ -16,7 +16,7 @@ jest.mock('react-intl', () => ({
|
|
|
16
16
|
function (props) {
|
|
17
17
|
return <Component {...props} intl={{ locale: defaultLocale }} />;
|
|
18
18
|
},
|
|
19
|
-
useIntl: () => ({ locale: defaultLocale, formatMessage: (id) =>
|
|
19
|
+
useIntl: () => ({ locale: defaultLocale, formatMessage: (id) => String(id) }),
|
|
20
20
|
defineMessages: (translations) => translations,
|
|
21
21
|
}));
|
|
22
22
|
|
|
@@ -161,6 +161,24 @@ describe('Modal', () => {
|
|
|
161
161
|
expect(onClose).toHaveBeenCalledTimes(1);
|
|
162
162
|
});
|
|
163
163
|
|
|
164
|
+
it('passes onUnmount to Dimmer onExited prop', () => {
|
|
165
|
+
const onUnmount = jest.fn();
|
|
166
|
+
component.setProps({ onUnmount });
|
|
167
|
+
component.setProps({ open: true });
|
|
168
|
+
expect(component.find('Dimmer').prop('onExited')).toBe(onUnmount);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('calls onUnmount when the component unmounts', () => {
|
|
172
|
+
const onUnmount = jest.fn();
|
|
173
|
+
component.setProps({ onUnmount });
|
|
174
|
+
component.setProps({ open: true });
|
|
175
|
+
expect(onUnmount).not.toHaveBeenCalled();
|
|
176
|
+
jest.runAllTimers();
|
|
177
|
+
component.setProps({ open: false });
|
|
178
|
+
component.find('Dimmer').prop('onExited')();
|
|
179
|
+
expect(onUnmount).toHaveBeenCalledTimes(1);
|
|
180
|
+
});
|
|
181
|
+
|
|
164
182
|
const clickCloseButton = () => {
|
|
165
183
|
component.find('.close').simulate('click');
|
|
166
184
|
};
|
package/src/modal/Modal.tsx
CHANGED
|
@@ -32,6 +32,7 @@ export type ModalProps = CommonProps & {
|
|
|
32
32
|
footer?: ReactNode;
|
|
33
33
|
size?: SizeSmall | SizeMedium | SizeLarge | SizeExtraLarge;
|
|
34
34
|
onClose: () => void;
|
|
35
|
+
onUnmount?: () => void;
|
|
35
36
|
open: boolean;
|
|
36
37
|
scroll?: ScrollContent | ScrollViewport;
|
|
37
38
|
position?: PositionTop | PositionCenter;
|
|
@@ -43,6 +44,7 @@ const Modal = ({
|
|
|
43
44
|
body,
|
|
44
45
|
footer = null,
|
|
45
46
|
onClose,
|
|
47
|
+
onUnmount,
|
|
46
48
|
className,
|
|
47
49
|
open,
|
|
48
50
|
size = Size.MEDIUM,
|
|
@@ -71,6 +73,7 @@ const Modal = ({
|
|
|
71
73
|
footerContent={footer}
|
|
72
74
|
position={Position.BOTTOM}
|
|
73
75
|
onClose={onClose}
|
|
76
|
+
onUnmount={onUnmount}
|
|
74
77
|
>
|
|
75
78
|
{body}
|
|
76
79
|
</Drawer>
|
|
@@ -81,6 +84,7 @@ const Modal = ({
|
|
|
81
84
|
contentPosition={position}
|
|
82
85
|
disableClickToClose={disableDimmerClickToClose}
|
|
83
86
|
onClose={onClose}
|
|
87
|
+
onExited={onUnmount}
|
|
84
88
|
>
|
|
85
89
|
<CSSTransition
|
|
86
90
|
nodeRef={contentReference}
|
|
@@ -35,27 +35,70 @@ describe('Popover', () => {
|
|
|
35
35
|
expect(getPanel()).toMatchSnapshot();
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
(
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
38
|
+
describe('title', () => {
|
|
39
|
+
it('renders title', async () => {
|
|
40
|
+
({ container, rerender } = render(
|
|
41
|
+
<Popover {...props}>
|
|
42
|
+
<button type="button">Open</button>
|
|
43
|
+
</Popover>,
|
|
44
|
+
));
|
|
45
|
+
|
|
46
|
+
await userEvent.click(screen.getByText('Open'));
|
|
47
|
+
await waitForPanel();
|
|
48
|
+
|
|
49
|
+
expect(getTitle()).toBeInTheDocument();
|
|
50
|
+
|
|
51
|
+
rerender(
|
|
52
|
+
<Popover {...props} title={undefined}>
|
|
53
|
+
<button type="button">Open</button>
|
|
54
|
+
</Popover>,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
await userEvent.click(screen.getByText('Open'));
|
|
58
|
+
|
|
59
|
+
expect(getTitle()).not.toBeInTheDocument();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should uses `title` as the accessible name', async () => {
|
|
63
|
+
render(
|
|
64
|
+
<Popover {...props}>
|
|
65
|
+
<button type="button">Open</button>
|
|
66
|
+
</Popover>,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
await userEvent.click(screen.getByText('Open'));
|
|
70
|
+
await waitForPanel();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('accessible name', () => {
|
|
74
|
+
const ACCESSIBLE_NAME = 'Accessible name';
|
|
75
|
+
|
|
76
|
+
it('should use `aria-label` as the accessible name', async () => {
|
|
77
|
+
render(
|
|
78
|
+
<Popover {...props} title={undefined} aria-label={ACCESSIBLE_NAME}>
|
|
79
|
+
<button type="button">Open</button>
|
|
80
|
+
</Popover>,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
await userEvent.click(screen.getByText('Open'));
|
|
84
|
+
await waitForPanel();
|
|
85
|
+
|
|
86
|
+
expect(screen.getByRole('dialog', { name: ACCESSIBLE_NAME })).toBeInTheDocument();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should prioritise `aria-label` over `title` as the accessible name', async () => {
|
|
90
|
+
render(
|
|
91
|
+
<Popover {...props} aria-label={ACCESSIBLE_NAME}>
|
|
92
|
+
<button type="button">Open</button>
|
|
93
|
+
</Popover>,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
await userEvent.click(screen.getByText('Open'));
|
|
97
|
+
await waitForPanel();
|
|
98
|
+
|
|
99
|
+
expect(screen.getByRole('dialog', { name: ACCESSIBLE_NAME })).toBeInTheDocument();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
59
102
|
});
|
|
60
103
|
|
|
61
104
|
it('renders Panel onClick', async () => {
|
|
@@ -1,54 +1,66 @@
|
|
|
1
1
|
import { action } from '@storybook/addon-actions';
|
|
2
|
-
import { select } from '@storybook/addon-knobs';
|
|
3
2
|
|
|
4
3
|
import Button from '../button';
|
|
5
4
|
import { Position } from '../common';
|
|
6
5
|
|
|
7
6
|
import Popover from './Popover';
|
|
7
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
8
|
+
|
|
9
|
+
type Story = StoryObj<typeof Popover>;
|
|
10
|
+
|
|
11
|
+
const Content = () => (
|
|
12
|
+
<>
|
|
13
|
+
You’ll get this rate as long as we receive your 10 EUR within the next 51 hours.
|
|
14
|
+
<div>
|
|
15
|
+
<a href="test1">Test 1</a>
|
|
16
|
+
</div>
|
|
17
|
+
<div>
|
|
18
|
+
<a href="test1">Test 2</a>
|
|
19
|
+
</div>
|
|
20
|
+
<div>
|
|
21
|
+
<a href="test1">Test 3</a>
|
|
22
|
+
</div>
|
|
23
|
+
</>
|
|
24
|
+
);
|
|
8
25
|
|
|
9
26
|
export default {
|
|
10
27
|
component: Popover,
|
|
11
28
|
title: 'Dialogs/Popover',
|
|
12
|
-
|
|
29
|
+
tags: ['autodocs'],
|
|
30
|
+
args: {
|
|
31
|
+
preferredPlacement: Position.BOTTOM,
|
|
32
|
+
title: 'Guaranteed rate',
|
|
33
|
+
content: <Content />,
|
|
34
|
+
children: <Button onClick={action(`I'm also triggered`)}>Click here to Open Popover!</Button>,
|
|
35
|
+
},
|
|
36
|
+
argTypes: {
|
|
37
|
+
preferredPlacement: {
|
|
38
|
+
control: 'select',
|
|
39
|
+
options: [Position.TOP, Position.RIGHT, Position.BOTTOM, Position.LEFT],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
} satisfies Meta<typeof Popover>;
|
|
13
43
|
|
|
14
|
-
export const Basic =
|
|
15
|
-
const preferredPlacement = select(
|
|
16
|
-
'preferredPlacement',
|
|
17
|
-
[
|
|
18
|
-
Position.TOP,
|
|
19
|
-
Position.RIGHT,
|
|
20
|
-
Position.BOTTOM,
|
|
21
|
-
Position.LEFT,
|
|
22
|
-
Position.LEFT_TOP,
|
|
23
|
-
Position.RIGHT_TOP,
|
|
24
|
-
Position.BOTTOM_RIGHT,
|
|
25
|
-
Position.BOTTOM_LEFT,
|
|
26
|
-
],
|
|
27
|
-
Position.TOP,
|
|
28
|
-
);
|
|
44
|
+
export const Basic: Story = {};
|
|
29
45
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
</Popover>
|
|
52
|
-
</div>
|
|
53
|
-
);
|
|
54
|
-
};
|
|
46
|
+
/**
|
|
47
|
+
* While it might be easier for sighted users to associate the content
|
|
48
|
+
* of a `Popover` with the surrounding and trigger content, it's likely
|
|
49
|
+
* much harder for people relying on the assistive-tech.
|
|
50
|
+
*
|
|
51
|
+
* For that reason, the `Popover` must always have an accessible name —
|
|
52
|
+
* if `title` prop is set, the component will use it automatically,
|
|
53
|
+
* otherwise `aria-label` must be provided instead.
|
|
54
|
+
*
|
|
55
|
+
* **NB:** If both props are provided, then screen readers will prioritise
|
|
56
|
+
* `aria-label` over `title`.
|
|
57
|
+
*/
|
|
58
|
+
export const WithoutVisibleTitle: Story = {
|
|
59
|
+
args: {
|
|
60
|
+
preferredPlacement: Position.BOTTOM,
|
|
61
|
+
title: undefined,
|
|
62
|
+
'aria-label': 'Guaranteed rate',
|
|
63
|
+
content: <Content />,
|
|
64
|
+
children: <Button onClick={action(`I'm also triggered`)}>Click here to Open Popover!</Button>,
|
|
65
|
+
},
|
|
66
|
+
} satisfies Meta<typeof Popover>;
|