@transferwise/components 0.0.0-experimental-b26a3c1 → 0.0.0-experimental-31fcf10
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/button/Button.js +9 -13
- package/build/button/Button.js.map +1 -1
- package/build/button/Button.mjs +9 -13
- package/build/button/Button.mjs.map +1 -1
- package/build/types/button/Button.d.ts.map +1 -1
- package/build/types/button/Button.types.d.ts +6 -15
- package/build/types/button/Button.types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/button/Button.accessibility.docs.mdx +103 -0
- package/src/button/Button.story.tsx +145 -170
- package/src/button/Button.tsx +9 -16
- package/src/button/Button.types.ts +9 -15
- package/src/button/LegacyButton.story.tsx +7 -2
package/build/button/Button.js
CHANGED
|
@@ -42,11 +42,9 @@ const Button = /*#__PURE__*/React.forwardRef(({
|
|
|
42
42
|
disabled = false,
|
|
43
43
|
priority = 'primary',
|
|
44
44
|
sentiment = 'default',
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
addonStart,
|
|
49
|
-
addonEnd,
|
|
45
|
+
iconStart: IconStart,
|
|
46
|
+
iconEnd: IconEnd,
|
|
47
|
+
avatars,
|
|
50
48
|
// @ts-expect-error NewButtonProps has `type` prop
|
|
51
49
|
type = 'button',
|
|
52
50
|
loading = false,
|
|
@@ -78,19 +76,17 @@ const Button = /*#__PURE__*/React.forwardRef(({
|
|
|
78
76
|
className: "wds-Button-label",
|
|
79
77
|
"aria-hidden": loading,
|
|
80
78
|
children: size === 'lg' ? children : /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
81
|
-
children: [size === 'md' &&
|
|
79
|
+
children: [size === 'md' && avatars && /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
82
80
|
className: "wds-Button-avatars",
|
|
83
81
|
children: /*#__PURE__*/jsxRuntime.jsx(AvatarLayout, {
|
|
84
82
|
orientation: "horizontal",
|
|
85
|
-
avatars:
|
|
83
|
+
avatars: avatars,
|
|
86
84
|
size: 24
|
|
87
85
|
})
|
|
88
|
-
}),
|
|
89
|
-
className: "wds-Button-icon wds-Button-icon--start"
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
className: "wds-Button-icon wds-Button-icon--end",
|
|
93
|
-
children: addonEnd.value
|
|
86
|
+
}), !avatars && IconStart && /*#__PURE__*/jsxRuntime.jsx(IconStart, {
|
|
87
|
+
className: "wds-Button-icon wds-Button-icon--start"
|
|
88
|
+
}), children, IconEnd && /*#__PURE__*/jsxRuntime.jsx(IconEnd, {
|
|
89
|
+
className: "wds-Button-icon wds-Button-icon--end"
|
|
94
90
|
})]
|
|
95
91
|
})
|
|
96
92
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","sources":["../../src/button/Button.tsx"],"sourcesContent":["/* eslint-disable react/display-name */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport {
|
|
1
|
+
{"version":3,"file":"Button.js","sources":["../../src/button/Button.tsx"],"sourcesContent":["/* eslint-disable react/display-name */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport { forwardRef } from 'react';\nimport {\n AnchorElementProps,\n ButtonReferenceType,\n ButtonProps as NewButtonProps,\n} from './Button.types';\nimport { PrimitiveAnchor, PrimitiveButton } from '../primitives';\nimport AvatarLayout from '../avatarLayout';\nimport ProcessIndicator from '../processIndicator';\nimport { clsx } from 'clsx';\nimport { Typography } from '../common';\nimport Body from '../body';\n\nconst Button = forwardRef<ButtonReferenceType, NewButtonProps>(\n (\n {\n as = 'button',\n children,\n className,\n size = 'lg',\n href,\n disabled = false,\n priority = 'primary',\n sentiment = 'default',\n iconStart: IconStart,\n iconEnd: IconEnd,\n avatars,\n // @ts-expect-error NewButtonProps has `type` prop\n type = 'button',\n loading = false,\n block = false,\n v2,\n ...props\n },\n ref,\n ) => {\n const classNames = clsx(\n 'wds-Button',\n {\n [`wds-Button--block`]: block,\n [`wds-Button--disabled`]: disabled,\n [`wds-Button--loading`]: loading,\n },\n `wds-Button--${{ sm: 'small', md: 'medium', lg: 'large' }[size]}`,\n `wds-Button--${priority}`,\n `wds-Button--${sentiment}`,\n className,\n );\n\n const contentClassNames = clsx('wds-Button-content', {\n [`wds-Button-content--loading`]: loading,\n });\n\n const content = (\n <Body\n as=\"span\"\n type={size === 'sm' ? Typography.BODY_DEFAULT_BOLD : Typography.BODY_LARGE_BOLD}\n className={contentClassNames}\n >\n {loading && (\n <ProcessIndicator\n size={size === 'sm' ? 'xxs' : 'xs'}\n className=\"wds-Button-loader\"\n data-testid=\"button-loader-indicator\"\n />\n )}\n <span className=\"wds-Button-label\" aria-hidden={loading}>\n {size === 'lg' ? (\n children\n ) : (\n <>\n {size === 'md' && avatars && (\n <span className=\"wds-Button-avatars\">\n <AvatarLayout orientation=\"horizontal\" avatars={avatars} size={24} />\n </span>\n )}\n {!avatars && IconStart && (\n <IconStart className=\"wds-Button-icon wds-Button-icon--start\" />\n )}\n {children}\n {IconEnd && <IconEnd className=\"wds-Button-icon wds-Button-icon--end\" />}\n </>\n )}\n </span>\n </Body>\n );\n\n if (href || as === 'a') {\n return (\n <PrimitiveAnchor\n ref={ref as React.Ref<HTMLAnchorElement>}\n {...(props as any)}\n href={href}\n className={classNames}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n >\n {content}\n </PrimitiveAnchor>\n );\n }\n\n return (\n <PrimitiveButton\n ref={ref as React.Ref<HTMLButtonElement>}\n {...(props as any)}\n className={classNames}\n disabled={disabled}\n loading={loading}\n type={type}\n >\n {content}\n </PrimitiveButton>\n );\n },\n);\n\nexport default Button;\n"],"names":["Button","forwardRef","as","children","className","size","href","disabled","priority","sentiment","iconStart","IconStart","iconEnd","IconEnd","avatars","type","loading","block","v2","props","ref","classNames","clsx","sm","md","lg","contentClassNames","content","_jsxs","Body","Typography","BODY_DEFAULT_BOLD","BODY_LARGE_BOLD","_jsx","ProcessIndicator","_Fragment","AvatarLayout","orientation","PrimitiveAnchor","undefined","PrimitiveButton"],"mappings":"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"}
|
package/build/button/Button.mjs
CHANGED
|
@@ -40,11 +40,9 @@ const Button = /*#__PURE__*/forwardRef(({
|
|
|
40
40
|
disabled = false,
|
|
41
41
|
priority = 'primary',
|
|
42
42
|
sentiment = 'default',
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
addonStart,
|
|
47
|
-
addonEnd,
|
|
43
|
+
iconStart: IconStart,
|
|
44
|
+
iconEnd: IconEnd,
|
|
45
|
+
avatars,
|
|
48
46
|
// @ts-expect-error NewButtonProps has `type` prop
|
|
49
47
|
type = 'button',
|
|
50
48
|
loading = false,
|
|
@@ -76,19 +74,17 @@ const Button = /*#__PURE__*/forwardRef(({
|
|
|
76
74
|
className: "wds-Button-label",
|
|
77
75
|
"aria-hidden": loading,
|
|
78
76
|
children: size === 'lg' ? children : /*#__PURE__*/jsxs(Fragment, {
|
|
79
|
-
children: [size === 'md' &&
|
|
77
|
+
children: [size === 'md' && avatars && /*#__PURE__*/jsx("span", {
|
|
80
78
|
className: "wds-Button-avatars",
|
|
81
79
|
children: /*#__PURE__*/jsx(AvatarLayout, {
|
|
82
80
|
orientation: "horizontal",
|
|
83
|
-
avatars:
|
|
81
|
+
avatars: avatars,
|
|
84
82
|
size: 24
|
|
85
83
|
})
|
|
86
|
-
}),
|
|
87
|
-
className: "wds-Button-icon wds-Button-icon--start"
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
className: "wds-Button-icon wds-Button-icon--end",
|
|
91
|
-
children: addonEnd.value
|
|
84
|
+
}), !avatars && IconStart && /*#__PURE__*/jsx(IconStart, {
|
|
85
|
+
className: "wds-Button-icon wds-Button-icon--start"
|
|
86
|
+
}), children, IconEnd && /*#__PURE__*/jsx(IconEnd, {
|
|
87
|
+
className: "wds-Button-icon wds-Button-icon--end"
|
|
92
88
|
})]
|
|
93
89
|
})
|
|
94
90
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.mjs","sources":["../../src/button/Button.tsx"],"sourcesContent":["/* eslint-disable react/display-name */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport {
|
|
1
|
+
{"version":3,"file":"Button.mjs","sources":["../../src/button/Button.tsx"],"sourcesContent":["/* eslint-disable react/display-name */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport { forwardRef } from 'react';\nimport {\n AnchorElementProps,\n ButtonReferenceType,\n ButtonProps as NewButtonProps,\n} from './Button.types';\nimport { PrimitiveAnchor, PrimitiveButton } from '../primitives';\nimport AvatarLayout from '../avatarLayout';\nimport ProcessIndicator from '../processIndicator';\nimport { clsx } from 'clsx';\nimport { Typography } from '../common';\nimport Body from '../body';\n\nconst Button = forwardRef<ButtonReferenceType, NewButtonProps>(\n (\n {\n as = 'button',\n children,\n className,\n size = 'lg',\n href,\n disabled = false,\n priority = 'primary',\n sentiment = 'default',\n iconStart: IconStart,\n iconEnd: IconEnd,\n avatars,\n // @ts-expect-error NewButtonProps has `type` prop\n type = 'button',\n loading = false,\n block = false,\n v2,\n ...props\n },\n ref,\n ) => {\n const classNames = clsx(\n 'wds-Button',\n {\n [`wds-Button--block`]: block,\n [`wds-Button--disabled`]: disabled,\n [`wds-Button--loading`]: loading,\n },\n `wds-Button--${{ sm: 'small', md: 'medium', lg: 'large' }[size]}`,\n `wds-Button--${priority}`,\n `wds-Button--${sentiment}`,\n className,\n );\n\n const contentClassNames = clsx('wds-Button-content', {\n [`wds-Button-content--loading`]: loading,\n });\n\n const content = (\n <Body\n as=\"span\"\n type={size === 'sm' ? Typography.BODY_DEFAULT_BOLD : Typography.BODY_LARGE_BOLD}\n className={contentClassNames}\n >\n {loading && (\n <ProcessIndicator\n size={size === 'sm' ? 'xxs' : 'xs'}\n className=\"wds-Button-loader\"\n data-testid=\"button-loader-indicator\"\n />\n )}\n <span className=\"wds-Button-label\" aria-hidden={loading}>\n {size === 'lg' ? (\n children\n ) : (\n <>\n {size === 'md' && avatars && (\n <span className=\"wds-Button-avatars\">\n <AvatarLayout orientation=\"horizontal\" avatars={avatars} size={24} />\n </span>\n )}\n {!avatars && IconStart && (\n <IconStart className=\"wds-Button-icon wds-Button-icon--start\" />\n )}\n {children}\n {IconEnd && <IconEnd className=\"wds-Button-icon wds-Button-icon--end\" />}\n </>\n )}\n </span>\n </Body>\n );\n\n if (href || as === 'a') {\n return (\n <PrimitiveAnchor\n ref={ref as React.Ref<HTMLAnchorElement>}\n {...(props as any)}\n href={href}\n className={classNames}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n >\n {content}\n </PrimitiveAnchor>\n );\n }\n\n return (\n <PrimitiveButton\n ref={ref as React.Ref<HTMLButtonElement>}\n {...(props as any)}\n className={classNames}\n disabled={disabled}\n loading={loading}\n type={type}\n >\n {content}\n </PrimitiveButton>\n );\n },\n);\n\nexport default Button;\n"],"names":["Button","forwardRef","as","children","className","size","href","disabled","priority","sentiment","iconStart","IconStart","iconEnd","IconEnd","avatars","type","loading","block","v2","props","ref","classNames","clsx","sm","md","lg","contentClassNames","content","_jsxs","Body","Typography","BODY_DEFAULT_BOLD","BODY_LARGE_BOLD","_jsx","ProcessIndicator","_Fragment","AvatarLayout","orientation","PrimitiveAnchor","undefined","PrimitiveButton"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/button/Button.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,mBAAmB,EACnB,WAAW,IAAI,cAAc,EAC9B,MAAM,gBAAgB,CAAC;AAQxB,QAAA,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/button/Button.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,mBAAmB,EACnB,WAAW,IAAI,cAAc,EAC9B,MAAM,gBAAgB,CAAC;AAQxB,QAAA,MAAM,MAAM,gHAsGX,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -4,16 +4,6 @@ export type ButtonSentiment = 'default' | 'negative';
|
|
|
4
4
|
export type ButtonPriority = 'primary' | 'secondary' | 'tertiary' | 'minimal';
|
|
5
5
|
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
6
6
|
export type ButtonReferenceType = HTMLButtonElement | HTMLAnchorElement;
|
|
7
|
-
type ButtonAddonIcon = {
|
|
8
|
-
type: 'icon';
|
|
9
|
-
value: ReactNode;
|
|
10
|
-
};
|
|
11
|
-
type ButtonAddonAvatar = {
|
|
12
|
-
type: 'avatar';
|
|
13
|
-
value: AvatarLayoutProps['avatars'];
|
|
14
|
-
};
|
|
15
|
-
type ButtonAddonStart = ButtonAddonIcon | ButtonAddonAvatar;
|
|
16
|
-
type ButtonAddonEnd = ButtonAddonIcon;
|
|
17
7
|
/**
|
|
18
8
|
* Common properties for the Button component.
|
|
19
9
|
*/
|
|
@@ -52,15 +42,16 @@ export interface CommonProps {
|
|
|
52
42
|
* @default default
|
|
53
43
|
*/
|
|
54
44
|
sentiment?: ButtonSentiment;
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
|
|
45
|
+
/** Icon to be displayed on the left side of the button */
|
|
46
|
+
iconStart?: React.ElementType;
|
|
47
|
+
/** Icon to be displayed on the right side of the button */
|
|
48
|
+
iconEnd?: React.ElementType;
|
|
49
|
+
/** Media to be displayed on the left side of the button */
|
|
50
|
+
avatars?: AvatarLayoutProps['avatars'];
|
|
59
51
|
/** Content to be displayed inside the button */
|
|
60
52
|
children?: ReactNode;
|
|
61
53
|
}
|
|
62
54
|
export type ButtonElementProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'disabled' | 'className'> & CommonProps;
|
|
63
55
|
export type AnchorElementProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'type' | 'disabled' | 'href' | 'className'> & CommonProps;
|
|
64
56
|
export type ButtonProps = ButtonElementProps | AnchorElementProps;
|
|
65
|
-
export {};
|
|
66
57
|
//# sourceMappingURL=Button.types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.types.d.ts","sourceRoot":"","sources":["../../../src/button/Button.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"Button.types.d.ts","sourceRoot":"","sources":["../../../src/button/Button.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,UAAU,CAAC;AACrD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAC9E,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC5C,MAAM,MAAM,mBAAmB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,IAAI,CAAC;IAET;;;QAGI;IACJ,EAAE,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC;IAEpB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;QAEI;IACJ,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;SAEK;IACL,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;SAGK;IACL,IAAI,CAAC,EAAE,UAAU,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;IAE1B;;;OAGG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B,0DAA0D;IAC1D,SAAS,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC;IAE9B,2DAA2D;IAC3D,OAAO,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC;IAE5B,2DAA2D;IAC3D,OAAO,CAAC,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAEvC,gDAAgD;IAChD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,oBAAoB,CAAC,iBAAiB,CAAC,EACvC,UAAU,GAAG,WAAW,CACzB,GACC,WAAW,CAAC;AACd,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,oBAAoB,CAAC,iBAAiB,CAAC,EACvC,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,WAAW,CAC3C,GACC,WAAW,CAAC;AAEd,MAAM,MAAM,WAAW,GAAG,kBAAkB,GAAG,kBAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "0.0.0-experimental-
|
|
3
|
+
"version": "0.0.0-experimental-31fcf10",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -92,12 +92,12 @@
|
|
|
92
92
|
"rollup-preserve-directives": "^1.1.1",
|
|
93
93
|
"storybook": "^8.2.2",
|
|
94
94
|
"@transferwise/less-config": "3.1.0",
|
|
95
|
-
"@transferwise/neptune-css": "0.0.0-experimental-
|
|
95
|
+
"@transferwise/neptune-css": "0.0.0-experimental-31fcf10",
|
|
96
96
|
"@wise/components-theming": "1.6.1"
|
|
97
97
|
},
|
|
98
98
|
"peerDependencies": {
|
|
99
99
|
"@transferwise/icons": "^3.13.1",
|
|
100
|
-
"@transferwise/neptune-css": "0.0.0-experimental-
|
|
100
|
+
"@transferwise/neptune-css": "0.0.0-experimental-31fcf10",
|
|
101
101
|
"@wise/art": "^2.16",
|
|
102
102
|
"@wise/components-theming": "^1.0.0",
|
|
103
103
|
"react": ">=18",
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Meta, Canvas, Source } from '@storybook/blocks';
|
|
2
|
+
import { NavigationOption } from '..';
|
|
3
|
+
import { Bulb } from '@transferwise/icons';
|
|
4
|
+
import * as stories from './Button.story';
|
|
5
|
+
|
|
6
|
+
<Meta title="Actions/Button/Accessibility" />
|
|
7
|
+
|
|
8
|
+
# Accessibility
|
|
9
|
+
|
|
10
|
+
Given the `Button` is a widely used and highly sensitive component, there are some instances where care is required to ensure inclusive and accessible experience.
|
|
11
|
+
|
|
12
|
+
<NavigationOption
|
|
13
|
+
media={<Bulb size={24} />}
|
|
14
|
+
title="Design guidance"
|
|
15
|
+
content="Before you start, familiarise yourself with the dedicated accessibility documentation."
|
|
16
|
+
href="https://wise.design/components/button#accessibility"
|
|
17
|
+
/>
|
|
18
|
+
|
|
19
|
+
<br />
|
|
20
|
+
<br />
|
|
21
|
+
|
|
22
|
+
## Anchors
|
|
23
|
+
|
|
24
|
+
While it's technically possible to make the `Button` component render as a link by using `as="a"` on its own, and there are use cases for it, this will not result in a semantic HTML anchor. For that to happen, you should set `href` instead – it will automatically render the component as a semantic anchor.
|
|
25
|
+
|
|
26
|
+
<Source dark code={`
|
|
27
|
+
// ⚠️ use with care
|
|
28
|
+
<Button v2 as="a">Inaccessible anchor</Button>
|
|
29
|
+
|
|
30
|
+
// ✅ semantic link
|
|
31
|
+
|
|
32
|
+
<Button v2 href="https://wise.com">
|
|
33
|
+
Accessible anchor
|
|
34
|
+
</Button>
|
|
35
|
+
<Button v2 href="https://wise.com" as="a">
|
|
36
|
+
Accessible anchor
|
|
37
|
+
</Button>
|
|
38
|
+
`}/>
|
|
39
|
+
|
|
40
|
+
It's also worth noting that HTML links without a valid `href` are not recognised by RTL via `getByRole('link')`.
|
|
41
|
+
|
|
42
|
+
**Additional resources:**
|
|
43
|
+
|
|
44
|
+
1. [Deque: Anchors must only be used as links with valid URLs or URL fragments](https://dequeuniversity.com/rules/axe-devtools/4.2/href-no-hash)
|
|
45
|
+
2. [whatwg HTML standard: 4.6.2 Links created by a and area elements](https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements)
|
|
46
|
+
|
|
47
|
+
<br />
|
|
48
|
+
|
|
49
|
+
## Disabled anchors
|
|
50
|
+
|
|
51
|
+
Technically, there's no such thing as disabled HTML anchor and the `disabled` attribute is not recognised on the `<a />`. While the code shown below works in all major screen readers, should be overall considered a last resort and design teams should be encouraged to use it sporadically and consider alternative flows instead.
|
|
52
|
+
|
|
53
|
+
<Source
|
|
54
|
+
dark
|
|
55
|
+
code={`
|
|
56
|
+
// ⚠️ use with care
|
|
57
|
+
<Button v2 href="https://wise.com" disabled>Emulated disabled anchor</Button>
|
|
58
|
+
`}
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
We're emulating this behaviour by applying a combination of the following:
|
|
62
|
+
|
|
63
|
+
1. removing `href` attribute to strip out the link's semantics.
|
|
64
|
+
2. adding `role="link"` to make it recognisable and discoverable by the assistive tech.
|
|
65
|
+
3. setting `aria-disabled="true"` to inform assistive tech of the component state.
|
|
66
|
+
|
|
67
|
+
**Additional resources:**
|
|
68
|
+
|
|
69
|
+
1. [Scott O'Hara: Disabling a link](https://www.scottohara.me/blog/2021/05/28/disabled-links.html)
|
|
70
|
+
2. [CSS-Tricks: How to Disable Links](https://css-tricks.com/how-to-disable-links/)
|
|
71
|
+
|
|
72
|
+
<br />
|
|
73
|
+
|
|
74
|
+
## Loading state
|
|
75
|
+
|
|
76
|
+
While it might be tempting to use the native, HTML `disabled` attribute for the `loading` state, it would result in a component that is completely invisible to the assistive tech – not focusable and not parsable – entirely inaccessible experience for users relying on such tools.
|
|
77
|
+
|
|
78
|
+
Instead, we're relying on ARIA attributes and roles to ensure the `Button` is focusable, correctly announced as "busy" and offering visual cue different to the disabled state.
|
|
79
|
+
|
|
80
|
+
<Source dark code={`
|
|
81
|
+
// ❌ do not use
|
|
82
|
+
<Button v2 loading disabled>Invisible</Button>
|
|
83
|
+
|
|
84
|
+
// ✅ semantic loading button
|
|
85
|
+
|
|
86
|
+
<Button v2 loading>
|
|
87
|
+
Proper loading state
|
|
88
|
+
</Button>
|
|
89
|
+
`}/>
|
|
90
|
+
|
|
91
|
+
`Button` instances rendered as HTML anchors, follow the strategy described in the [Disabled anchors](#disabled-anchors) section above.
|
|
92
|
+
|
|
93
|
+
<br />
|
|
94
|
+
|
|
95
|
+
## Working with addons (accessories)
|
|
96
|
+
|
|
97
|
+
One of the core requirements of accessible experience is that all users have equal access to the same content, no matter how they interact with our products.
|
|
98
|
+
|
|
99
|
+
This becomes troublesome for more complex instances of the `Button` such as those with contentful icons or avatars, e.g. those referring to particular currencies, people or action types.
|
|
100
|
+
|
|
101
|
+
Exposing separate ARIA labels for such addons would likely become problematic due to syntactic differences between different languages and so instead we recommend using simple `aria-label` attribute to describe given components complete content. Please note, that screen readers will use that text over the visible label
|
|
102
|
+
|
|
103
|
+
<Canvas of={stories.AccessibilityAddons} />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import { fn } from '@storybook/test';
|
|
3
|
-
import { Freeze, ArrowRight, ChevronRight } from '@transferwise/icons';
|
|
3
|
+
import { Freeze, ArrowRight, ArrowLeft, ChevronRight, ChevronLeft } from '@transferwise/icons';
|
|
4
4
|
import { Flag } from '@wise/art';
|
|
5
5
|
import Button from './Button.resolver';
|
|
6
6
|
import type { ButtonProps, ButtonPriority } from './Button.types';
|
|
@@ -39,8 +39,9 @@ const withComponentGrid =
|
|
|
39
39
|
*/
|
|
40
40
|
const hideControls = (args: string[]) => {
|
|
41
41
|
const hidden = [
|
|
42
|
-
'
|
|
43
|
-
'
|
|
42
|
+
'avatars',
|
|
43
|
+
'iconStart',
|
|
44
|
+
'iconEnd',
|
|
44
45
|
'onClick',
|
|
45
46
|
'onBlur',
|
|
46
47
|
'onFocus',
|
|
@@ -53,88 +54,84 @@ const hideControls = (args: string[]) => {
|
|
|
53
54
|
return Object.fromEntries(hidden.map((item) => [item, { table: { disable: true } }]));
|
|
54
55
|
};
|
|
55
56
|
|
|
57
|
+
/**
|
|
58
|
+
* SB code generation is often not ideal, rendering confusing source.
|
|
59
|
+
* This helper makes icon values more understandable for the stories below.
|
|
60
|
+
*/
|
|
61
|
+
const augmentIconProps = ({ start = 'Freeze', end = 'ArrowRight' } = {}) => ({
|
|
62
|
+
docs: {
|
|
63
|
+
source: {
|
|
64
|
+
transform(value: string): string {
|
|
65
|
+
return value
|
|
66
|
+
.replace(/iconStart=.*?\}+/g, `iconStart={${start}}`)
|
|
67
|
+
.replace(/iconEnd=.*?\}+/g, `iconEnd={${end}}`);
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
56
73
|
/**
|
|
57
74
|
* Convenience controls for previewing rich markup,
|
|
58
75
|
* not otherwise possible via Storybook
|
|
59
76
|
*/
|
|
60
77
|
type PreviewStoryArgs = Parameters<typeof Button>[0] & {
|
|
61
|
-
|
|
62
|
-
|
|
78
|
+
previewAvatars: boolean | ButtonProps['avatars'];
|
|
79
|
+
previewIconStart: boolean | ButtonProps['iconStart'];
|
|
80
|
+
previewIconEnd: boolean | ButtonProps['iconEnd'];
|
|
63
81
|
};
|
|
64
82
|
const previewArgTypes = {
|
|
65
|
-
|
|
66
|
-
control: '
|
|
67
|
-
|
|
68
|
-
'undefined',
|
|
69
|
-
'icon',
|
|
70
|
-
'avatar: flag',
|
|
71
|
-
'avatar: initials',
|
|
72
|
-
'avatar: icon',
|
|
73
|
-
'avatar: image',
|
|
74
|
-
'avatar: double',
|
|
75
|
-
],
|
|
76
|
-
name: 'Preview with `addonStart`',
|
|
83
|
+
previewIconStart: {
|
|
84
|
+
control: 'boolean',
|
|
85
|
+
name: 'Show with `iconStart`',
|
|
77
86
|
mapping: {
|
|
78
|
-
|
|
79
|
-
icon: {
|
|
80
|
-
type: 'icon',
|
|
81
|
-
value: <Freeze />,
|
|
82
|
-
},
|
|
83
|
-
'avatar: flag': {
|
|
84
|
-
type: 'avatar',
|
|
85
|
-
value: [{ asset: <Flag code="pl" /> }],
|
|
86
|
-
},
|
|
87
|
-
'avatar: initials': {
|
|
88
|
-
type: 'avatar',
|
|
89
|
-
value: [{ profileName: 'Jay Jay' }],
|
|
90
|
-
},
|
|
91
|
-
'avatar: icon': {
|
|
92
|
-
type: 'avatar',
|
|
93
|
-
value: [{ asset: <Freeze /> }],
|
|
94
|
-
},
|
|
95
|
-
'avatar: image': {
|
|
96
|
-
type: 'avatar',
|
|
97
|
-
value: [{ imgSrc: '../avatar-square-dude.webp' }],
|
|
98
|
-
},
|
|
99
|
-
'avatar: double': {
|
|
100
|
-
type: 'avatar',
|
|
101
|
-
value: [{ asset: <Flag code="gb" /> }, { imgSrc: '../avatar-square-dude.webp' }],
|
|
102
|
-
},
|
|
87
|
+
true: Freeze,
|
|
103
88
|
},
|
|
104
89
|
table: {
|
|
105
90
|
category: 'Preview options',
|
|
106
|
-
type: {
|
|
107
|
-
summary: undefined,
|
|
108
|
-
},
|
|
109
91
|
},
|
|
110
92
|
},
|
|
111
|
-
|
|
93
|
+
previewIconEnd: {
|
|
112
94
|
control: 'boolean',
|
|
113
|
-
name: '
|
|
95
|
+
name: 'Show with `iconEnd`',
|
|
114
96
|
mapping: {
|
|
115
|
-
true:
|
|
97
|
+
true: ArrowRight,
|
|
98
|
+
},
|
|
99
|
+
table: {
|
|
100
|
+
category: 'Preview options',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
previewAvatars: {
|
|
104
|
+
control: 'select',
|
|
105
|
+
options: ['undefined', 'flag', 'initials', 'icon', 'image', 'double'],
|
|
106
|
+
name: 'Show with Avatar',
|
|
107
|
+
mapping: {
|
|
108
|
+
undefined,
|
|
109
|
+
flag: [{ asset: <Flag code="pl" /> }],
|
|
110
|
+
initials: [{ profileName: 'Jay Jay' }],
|
|
111
|
+
icon: [{ asset: <Freeze /> }],
|
|
112
|
+
image: [{ imgSrc: '../avatar-square-dude.webp' }],
|
|
113
|
+
double: [{ asset: <Flag code="gb" /> }, { imgSrc: '../avatar-square-dude.webp' }],
|
|
116
114
|
},
|
|
117
115
|
table: {
|
|
118
116
|
category: 'Preview options',
|
|
119
|
-
type: {
|
|
120
|
-
summary: undefined,
|
|
121
|
-
},
|
|
122
117
|
},
|
|
123
118
|
},
|
|
124
119
|
} as const;
|
|
125
120
|
|
|
126
121
|
const getPropsForPreview = (args: PreviewStoryArgs) => {
|
|
127
|
-
const {
|
|
128
|
-
|
|
129
|
-
|
|
122
|
+
const { previewAvatars, previewIconStart, previewIconEnd, ...props } = args as {
|
|
123
|
+
previewAvatars: ButtonProps['avatars'];
|
|
124
|
+
previewIconStart: ButtonProps['iconStart'];
|
|
125
|
+
previewIconEnd: ButtonProps['iconEnd'];
|
|
130
126
|
props: typeof Button;
|
|
131
127
|
};
|
|
132
128
|
|
|
133
129
|
return [
|
|
134
130
|
props,
|
|
135
131
|
{
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
avatars: previewAvatars,
|
|
133
|
+
iconStart: previewIconStart,
|
|
134
|
+
iconEnd: previewIconEnd,
|
|
138
135
|
},
|
|
139
136
|
];
|
|
140
137
|
};
|
|
@@ -209,10 +206,13 @@ const meta: Meta<typeof Button> = {
|
|
|
209
206
|
},
|
|
210
207
|
description: 'If set, the component will render as an HTML anchor.',
|
|
211
208
|
},
|
|
212
|
-
|
|
209
|
+
iconStart: {
|
|
210
|
+
control: 'object',
|
|
211
|
+
},
|
|
212
|
+
iconEnd: {
|
|
213
213
|
control: 'object',
|
|
214
214
|
},
|
|
215
|
-
|
|
215
|
+
avatars: {
|
|
216
216
|
control: 'object',
|
|
217
217
|
},
|
|
218
218
|
type: {
|
|
@@ -237,8 +237,9 @@ const meta: Meta<typeof Button> = {
|
|
|
237
237
|
href: undefined,
|
|
238
238
|
as: undefined,
|
|
239
239
|
type: undefined,
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
iconStart: undefined,
|
|
241
|
+
iconEnd: undefined,
|
|
242
|
+
avatars: undefined,
|
|
242
243
|
className: undefined,
|
|
243
244
|
onClick: fn(),
|
|
244
245
|
children: 'Button text',
|
|
@@ -263,8 +264,9 @@ export const Playground: StoryObj<PreviewStoryArgs> = {
|
|
|
263
264
|
onKeyDown: fn(),
|
|
264
265
|
onMouseEnter: fn(),
|
|
265
266
|
onMouseLeave: fn(),
|
|
266
|
-
|
|
267
|
-
|
|
267
|
+
previewIconStart: false,
|
|
268
|
+
previewIconEnd: false,
|
|
269
|
+
previewAvatars: false,
|
|
268
270
|
},
|
|
269
271
|
argTypes: {
|
|
270
272
|
onClick: { table: { disable: true } },
|
|
@@ -309,10 +311,12 @@ export const Sentiment: StoryObj<PreviewStoryArgs> = {
|
|
|
309
311
|
...previewArgTypes,
|
|
310
312
|
},
|
|
311
313
|
args: {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
+
previewIconStart: false,
|
|
315
|
+
previewIconEnd: false,
|
|
316
|
+
previewAvatars: false,
|
|
314
317
|
},
|
|
315
318
|
decorators: [withComponentGrid('30rem')],
|
|
319
|
+
parameters: augmentIconProps(),
|
|
316
320
|
};
|
|
317
321
|
|
|
318
322
|
/**
|
|
@@ -346,8 +350,9 @@ export const Priority: StoryObj<PreviewStoryArgs> = {
|
|
|
346
350
|
...previewArgTypes,
|
|
347
351
|
},
|
|
348
352
|
args: {
|
|
349
|
-
|
|
350
|
-
|
|
353
|
+
previewIconStart: false,
|
|
354
|
+
previewIconEnd: false,
|
|
355
|
+
previewAvatars: false,
|
|
351
356
|
},
|
|
352
357
|
decorators: [withComponentGrid()],
|
|
353
358
|
};
|
|
@@ -379,8 +384,9 @@ export const Size: StoryObj<PreviewStoryArgs> = {
|
|
|
379
384
|
...previewArgTypes,
|
|
380
385
|
},
|
|
381
386
|
args: {
|
|
382
|
-
|
|
383
|
-
|
|
387
|
+
previewIconStart: false,
|
|
388
|
+
previewIconEnd: false,
|
|
389
|
+
previewAvatars: false,
|
|
384
390
|
},
|
|
385
391
|
decorators: [withComponentGrid()],
|
|
386
392
|
};
|
|
@@ -405,8 +411,9 @@ export const AsAnchor: StoryObj<PreviewStoryArgs> = {
|
|
|
405
411
|
args: {
|
|
406
412
|
as: 'a',
|
|
407
413
|
href: 'https://wise.com',
|
|
408
|
-
|
|
409
|
-
|
|
414
|
+
previewIconStart: false,
|
|
415
|
+
previewIconEnd: false,
|
|
416
|
+
previewAvatars: false,
|
|
410
417
|
onClick: undefined,
|
|
411
418
|
},
|
|
412
419
|
};
|
|
@@ -427,8 +434,9 @@ export const Disabled: StoryObj<PreviewStoryArgs> = {
|
|
|
427
434
|
},
|
|
428
435
|
args: {
|
|
429
436
|
disabled: true,
|
|
430
|
-
|
|
431
|
-
|
|
437
|
+
previewIconStart: false,
|
|
438
|
+
previewIconEnd: false,
|
|
439
|
+
previewAvatars: false,
|
|
432
440
|
},
|
|
433
441
|
};
|
|
434
442
|
|
|
@@ -448,8 +456,9 @@ export const Loading: StoryObj<PreviewStoryArgs> = {
|
|
|
448
456
|
},
|
|
449
457
|
args: {
|
|
450
458
|
loading: true,
|
|
451
|
-
|
|
452
|
-
|
|
459
|
+
previewIconStart: false,
|
|
460
|
+
previewIconEnd: false,
|
|
461
|
+
previewAvatars: false,
|
|
453
462
|
},
|
|
454
463
|
};
|
|
455
464
|
|
|
@@ -472,8 +481,9 @@ export const DisplayBlock: StoryObj<PreviewStoryArgs> = {
|
|
|
472
481
|
},
|
|
473
482
|
args: {
|
|
474
483
|
block: true,
|
|
475
|
-
|
|
476
|
-
|
|
484
|
+
previewIconStart: false,
|
|
485
|
+
previewIconEnd: false,
|
|
486
|
+
previewAvatars: false,
|
|
477
487
|
},
|
|
478
488
|
};
|
|
479
489
|
|
|
@@ -487,20 +497,15 @@ export const WithIcons: StoryObj<PreviewStoryArgs> = {
|
|
|
487
497
|
|
|
488
498
|
return (
|
|
489
499
|
<>
|
|
490
|
-
<Button {...props}
|
|
500
|
+
<Button {...props} iconStart={Freeze}>
|
|
491
501
|
With start icon
|
|
492
502
|
</Button>
|
|
493
503
|
|
|
494
|
-
<Button {...props}
|
|
504
|
+
<Button {...props} iconEnd={ArrowRight}>
|
|
495
505
|
With end icon
|
|
496
506
|
</Button>
|
|
497
507
|
|
|
498
|
-
<Button
|
|
499
|
-
{...props}
|
|
500
|
-
v2
|
|
501
|
-
addonStart={{ type: 'icon', value: <Freeze /> }}
|
|
502
|
-
addonEnd={{ type: 'icon', value: <ArrowRight /> }}
|
|
503
|
-
>
|
|
508
|
+
<Button {...props} iconStart={Freeze} iconEnd={ArrowRight}>
|
|
504
509
|
With both icons
|
|
505
510
|
</Button>
|
|
506
511
|
</>
|
|
@@ -512,27 +517,7 @@ export const WithIcons: StoryObj<PreviewStoryArgs> = {
|
|
|
512
517
|
args: {
|
|
513
518
|
size: 'md',
|
|
514
519
|
},
|
|
515
|
-
parameters:
|
|
516
|
-
docs: {
|
|
517
|
-
source: {
|
|
518
|
-
code: `
|
|
519
|
-
<>
|
|
520
|
-
<Button v2 size="md" addonStart={{ type: 'icon', value: <Freeze /> }}>
|
|
521
|
-
With start icon
|
|
522
|
-
</Button>
|
|
523
|
-
|
|
524
|
-
<Button v2 size="md" addonEnd={{ type: 'icon', value: <ArrowRight /> }}>
|
|
525
|
-
With end icon
|
|
526
|
-
</Button>
|
|
527
|
-
|
|
528
|
-
<Button v2 size="md" addonStart={{ type: 'icon', value: <Freeze /> }} addonEnd={{ type: 'icon', value: <ArrowRight /> }}>
|
|
529
|
-
With both icons
|
|
530
|
-
</Button>
|
|
531
|
-
</>
|
|
532
|
-
`,
|
|
533
|
-
},
|
|
534
|
-
},
|
|
535
|
-
},
|
|
520
|
+
parameters: augmentIconProps(),
|
|
536
521
|
decorators: [withComponentGrid()],
|
|
537
522
|
};
|
|
538
523
|
|
|
@@ -546,30 +531,19 @@ export const WithAvatars: StoryObj<PreviewStoryArgs> = {
|
|
|
546
531
|
|
|
547
532
|
return (
|
|
548
533
|
<>
|
|
549
|
-
<Button {...props}
|
|
534
|
+
<Button {...props} avatars={[{ asset: <Freeze /> }]}>
|
|
550
535
|
With single avatar
|
|
551
536
|
</Button>
|
|
552
537
|
|
|
553
|
-
<Button
|
|
554
|
-
{...props}
|
|
555
|
-
v2
|
|
556
|
-
addonStart={{
|
|
557
|
-
type: 'avatar',
|
|
558
|
-
value: [{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }],
|
|
559
|
-
}}
|
|
560
|
-
>
|
|
538
|
+
<Button {...props} avatars={[{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }]}>
|
|
561
539
|
With double avatar
|
|
562
540
|
</Button>
|
|
563
541
|
|
|
564
|
-
<Button {...props}
|
|
542
|
+
<Button {...props} avatars={[{ profileName: 'John Doe' }]}>
|
|
565
543
|
With initials
|
|
566
544
|
</Button>
|
|
567
545
|
|
|
568
|
-
<Button
|
|
569
|
-
{...props}
|
|
570
|
-
v2
|
|
571
|
-
addonStart={{ type: 'avatar', value: [{ imgSrc: '../avatar-square-dude.webp' }] }}
|
|
572
|
-
>
|
|
546
|
+
<Button {...props} avatars={[{ imgSrc: '../avatar-square-dude.webp' }]}>
|
|
573
547
|
With an image
|
|
574
548
|
</Button>
|
|
575
549
|
</>
|
|
@@ -578,53 +552,26 @@ export const WithAvatars: StoryObj<PreviewStoryArgs> = {
|
|
|
578
552
|
argTypes: hideControls(['href', 'target', 'priority', 'sentiment', 'as', 'disabled', 'children']),
|
|
579
553
|
args: {
|
|
580
554
|
size: 'md',
|
|
555
|
+
avatars: [],
|
|
581
556
|
},
|
|
582
557
|
parameters: {
|
|
583
558
|
docs: {
|
|
584
559
|
source: {
|
|
585
560
|
code: `
|
|
586
561
|
<>
|
|
587
|
-
<Button
|
|
588
|
-
v2
|
|
589
|
-
size="md"
|
|
590
|
-
addonStart={{
|
|
591
|
-
type: 'avatar',
|
|
592
|
-
value: [{ asset: <Freeze /> }]
|
|
593
|
-
}}
|
|
594
|
-
>
|
|
562
|
+
<Button v2 size="md" avatars={[{ asset: <Freeze /> }]}>
|
|
595
563
|
With single avatar
|
|
596
564
|
</Button>
|
|
597
|
-
|
|
598
|
-
<Button
|
|
599
|
-
v2
|
|
600
|
-
size="md"
|
|
601
|
-
addonStart={{
|
|
602
|
-
type: 'avatar',
|
|
603
|
-
value: [{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }]
|
|
604
|
-
}}
|
|
605
|
-
>
|
|
565
|
+
|
|
566
|
+
<Button v2 size="md" avatars={[{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }]}>
|
|
606
567
|
With double avatar
|
|
607
568
|
</Button>
|
|
608
|
-
|
|
609
|
-
<Button
|
|
610
|
-
v2
|
|
611
|
-
size="md"
|
|
612
|
-
addonStart={{
|
|
613
|
-
type: 'avatar',
|
|
614
|
-
value: [{ profileName: 'John Doe' }]
|
|
615
|
-
}}
|
|
616
|
-
>
|
|
569
|
+
|
|
570
|
+
<Button v2 size="md" avatars={[{ profileName: 'John Doe' }]}>
|
|
617
571
|
With initials
|
|
618
572
|
</Button>
|
|
619
|
-
|
|
620
|
-
<Button
|
|
621
|
-
v2
|
|
622
|
-
size="md"
|
|
623
|
-
addonStart={{
|
|
624
|
-
type: 'avatar',
|
|
625
|
-
value: [{ imgSrc: '../avatar-square-dude.webp' }]
|
|
626
|
-
}}
|
|
627
|
-
>
|
|
573
|
+
|
|
574
|
+
<Button v2 size="md" avatars={[{ imgSrc: '../avatar-square-dude.webp' }]}>
|
|
628
575
|
With image Avatar
|
|
629
576
|
</Button>
|
|
630
577
|
</>
|
|
@@ -635,6 +582,20 @@ export const WithAvatars: StoryObj<PreviewStoryArgs> = {
|
|
|
635
582
|
decorators: [withComponentGrid()],
|
|
636
583
|
};
|
|
637
584
|
|
|
585
|
+
/**
|
|
586
|
+
* Avatar will always take precedence over `iconStart`
|
|
587
|
+
*/
|
|
588
|
+
export const WithAvatarAndIcon: Story = {
|
|
589
|
+
args: {
|
|
590
|
+
size: 'md',
|
|
591
|
+
iconStart: Freeze,
|
|
592
|
+
avatars: [{ profileName: 'John Doe' }],
|
|
593
|
+
iconEnd: ArrowRight,
|
|
594
|
+
},
|
|
595
|
+
argTypes: hideControls(['href', 'target', 'as', 'children']),
|
|
596
|
+
parameters: augmentIconProps(),
|
|
597
|
+
};
|
|
598
|
+
|
|
638
599
|
const buttonPriorities = ['primary', 'secondary', 'tertiary', 'minimal'] as const;
|
|
639
600
|
const buttonSizes = ['sm', 'md', 'lg'] as const;
|
|
640
601
|
|
|
@@ -659,8 +620,9 @@ export const AllVariants = storyConfig(
|
|
|
659
620
|
v2
|
|
660
621
|
priority={priority as ButtonPriority}
|
|
661
622
|
size={size}
|
|
662
|
-
|
|
663
|
-
|
|
623
|
+
iconStart={ArrowLeft}
|
|
624
|
+
iconEnd={ArrowRight}
|
|
625
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
664
626
|
block
|
|
665
627
|
href="https://wise.com"
|
|
666
628
|
target="_blank"
|
|
@@ -672,11 +634,9 @@ export const AllVariants = storyConfig(
|
|
|
672
634
|
v2
|
|
673
635
|
priority={priority as ButtonPriority}
|
|
674
636
|
size={size}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
}}
|
|
679
|
-
addonEnd={{ type: 'icon', value: <ArrowRight /> }}
|
|
637
|
+
iconStart={ArrowLeft}
|
|
638
|
+
iconEnd={ArrowRight}
|
|
639
|
+
avatars={[{ asset: <Freeze /> }, { asset: <Freeze /> }]}
|
|
680
640
|
block
|
|
681
641
|
disabled
|
|
682
642
|
>
|
|
@@ -686,8 +646,9 @@ export const AllVariants = storyConfig(
|
|
|
686
646
|
v2
|
|
687
647
|
priority={priority as ButtonPriority}
|
|
688
648
|
size={size}
|
|
689
|
-
|
|
690
|
-
|
|
649
|
+
iconStart={ArrowLeft}
|
|
650
|
+
iconEnd={ArrowRight}
|
|
651
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
691
652
|
block
|
|
692
653
|
loading
|
|
693
654
|
>
|
|
@@ -707,8 +668,9 @@ export const AllVariants = storyConfig(
|
|
|
707
668
|
sentiment="negative"
|
|
708
669
|
priority={priority as ButtonPriority}
|
|
709
670
|
size={size}
|
|
710
|
-
|
|
711
|
-
|
|
671
|
+
iconStart={ChevronLeft}
|
|
672
|
+
iconEnd={ChevronRight}
|
|
673
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
712
674
|
block
|
|
713
675
|
href="https://wise.com"
|
|
714
676
|
target="_blank"
|
|
@@ -721,8 +683,9 @@ export const AllVariants = storyConfig(
|
|
|
721
683
|
sentiment="negative"
|
|
722
684
|
priority={priority as ButtonPriority}
|
|
723
685
|
size={size}
|
|
724
|
-
|
|
725
|
-
|
|
686
|
+
iconStart={ChevronLeft}
|
|
687
|
+
iconEnd={ChevronRight}
|
|
688
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
726
689
|
block
|
|
727
690
|
disabled
|
|
728
691
|
>
|
|
@@ -733,8 +696,9 @@ export const AllVariants = storyConfig(
|
|
|
733
696
|
sentiment="negative"
|
|
734
697
|
priority={priority as ButtonPriority}
|
|
735
698
|
size={size}
|
|
736
|
-
|
|
737
|
-
|
|
699
|
+
iconStart={ChevronLeft}
|
|
700
|
+
iconEnd={ChevronRight}
|
|
701
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
738
702
|
block
|
|
739
703
|
loading
|
|
740
704
|
>
|
|
@@ -748,3 +712,14 @@ export const AllVariants = storyConfig(
|
|
|
748
712
|
},
|
|
749
713
|
{ variants: ['default', 'dark', 'bright-green', 'forest-green', 'rtl'] },
|
|
750
714
|
);
|
|
715
|
+
|
|
716
|
+
export const AccessibilityAddons: Story = {
|
|
717
|
+
args: {
|
|
718
|
+
v2: true,
|
|
719
|
+
avatars: [{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }],
|
|
720
|
+
'aria-label': 'Convert Real to Yen',
|
|
721
|
+
children: 'Convert',
|
|
722
|
+
size: 'md',
|
|
723
|
+
},
|
|
724
|
+
tags: ['docs-only'],
|
|
725
|
+
};
|
package/src/button/Button.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable react/display-name */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
3
|
-
import {
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
4
|
import {
|
|
5
5
|
AnchorElementProps,
|
|
6
6
|
ButtonReferenceType,
|
|
@@ -24,11 +24,9 @@ const Button = forwardRef<ButtonReferenceType, NewButtonProps>(
|
|
|
24
24
|
disabled = false,
|
|
25
25
|
priority = 'primary',
|
|
26
26
|
sentiment = 'default',
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
addonStart,
|
|
31
|
-
addonEnd,
|
|
27
|
+
iconStart: IconStart,
|
|
28
|
+
iconEnd: IconEnd,
|
|
29
|
+
avatars,
|
|
32
30
|
// @ts-expect-error NewButtonProps has `type` prop
|
|
33
31
|
type = 'button',
|
|
34
32
|
loading = false,
|
|
@@ -73,21 +71,16 @@ const Button = forwardRef<ButtonReferenceType, NewButtonProps>(
|
|
|
73
71
|
children
|
|
74
72
|
) : (
|
|
75
73
|
<>
|
|
76
|
-
{size === 'md' &&
|
|
74
|
+
{size === 'md' && avatars && (
|
|
77
75
|
<span className="wds-Button-avatars">
|
|
78
|
-
<AvatarLayout orientation="horizontal" avatars={
|
|
76
|
+
<AvatarLayout orientation="horizontal" avatars={avatars} size={24} />
|
|
79
77
|
</span>
|
|
80
78
|
)}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<span className="wds-Button-icon wds-Button-icon--start">{addonStart.value}</span>
|
|
79
|
+
{!avatars && IconStart && (
|
|
80
|
+
<IconStart className="wds-Button-icon wds-Button-icon--start" />
|
|
84
81
|
)}
|
|
85
|
-
|
|
86
82
|
{children}
|
|
87
|
-
|
|
88
|
-
{addonEnd?.value && (
|
|
89
|
-
<span className="wds-Button-icon wds-Button-icon--end">{addonEnd.value}</span>
|
|
90
|
-
)}
|
|
83
|
+
{IconEnd && <IconEnd className="wds-Button-icon wds-Button-icon--end" />}
|
|
91
84
|
</>
|
|
92
85
|
)}
|
|
93
86
|
</span>
|
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
import { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode
|
|
1
|
+
import { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import type { PrimitiveButtonProps, PrimitiveAnchorProps } from '../primitives';
|
|
2
3
|
import type { AvatarLayoutProps } from '../avatarLayout';
|
|
3
4
|
|
|
4
5
|
export type ButtonSentiment = 'default' | 'negative';
|
|
5
6
|
export type ButtonPriority = 'primary' | 'secondary' | 'tertiary' | 'minimal';
|
|
6
7
|
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
7
8
|
export type ButtonReferenceType = HTMLButtonElement | HTMLAnchorElement;
|
|
8
|
-
type ButtonAddonIcon = {
|
|
9
|
-
type: 'icon';
|
|
10
|
-
value: ReactNode;
|
|
11
|
-
};
|
|
12
|
-
type ButtonAddonAvatar = {
|
|
13
|
-
type: 'avatar';
|
|
14
|
-
value: AvatarLayoutProps['avatars'];
|
|
15
|
-
};
|
|
16
|
-
type ButtonAddonStart = ButtonAddonIcon | ButtonAddonAvatar;
|
|
17
|
-
type ButtonAddonEnd = ButtonAddonIcon;
|
|
18
9
|
|
|
19
10
|
/**
|
|
20
11
|
* Common properties for the Button component.
|
|
@@ -64,11 +55,14 @@ export interface CommonProps {
|
|
|
64
55
|
*/
|
|
65
56
|
sentiment?: ButtonSentiment;
|
|
66
57
|
|
|
67
|
-
/**
|
|
68
|
-
|
|
58
|
+
/** Icon to be displayed on the left side of the button */
|
|
59
|
+
iconStart?: React.ElementType;
|
|
69
60
|
|
|
70
|
-
/**
|
|
71
|
-
|
|
61
|
+
/** Icon to be displayed on the right side of the button */
|
|
62
|
+
iconEnd?: React.ElementType;
|
|
63
|
+
|
|
64
|
+
/** Media to be displayed on the left side of the button */
|
|
65
|
+
avatars?: AvatarLayoutProps['avatars'];
|
|
72
66
|
|
|
73
67
|
/** Content to be displayed inside the button */
|
|
74
68
|
children?: ReactNode;
|
|
@@ -61,12 +61,17 @@ const meta: Meta<typeof Button> = {
|
|
|
61
61
|
disable: true,
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
|
-
|
|
64
|
+
iconStart: {
|
|
65
65
|
table: {
|
|
66
66
|
disable: true,
|
|
67
67
|
},
|
|
68
68
|
},
|
|
69
|
-
|
|
69
|
+
iconEnd: {
|
|
70
|
+
table: {
|
|
71
|
+
disable: true,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
avatars: {
|
|
70
75
|
table: {
|
|
71
76
|
disable: true,
|
|
72
77
|
},
|