@transferwise/components 46.72.2 → 46.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/alert/Alert.js +12 -3
- package/build/alert/Alert.js.map +1 -1
- package/build/alert/Alert.mjs +12 -3
- package/build/alert/Alert.mjs.map +1 -1
- 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/constants.js +15 -0
- package/build/common/constants.js.map +1 -0
- package/build/common/constants.mjs +13 -0
- package/build/common/constants.mjs.map +1 -0
- 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/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/alert/Alert.d.ts.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/constants.d.ts +11 -0
- package/build/types/common/constants.d.ts.map +1 -0
- package/build/types/common/index.d.ts +2 -0
- package/build/types/common/responsivePanel/ResponsivePanel.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/package.json +1 -1
- package/src/alert/Alert.spec.story.tsx +87 -0
- package/src/alert/Alert.story.tsx +36 -6
- package/src/alert/Alert.tsx +20 -4
- package/src/common/bottomSheet/BottomSheet.tsx +4 -2
- package/src/common/constants.ts +11 -0
- package/src/common/index.js +2 -0
- package/src/common/responsivePanel/ResponsivePanel.tsx +13 -3
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.js","sources":["../../src/popover/Popover.tsx"],"sourcesContent":["import { useTheme } from '@wise/components-theming';\nimport { clsx } from 'clsx';\nimport { useRef, useState, cloneElement, useEffect, isValidElement } from 'react';\n\nimport { Position, Typography } from '../common';\nimport ResponsivePanel from '../common/responsivePanel';\nimport Title from '../title';\nimport { logActionRequired } from '../utilities';\n\n/** @deprecated Use `\"top\" | \"bottom\"` instead. */\ntype PopoverPreferredPlacementDeprecated =\n | `${Position.LEFT_TOP}`\n | `${Position.RIGHT_TOP}`\n | `${Position.BOTTOM_RIGHT}`\n | `${Position.BOTTOM_LEFT}`;\n\nexport type PopoverPreferredPlacement =\n | `${Position.TOP}`\n | `${Position.RIGHT}`\n | `${Position.BOTTOM}`\n | `${Position.LEFT}`\n | PopoverPreferredPlacementDeprecated;\n\nexport interface PopoverProps {\n children?: React.ReactNode;\n
|
|
1
|
+
{"version":3,"file":"Popover.js","sources":["../../src/popover/Popover.tsx"],"sourcesContent":["import { useTheme } from '@wise/components-theming';\nimport { clsx } from 'clsx';\nimport { useRef, useState, cloneElement, useEffect, isValidElement, useId } from 'react';\n\nimport { Position, Typography } from '../common';\nimport ResponsivePanel from '../common/responsivePanel';\nimport Title from '../title';\nimport { logActionRequired } from '../utilities';\n\n/** @deprecated Use `\"top\" | \"bottom\"` instead. */\ntype PopoverPreferredPlacementDeprecated =\n | `${Position.LEFT_TOP}`\n | `${Position.RIGHT_TOP}`\n | `${Position.BOTTOM_RIGHT}`\n | `${Position.BOTTOM_LEFT}`;\n\nexport type PopoverPreferredPlacement =\n | `${Position.TOP}`\n | `${Position.RIGHT}`\n | `${Position.BOTTOM}`\n | `${Position.LEFT}`\n | PopoverPreferredPlacementDeprecated;\n\nexport interface PopoverProps {\n children?: React.ReactNode;\n title?: React.ReactNode;\n /** Screen-reader-friendly title. Must be provided if `title` prop is not set. */\n 'aria-label'?: string;\n preferredPlacement?: PopoverPreferredPlacement;\n content: React.ReactNode;\n onClose?: () => void;\n className?: string;\n}\n\nfunction resolvePlacement(preferredPlacement: PopoverPreferredPlacement) {\n switch (preferredPlacement) {\n case 'left-top':\n case 'right-top':\n return 'top';\n case 'bottom-left':\n case 'bottom-right':\n return 'bottom';\n default:\n return preferredPlacement;\n }\n}\n\nexport default function Popover({\n children,\n className,\n content,\n preferredPlacement = Position.RIGHT,\n title,\n onClose,\n 'aria-label': ariaLabel,\n}: PopoverProps) {\n const titleId = useId();\n\n const resolvedPlacement = resolvePlacement(preferredPlacement);\n useEffect(() => {\n if (resolvedPlacement !== preferredPlacement) {\n logActionRequired(\n `Popover has deprecated ${preferredPlacement} value for the 'preferredPlacement' prop. Please use ${resolvedPlacement} instead.`,\n );\n }\n }, [preferredPlacement, resolvedPlacement]);\n\n const anchorReference = useRef(null);\n const [open, setOpen] = useState(false);\n\n const handleOnClose = () => {\n setOpen(false);\n onClose?.();\n };\n\n return (\n <span className={clsx('np-popover', className)}>\n <span ref={anchorReference} className=\"d-inline-block\">\n {isValidElement<{ onClick?: () => void }>(children)\n ? cloneElement(children, {\n onClick: () => {\n children.props.onClick?.();\n setOpen((prevOpen) => !prevOpen);\n },\n })\n : children}\n </span>\n <ResponsivePanel\n aria-label={ariaLabel}\n aria-labelledby={title && !ariaLabel ? titleId : undefined}\n open={open}\n anchorRef={anchorReference}\n position={resolvedPlacement}\n arrow\n className=\"np-popover__container\"\n onClose={handleOnClose}\n >\n <div className=\"np-popover__content np-text-default-body\">\n {title && (\n <Title type={Typography.TITLE_BODY} id={titleId} className=\"m-b-1\">\n {title}\n </Title>\n )}\n {content}\n </div>\n </ResponsivePanel>\n </span>\n );\n}\n"],"names":["resolvePlacement","preferredPlacement","Popover","children","className","content","Position","RIGHT","title","onClose","ariaLabel","titleId","useId","resolvedPlacement","useEffect","logActionRequired","anchorReference","useRef","open","setOpen","useState","handleOnClose","_jsxs","clsx","_jsx","ref","isValidElement","cloneElement","onClick","props","prevOpen","ResponsivePanel","undefined","anchorRef","position","arrow","Title","type","Typography","TITLE_BODY","id"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
|
-
import { useEffect, useRef, useState, isValidElement, cloneElement } from 'react';
|
|
2
|
+
import { useId, useEffect, useRef, useState, isValidElement, cloneElement } from 'react';
|
|
3
3
|
import Title from '../title/Title.mjs';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
5
|
import { logActionRequired } from '../utilities/logActionRequired.mjs';
|
|
@@ -25,8 +25,10 @@ function Popover({
|
|
|
25
25
|
content,
|
|
26
26
|
preferredPlacement = Position.RIGHT,
|
|
27
27
|
title,
|
|
28
|
-
onClose
|
|
28
|
+
onClose,
|
|
29
|
+
'aria-label': ariaLabel
|
|
29
30
|
}) {
|
|
31
|
+
const titleId = useId();
|
|
30
32
|
const resolvedPlacement = resolvePlacement(preferredPlacement);
|
|
31
33
|
useEffect(() => {
|
|
32
34
|
if (resolvedPlacement !== preferredPlacement) {
|
|
@@ -51,6 +53,8 @@ function Popover({
|
|
|
51
53
|
}
|
|
52
54
|
}) : children
|
|
53
55
|
}), /*#__PURE__*/jsx(ResponsivePanel, {
|
|
56
|
+
"aria-label": ariaLabel,
|
|
57
|
+
"aria-labelledby": title && !ariaLabel ? titleId : undefined,
|
|
54
58
|
open: open,
|
|
55
59
|
anchorRef: anchorReference,
|
|
56
60
|
position: resolvedPlacement,
|
|
@@ -61,6 +65,7 @@ function Popover({
|
|
|
61
65
|
className: "np-popover__content np-text-default-body",
|
|
62
66
|
children: [title && /*#__PURE__*/jsx(Title, {
|
|
63
67
|
type: Typography.TITLE_BODY,
|
|
68
|
+
id: titleId,
|
|
64
69
|
className: "m-b-1",
|
|
65
70
|
children: title
|
|
66
71
|
}), content]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.mjs","sources":["../../src/popover/Popover.tsx"],"sourcesContent":["import { useTheme } from '@wise/components-theming';\nimport { clsx } from 'clsx';\nimport { useRef, useState, cloneElement, useEffect, isValidElement } from 'react';\n\nimport { Position, Typography } from '../common';\nimport ResponsivePanel from '../common/responsivePanel';\nimport Title from '../title';\nimport { logActionRequired } from '../utilities';\n\n/** @deprecated Use `\"top\" | \"bottom\"` instead. */\ntype PopoverPreferredPlacementDeprecated =\n | `${Position.LEFT_TOP}`\n | `${Position.RIGHT_TOP}`\n | `${Position.BOTTOM_RIGHT}`\n | `${Position.BOTTOM_LEFT}`;\n\nexport type PopoverPreferredPlacement =\n | `${Position.TOP}`\n | `${Position.RIGHT}`\n | `${Position.BOTTOM}`\n | `${Position.LEFT}`\n | PopoverPreferredPlacementDeprecated;\n\nexport interface PopoverProps {\n children?: React.ReactNode;\n
|
|
1
|
+
{"version":3,"file":"Popover.mjs","sources":["../../src/popover/Popover.tsx"],"sourcesContent":["import { useTheme } from '@wise/components-theming';\nimport { clsx } from 'clsx';\nimport { useRef, useState, cloneElement, useEffect, isValidElement, useId } from 'react';\n\nimport { Position, Typography } from '../common';\nimport ResponsivePanel from '../common/responsivePanel';\nimport Title from '../title';\nimport { logActionRequired } from '../utilities';\n\n/** @deprecated Use `\"top\" | \"bottom\"` instead. */\ntype PopoverPreferredPlacementDeprecated =\n | `${Position.LEFT_TOP}`\n | `${Position.RIGHT_TOP}`\n | `${Position.BOTTOM_RIGHT}`\n | `${Position.BOTTOM_LEFT}`;\n\nexport type PopoverPreferredPlacement =\n | `${Position.TOP}`\n | `${Position.RIGHT}`\n | `${Position.BOTTOM}`\n | `${Position.LEFT}`\n | PopoverPreferredPlacementDeprecated;\n\nexport interface PopoverProps {\n children?: React.ReactNode;\n title?: React.ReactNode;\n /** Screen-reader-friendly title. Must be provided if `title` prop is not set. */\n 'aria-label'?: string;\n preferredPlacement?: PopoverPreferredPlacement;\n content: React.ReactNode;\n onClose?: () => void;\n className?: string;\n}\n\nfunction resolvePlacement(preferredPlacement: PopoverPreferredPlacement) {\n switch (preferredPlacement) {\n case 'left-top':\n case 'right-top':\n return 'top';\n case 'bottom-left':\n case 'bottom-right':\n return 'bottom';\n default:\n return preferredPlacement;\n }\n}\n\nexport default function Popover({\n children,\n className,\n content,\n preferredPlacement = Position.RIGHT,\n title,\n onClose,\n 'aria-label': ariaLabel,\n}: PopoverProps) {\n const titleId = useId();\n\n const resolvedPlacement = resolvePlacement(preferredPlacement);\n useEffect(() => {\n if (resolvedPlacement !== preferredPlacement) {\n logActionRequired(\n `Popover has deprecated ${preferredPlacement} value for the 'preferredPlacement' prop. Please use ${resolvedPlacement} instead.`,\n );\n }\n }, [preferredPlacement, resolvedPlacement]);\n\n const anchorReference = useRef(null);\n const [open, setOpen] = useState(false);\n\n const handleOnClose = () => {\n setOpen(false);\n onClose?.();\n };\n\n return (\n <span className={clsx('np-popover', className)}>\n <span ref={anchorReference} className=\"d-inline-block\">\n {isValidElement<{ onClick?: () => void }>(children)\n ? cloneElement(children, {\n onClick: () => {\n children.props.onClick?.();\n setOpen((prevOpen) => !prevOpen);\n },\n })\n : children}\n </span>\n <ResponsivePanel\n aria-label={ariaLabel}\n aria-labelledby={title && !ariaLabel ? titleId : undefined}\n open={open}\n anchorRef={anchorReference}\n position={resolvedPlacement}\n arrow\n className=\"np-popover__container\"\n onClose={handleOnClose}\n >\n <div className=\"np-popover__content np-text-default-body\">\n {title && (\n <Title type={Typography.TITLE_BODY} id={titleId} className=\"m-b-1\">\n {title}\n </Title>\n )}\n {content}\n </div>\n </ResponsivePanel>\n </span>\n );\n}\n"],"names":["resolvePlacement","preferredPlacement","Popover","children","className","content","Position","RIGHT","title","onClose","ariaLabel","titleId","useId","resolvedPlacement","useEffect","logActionRequired","anchorReference","useRef","open","setOpen","useState","handleOnClose","_jsxs","clsx","_jsx","ref","isValidElement","cloneElement","onClick","props","prevOpen","ResponsivePanel","undefined","anchorRef","position","arrow","Title","type","Typography","TITLE_BODY","id"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../../../src/alert/Alert.tsx"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../../../src/alert/Alert.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,SAAS,EACT,IAAI,EAEJ,OAAO,EAER,MAAM,WAAW,CAAC;AASnB,MAAM,MAAM,WAAW,GAAG;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,kDAAkD;AAClD,KAAK,mBAAmB,GAAG,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;AACrF,KAAK,iBAAiB,GAAG,GACrB,SAAS,CAAC,QAAQ,GAClB,SAAS,CAAC,OAAO,GACjB,SAAS,CAAC,OAAO,GACjB,SAAS,CAAC,QAAQ,EAAE,CAAC;AACzB,MAAM,MAAM,SAAS,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAEhE,oBAAY,kBAAkB;IAC5B,QAAQ,YAAY;IACpB,GAAG,cAAc;IACjB,SAAS,aAAa;IACtB,WAAW,cAAc;IACzB,MAAM,gBAAgB;IACtB,YAAY,eAAe;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,yIAAyI;IACzI,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kGAAkG;IAClG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IACvD,2DAA2D;IAC3D,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;IACvB,4LAA4L;IAC5L,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,GAAG,kBAAkB,EAAE,CAAC;IAChC,oHAAoH;IACpH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,2CAA2C;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2FAA2F;IAC3F,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC;CAClB;AAeD,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAC5B,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,EACT,WAAW,EACX,IAAI,EACJ,SAAS,EACT,OAAO,EACP,IAAI,EACJ,KAAK,EACL,IAAgB,EAChB,OAAmB,EACnB,MAAa,GACd,EAAE,UAAU,+BAkHZ"}
|
|
@@ -3,7 +3,7 @@ import { CommonProps } from '../commonProps';
|
|
|
3
3
|
export type BottomSheetProps = PropsWithChildren<{
|
|
4
4
|
onClose?: (event: Event | SyntheticEvent) => void;
|
|
5
5
|
open: boolean;
|
|
6
|
-
} & CommonProps & Pick<HTMLAttributes<HTMLDivElement>, 'role' | 'aria-labelledby'>>;
|
|
6
|
+
} & CommonProps & Pick<HTMLAttributes<HTMLDivElement>, 'role' | 'aria-labelledby' | 'aria-label'>>;
|
|
7
7
|
/**
|
|
8
8
|
* Neptune: https://transferwise.github.io/neptune/components/bottom-sheet/
|
|
9
9
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../../../src/common/bottomSheet/BottomSheet.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,cAAc,EACd,iBAAiB,EACjB,cAAc,EAIf,MAAM,OAAO,CAAC;AAOf,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAa7C,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,CAC9C;IACE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc,KAAK,IAAI,CAAC;IAClD,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,WAAW,GACb,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../../../src/common/bottomSheet/BottomSheet.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,cAAc,EACd,iBAAiB,EACjB,cAAc,EAIf,MAAM,OAAO,CAAC;AAOf,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAa7C,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,CAC9C;IACE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc,KAAK,IAAI,CAAC;IAClD,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,WAAW,GACb,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,YAAY,CAAC,CAClF,CAAC;AAEF;;;;;GAKG;AACH,QAAA,MAAM,WAAW,uBAAmC,gBAAgB,gCA6LnE,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file holds repository-wide constants that are reusable by more than 1 component.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* A delay [ms] after which it's OK to update a live region content,
|
|
6
|
+
* taking under consideration delayed programmatic refocusing
|
|
7
|
+
* of triggering components (e.g., SelectInput) and Accessibility
|
|
8
|
+
* Tree updates that prevent the screen reader announcements.
|
|
9
|
+
*/
|
|
10
|
+
export declare const WDS_LIVE_REGION_DELAY_MS = 175;
|
|
11
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/common/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,MAAM,CAAC"}
|
|
@@ -14,6 +14,7 @@ export * from "./locale";
|
|
|
14
14
|
export * from "./commonProps";
|
|
15
15
|
export * from "./initials";
|
|
16
16
|
export * from "./colors";
|
|
17
|
+
export * from "./constants";
|
|
17
18
|
export { Breakpoint } from "./propsValues/breakpoint";
|
|
18
19
|
export { Type } from "./propsValues/type";
|
|
19
20
|
export { DateMode } from "./propsValues/dateMode";
|
|
@@ -23,5 +24,6 @@ export { Sentiment } from "./propsValues/sentiment";
|
|
|
23
24
|
export { Variant } from "./propsValues/variant";
|
|
24
25
|
export { MarkdownNodeType } from "./propsValues/markdownNodeType";
|
|
25
26
|
export { FileType } from "./fileType";
|
|
27
|
+
export { CloseButton } from "./closeButton";
|
|
26
28
|
export { addNoScrollClass, removeNoScrollClass } from "./DOMOperations";
|
|
27
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResponsivePanel.d.ts","sourceRoot":"","sources":["../../../../src/common/responsivePanel/ResponsivePanel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ResponsivePanel.d.ts","sourceRoot":"","sources":["../../../../src/common/responsivePanel/ResponsivePanel.tsx"],"names":[],"mappings":"AAOA,QAAA,MAAM,eAAe;;;;;;;;;;;mGAiDnB,CAAC;AAEH,eAAe,eAAe,CAAC"}
|
|
@@ -4,12 +4,14 @@ type PopoverPreferredPlacementDeprecated = `${Position.LEFT_TOP}` | `${Position.
|
|
|
4
4
|
export type PopoverPreferredPlacement = `${Position.TOP}` | `${Position.RIGHT}` | `${Position.BOTTOM}` | `${Position.LEFT}` | PopoverPreferredPlacementDeprecated;
|
|
5
5
|
export interface PopoverProps {
|
|
6
6
|
children?: React.ReactNode;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
title?: React.ReactNode;
|
|
8
|
+
/** Screen-reader-friendly title. Must be provided if `title` prop is not set. */
|
|
9
|
+
'aria-label'?: string;
|
|
9
10
|
preferredPlacement?: PopoverPreferredPlacement;
|
|
11
|
+
content: React.ReactNode;
|
|
10
12
|
onClose?: () => void;
|
|
11
|
-
|
|
13
|
+
className?: string;
|
|
12
14
|
}
|
|
13
|
-
export default function Popover({ children, className, content, preferredPlacement, title, onClose, }: PopoverProps): import("react").JSX.Element;
|
|
15
|
+
export default function Popover({ children, className, content, preferredPlacement, title, onClose, 'aria-label': ariaLabel, }: PopoverProps): import("react").JSX.Element;
|
|
14
16
|
export {};
|
|
15
17
|
//# sourceMappingURL=Popover.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/popover/Popover.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAc,MAAM,WAAW,CAAC;AAKjD,kDAAkD;AAClD,KAAK,mCAAmC,GACpC,GAAG,QAAQ,CAAC,QAAQ,EAAE,GACtB,GAAG,QAAQ,CAAC,SAAS,EAAE,GACvB,GAAG,QAAQ,CAAC,YAAY,EAAE,GAC1B,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAE9B,MAAM,MAAM,yBAAyB,GACjC,GAAG,QAAQ,CAAC,GAAG,EAAE,GACjB,GAAG,QAAQ,CAAC,KAAK,EAAE,GACnB,GAAG,QAAQ,CAAC,MAAM,EAAE,GACpB,GAAG,QAAQ,CAAC,IAAI,EAAE,GAClB,mCAAmC,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/popover/Popover.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAc,MAAM,WAAW,CAAC;AAKjD,kDAAkD;AAClD,KAAK,mCAAmC,GACpC,GAAG,QAAQ,CAAC,QAAQ,EAAE,GACtB,GAAG,QAAQ,CAAC,SAAS,EAAE,GACvB,GAAG,QAAQ,CAAC,YAAY,EAAE,GAC1B,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAE9B,MAAM,MAAM,yBAAyB,GACjC,GAAG,QAAQ,CAAC,GAAG,EAAE,GACjB,GAAG,QAAQ,CAAC,KAAK,EAAE,GACnB,GAAG,QAAQ,CAAC,MAAM,EAAE,GACpB,GAAG,QAAQ,CAAC,IAAI,EAAE,GAClB,mCAAmC,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;IAC/C,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAeD,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAC9B,QAAQ,EACR,SAAS,EACT,OAAO,EACP,kBAAmC,EACnC,KAAK,EACL,OAAO,EACP,YAAY,EAAE,SAAS,GACxB,EAAE,YAAY,+BAqDd"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { userEvent, within, expect, waitFor } from '@storybook/test';
|
|
3
|
+
import { Button, Field, SelectInput, Sentiment } from '..';
|
|
4
|
+
import Alert from './Alert';
|
|
5
|
+
|
|
6
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Feedback/Alert/tests',
|
|
10
|
+
component: Alert,
|
|
11
|
+
argTypes: {},
|
|
12
|
+
args: {
|
|
13
|
+
type: Sentiment.POSITIVE,
|
|
14
|
+
active: true,
|
|
15
|
+
message: 'Payments sent to your bank details today might not arrive in time for the holidays.',
|
|
16
|
+
},
|
|
17
|
+
} satisfies Meta<typeof Alert>;
|
|
18
|
+
export default meta;
|
|
19
|
+
|
|
20
|
+
type Story = StoryObj<typeof meta>;
|
|
21
|
+
|
|
22
|
+
const wait = async (duration = 500) =>
|
|
23
|
+
new Promise<void>((resolve) => {
|
|
24
|
+
setTimeout(resolve, duration);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const SimpleTrigger: Story = {
|
|
28
|
+
play: async ({ args, canvasElement }) => {
|
|
29
|
+
const canvas = within(canvasElement);
|
|
30
|
+
await wait();
|
|
31
|
+
await userEvent.tab();
|
|
32
|
+
await wait();
|
|
33
|
+
await userEvent.keyboard('{Enter}');
|
|
34
|
+
|
|
35
|
+
await waitFor(async () => expect(canvas.getByText(args.message || '')).toBeInTheDocument());
|
|
36
|
+
},
|
|
37
|
+
render: function Render(args) {
|
|
38
|
+
const [isActive, setIsActive] = useState(false);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<Button htmlType="button" onClick={() => setIsActive(true)}>
|
|
43
|
+
Trigger Alert
|
|
44
|
+
</Button>
|
|
45
|
+
|
|
46
|
+
<Alert {...args} active={isActive} className="m-t-4" />
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const ComplexTrigger: Story = {
|
|
53
|
+
play: async ({ args, canvasElement }) => {
|
|
54
|
+
const canvas = within(canvasElement);
|
|
55
|
+
await wait();
|
|
56
|
+
await userEvent.tab();
|
|
57
|
+
await wait();
|
|
58
|
+
await userEvent.keyboard('{ArrowDown}');
|
|
59
|
+
await wait();
|
|
60
|
+
await userEvent.keyboard('{ArrowDown}');
|
|
61
|
+
await wait();
|
|
62
|
+
await userEvent.keyboard('{Enter}');
|
|
63
|
+
|
|
64
|
+
await waitFor(async () => expect(canvas.getByText(args.message || '')).toBeInTheDocument());
|
|
65
|
+
},
|
|
66
|
+
render: function Render(args) {
|
|
67
|
+
const [isActive, setIsActive] = useState(false);
|
|
68
|
+
const [value, setValue] = useState<string>();
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
<Field label="Select option to triger Alert">
|
|
73
|
+
<SelectInput
|
|
74
|
+
items={[
|
|
75
|
+
{ type: 'option', value: 'one' },
|
|
76
|
+
{ type: 'option', value: 'two' },
|
|
77
|
+
]}
|
|
78
|
+
onChange={setValue}
|
|
79
|
+
onClose={() => setIsActive(Boolean(value))}
|
|
80
|
+
/>
|
|
81
|
+
</Field>
|
|
82
|
+
|
|
83
|
+
<Alert {...args} active={isActive} className="m-t-2" />
|
|
84
|
+
</>
|
|
85
|
+
);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
@@ -4,7 +4,7 @@ import { action } from '@storybook/addon-actions';
|
|
|
4
4
|
import { ClockBorderless } from '@transferwise/icons';
|
|
5
5
|
|
|
6
6
|
import { Sentiment } from '../common';
|
|
7
|
-
import { Button } from '..';
|
|
7
|
+
import { Button, Field, SelectInput } from '..';
|
|
8
8
|
import Alert, { AlertArrowPosition } from './Alert';
|
|
9
9
|
|
|
10
10
|
export default {
|
|
@@ -109,23 +109,41 @@ export const WithTitle: Story = {
|
|
|
109
109
|
* For ARIA live region to function correctly with screen readers,
|
|
110
110
|
* the container with an appropriate ARIA role (in the case of this
|
|
111
111
|
* component, it's `status` or `alert`) must be rendered first.
|
|
112
|
-
* Once present in the accessibility tree, its dynamic contents
|
|
112
|
+
* Once present in the accessibility tree (AT), its dynamic contents
|
|
113
113
|
* will be announced correctly.
|
|
114
114
|
*
|
|
115
115
|
* Because of that, using logical AND (&&) operator is discouraged
|
|
116
116
|
* and, instead, engineers should toggle the `active` prop which
|
|
117
117
|
* provides that logic internally.
|
|
118
|
+
*
|
|
119
|
+
* We're additionally adding a small delay (175ms) between toggling
|
|
120
|
+
* the `active` prop and actual DOM injection to compensate for some
|
|
121
|
+
* common triggers like e.g. `SelectInput`. Those components affect
|
|
122
|
+
* the AT and have programmatic focus control, which prevents the
|
|
123
|
+
* screen readers from announcing simultaneous changes on the page.
|
|
118
124
|
*/
|
|
119
125
|
export const ConditionallyRendered: Story = {
|
|
120
126
|
render: function Render(args) {
|
|
121
127
|
const [isActive, setIsActive] = useState(false);
|
|
128
|
+
const [value, setValue] = useState<string>();
|
|
122
129
|
|
|
123
130
|
return (
|
|
124
131
|
<>
|
|
125
|
-
<Button htmlType="button" onClick={() => setIsActive((
|
|
132
|
+
<Button htmlType="button" onClick={() => setIsActive((current) => !current)}>
|
|
126
133
|
Trigger Alert
|
|
127
134
|
</Button>
|
|
128
135
|
|
|
136
|
+
<Field label="Select `two` to triger Alert" className="m-t-3">
|
|
137
|
+
<SelectInput
|
|
138
|
+
items={[
|
|
139
|
+
{ type: 'option', value: 'one' },
|
|
140
|
+
{ type: 'option', value: 'two' },
|
|
141
|
+
]}
|
|
142
|
+
onChange={setValue}
|
|
143
|
+
onClose={() => setIsActive(value === 'two')}
|
|
144
|
+
/>
|
|
145
|
+
</Field>
|
|
146
|
+
|
|
129
147
|
<Alert {...args} active={isActive} className="m-t-5" />
|
|
130
148
|
</>
|
|
131
149
|
);
|
|
@@ -134,18 +152,30 @@ export const ConditionallyRendered: Story = {
|
|
|
134
152
|
docs: {
|
|
135
153
|
source: {
|
|
136
154
|
code: `
|
|
137
|
-
function Render
|
|
155
|
+
function Render(args) {
|
|
138
156
|
const [isActive, setIsActive] = useState(false);
|
|
157
|
+
const [value, setValue] = useState<string>();
|
|
139
158
|
|
|
140
159
|
return (
|
|
141
160
|
<>
|
|
142
|
-
<Button htmlType="button" onClick={() => setIsActive(
|
|
161
|
+
<Button htmlType="button" onClick={() => setIsActive((current) => !current)}>
|
|
143
162
|
Trigger Alert
|
|
144
163
|
</Button>
|
|
145
164
|
|
|
165
|
+
<Field label="Select 'two' to triger Alert" className="m-t-3">
|
|
166
|
+
<SelectInput
|
|
167
|
+
items={[
|
|
168
|
+
{ type: 'option', value: 'one' },
|
|
169
|
+
{ type: 'option', value: 'two' },
|
|
170
|
+
]}
|
|
171
|
+
onChange={setValue}
|
|
172
|
+
onClose={() => setIsActive(value === 'two')}
|
|
173
|
+
/>
|
|
174
|
+
</Field>
|
|
175
|
+
|
|
146
176
|
<Alert {...args} active={isActive} className="m-t-5" />
|
|
147
177
|
</>
|
|
148
|
-
)
|
|
178
|
+
);
|
|
149
179
|
}`,
|
|
150
180
|
},
|
|
151
181
|
},
|
package/src/alert/Alert.tsx
CHANGED
|
@@ -2,8 +2,15 @@ import { clsx } from 'clsx';
|
|
|
2
2
|
import { useState, useRef, useEffect } from 'react';
|
|
3
3
|
|
|
4
4
|
import Body from '../body/Body';
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
CloseButton,
|
|
7
|
+
Sentiment,
|
|
8
|
+
Size,
|
|
9
|
+
Typography,
|
|
10
|
+
Variant,
|
|
11
|
+
WDS_LIVE_REGION_DELAY_MS,
|
|
12
|
+
} from '../common';
|
|
13
|
+
|
|
7
14
|
import StatusIcon from '../statusIcon';
|
|
8
15
|
import Title from '../title/Title';
|
|
9
16
|
import { logActionRequired } from '../utilities';
|
|
@@ -131,13 +138,22 @@ export default function Alert({
|
|
|
131
138
|
}
|
|
132
139
|
}, [resolvedType, type]);
|
|
133
140
|
|
|
134
|
-
const [shouldFire, setShouldFire] = useState(
|
|
141
|
+
const [shouldFire, setShouldFire] = useState<boolean>();
|
|
142
|
+
|
|
143
|
+
const [shouldShow, setShouldShow] = useState<boolean>();
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (shouldShow === undefined || !active) {
|
|
146
|
+
setShouldShow(active);
|
|
147
|
+
} else {
|
|
148
|
+
setTimeout(() => setShouldShow(active), WDS_LIVE_REGION_DELAY_MS);
|
|
149
|
+
}
|
|
150
|
+
}, [active, shouldShow]);
|
|
135
151
|
|
|
136
152
|
const closeButtonReference = useRef<HTMLButtonElement>(null);
|
|
137
153
|
|
|
138
154
|
return (
|
|
139
155
|
<div role={resolvedType === Sentiment.NEGATIVE ? 'alert' : 'status'}>
|
|
140
|
-
{
|
|
156
|
+
{shouldShow && (
|
|
141
157
|
<div
|
|
142
158
|
className={clsx(
|
|
143
159
|
'alert d-flex',
|
|
@@ -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}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file holds repository-wide constants that are reusable by more than 1 component.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A delay [ms] after which it's OK to update a live region content,
|
|
7
|
+
* taking under consideration delayed programmatic refocusing
|
|
8
|
+
* of triggering components (e.g., SelectInput) and Accessibility
|
|
9
|
+
* Tree updates that prevent the screen reader announcements.
|
|
10
|
+
*/
|
|
11
|
+
export const WDS_LIVE_REGION_DELAY_MS = 175;
|
package/src/common/index.js
CHANGED
|
@@ -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
|
>
|
|
@@ -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 () => {
|