@transferwise/components 0.0.0-experimental-c5e7eab → 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 -12
- package/build/types/button/Button.types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/button/Button.accessibility.docs.mdx +103 -0
- package/src/button/Button.story.tsx +133 -113
- package/src/button/Button.tsx +8 -12
- package/src/button/Button.types.ts +8 -13
- 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.icon
|
|
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 { 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
|
|
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.icon
|
|
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 { 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
|
|
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,13 +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 ButtonAddonStart = {
|
|
8
|
-
icon?: ReactNode;
|
|
9
|
-
avatars?: AvatarLayoutProps['avatars'];
|
|
10
|
-
};
|
|
11
|
-
type ButtonAddonEnd = {
|
|
12
|
-
icon?: ReactNode;
|
|
13
|
-
};
|
|
14
7
|
/**
|
|
15
8
|
* Common properties for the Button component.
|
|
16
9
|
*/
|
|
@@ -49,15 +42,16 @@ export interface CommonProps {
|
|
|
49
42
|
* @default default
|
|
50
43
|
*/
|
|
51
44
|
sentiment?: ButtonSentiment;
|
|
52
|
-
/**
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
|
|
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'];
|
|
56
51
|
/** Content to be displayed inside the button */
|
|
57
52
|
children?: ReactNode;
|
|
58
53
|
}
|
|
59
54
|
export type ButtonElementProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'disabled' | 'className'> & CommonProps;
|
|
60
55
|
export type AnchorElementProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'type' | 'disabled' | 'href' | 'className'> & CommonProps;
|
|
61
56
|
export type ButtonProps = ButtonElementProps | AnchorElementProps;
|
|
62
|
-
export {};
|
|
63
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,EAAE,MAAM,OAAO,CAAC;
|
|
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": {
|
|
@@ -91,13 +91,13 @@
|
|
|
91
91
|
"rollup": "^4.18.1",
|
|
92
92
|
"rollup-preserve-directives": "^1.1.1",
|
|
93
93
|
"storybook": "^8.2.2",
|
|
94
|
-
"@transferwise/
|
|
95
|
-
"@
|
|
96
|
-
"@
|
|
94
|
+
"@transferwise/less-config": "3.1.0",
|
|
95
|
+
"@transferwise/neptune-css": "0.0.0-experimental-31fcf10",
|
|
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,72 +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: { icon: <Freeze /> },
|
|
80
|
-
'avatar: flag': { avatars: [{ asset: <Flag code="pl" /> }] },
|
|
81
|
-
'avatar: initials': { avatars: [{ profileName: 'Jay Jay' }] },
|
|
82
|
-
'avatar: icon': { avatars: [{ asset: <Freeze /> }] },
|
|
83
|
-
'avatar: image': { avatars: [{ imgSrc: '../avatar-square-dude.webp' }] },
|
|
84
|
-
'avatar: double': {
|
|
85
|
-
avatars: [{ asset: <Flag code="gb" /> }, { imgSrc: '../avatar-square-dude.webp' }],
|
|
86
|
-
},
|
|
87
|
+
true: Freeze,
|
|
87
88
|
},
|
|
88
89
|
table: {
|
|
89
90
|
category: 'Preview options',
|
|
90
|
-
type: {
|
|
91
|
-
summary: undefined,
|
|
92
|
-
},
|
|
93
91
|
},
|
|
94
92
|
},
|
|
95
|
-
|
|
93
|
+
previewIconEnd: {
|
|
96
94
|
control: 'boolean',
|
|
97
|
-
name: '
|
|
95
|
+
name: 'Show with `iconEnd`',
|
|
98
96
|
mapping: {
|
|
99
|
-
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' }],
|
|
100
114
|
},
|
|
101
115
|
table: {
|
|
102
116
|
category: 'Preview options',
|
|
103
|
-
type: {
|
|
104
|
-
summary: undefined,
|
|
105
|
-
},
|
|
106
117
|
},
|
|
107
118
|
},
|
|
108
119
|
} as const;
|
|
109
120
|
|
|
110
121
|
const getPropsForPreview = (args: PreviewStoryArgs) => {
|
|
111
|
-
const {
|
|
112
|
-
|
|
113
|
-
|
|
122
|
+
const { previewAvatars, previewIconStart, previewIconEnd, ...props } = args as {
|
|
123
|
+
previewAvatars: ButtonProps['avatars'];
|
|
124
|
+
previewIconStart: ButtonProps['iconStart'];
|
|
125
|
+
previewIconEnd: ButtonProps['iconEnd'];
|
|
114
126
|
props: typeof Button;
|
|
115
127
|
};
|
|
116
128
|
|
|
117
129
|
return [
|
|
118
130
|
props,
|
|
119
131
|
{
|
|
120
|
-
|
|
121
|
-
|
|
132
|
+
avatars: previewAvatars,
|
|
133
|
+
iconStart: previewIconStart,
|
|
134
|
+
iconEnd: previewIconEnd,
|
|
122
135
|
},
|
|
123
136
|
];
|
|
124
137
|
};
|
|
@@ -193,10 +206,13 @@ const meta: Meta<typeof Button> = {
|
|
|
193
206
|
},
|
|
194
207
|
description: 'If set, the component will render as an HTML anchor.',
|
|
195
208
|
},
|
|
196
|
-
|
|
209
|
+
iconStart: {
|
|
210
|
+
control: 'object',
|
|
211
|
+
},
|
|
212
|
+
iconEnd: {
|
|
197
213
|
control: 'object',
|
|
198
214
|
},
|
|
199
|
-
|
|
215
|
+
avatars: {
|
|
200
216
|
control: 'object',
|
|
201
217
|
},
|
|
202
218
|
type: {
|
|
@@ -221,8 +237,9 @@ const meta: Meta<typeof Button> = {
|
|
|
221
237
|
href: undefined,
|
|
222
238
|
as: undefined,
|
|
223
239
|
type: undefined,
|
|
224
|
-
|
|
225
|
-
|
|
240
|
+
iconStart: undefined,
|
|
241
|
+
iconEnd: undefined,
|
|
242
|
+
avatars: undefined,
|
|
226
243
|
className: undefined,
|
|
227
244
|
onClick: fn(),
|
|
228
245
|
children: 'Button text',
|
|
@@ -247,8 +264,9 @@ export const Playground: StoryObj<PreviewStoryArgs> = {
|
|
|
247
264
|
onKeyDown: fn(),
|
|
248
265
|
onMouseEnter: fn(),
|
|
249
266
|
onMouseLeave: fn(),
|
|
250
|
-
|
|
251
|
-
|
|
267
|
+
previewIconStart: false,
|
|
268
|
+
previewIconEnd: false,
|
|
269
|
+
previewAvatars: false,
|
|
252
270
|
},
|
|
253
271
|
argTypes: {
|
|
254
272
|
onClick: { table: { disable: true } },
|
|
@@ -293,10 +311,12 @@ export const Sentiment: StoryObj<PreviewStoryArgs> = {
|
|
|
293
311
|
...previewArgTypes,
|
|
294
312
|
},
|
|
295
313
|
args: {
|
|
296
|
-
|
|
297
|
-
|
|
314
|
+
previewIconStart: false,
|
|
315
|
+
previewIconEnd: false,
|
|
316
|
+
previewAvatars: false,
|
|
298
317
|
},
|
|
299
318
|
decorators: [withComponentGrid('30rem')],
|
|
319
|
+
parameters: augmentIconProps(),
|
|
300
320
|
};
|
|
301
321
|
|
|
302
322
|
/**
|
|
@@ -330,8 +350,9 @@ export const Priority: StoryObj<PreviewStoryArgs> = {
|
|
|
330
350
|
...previewArgTypes,
|
|
331
351
|
},
|
|
332
352
|
args: {
|
|
333
|
-
|
|
334
|
-
|
|
353
|
+
previewIconStart: false,
|
|
354
|
+
previewIconEnd: false,
|
|
355
|
+
previewAvatars: false,
|
|
335
356
|
},
|
|
336
357
|
decorators: [withComponentGrid()],
|
|
337
358
|
};
|
|
@@ -363,8 +384,9 @@ export const Size: StoryObj<PreviewStoryArgs> = {
|
|
|
363
384
|
...previewArgTypes,
|
|
364
385
|
},
|
|
365
386
|
args: {
|
|
366
|
-
|
|
367
|
-
|
|
387
|
+
previewIconStart: false,
|
|
388
|
+
previewIconEnd: false,
|
|
389
|
+
previewAvatars: false,
|
|
368
390
|
},
|
|
369
391
|
decorators: [withComponentGrid()],
|
|
370
392
|
};
|
|
@@ -389,8 +411,9 @@ export const AsAnchor: StoryObj<PreviewStoryArgs> = {
|
|
|
389
411
|
args: {
|
|
390
412
|
as: 'a',
|
|
391
413
|
href: 'https://wise.com',
|
|
392
|
-
|
|
393
|
-
|
|
414
|
+
previewIconStart: false,
|
|
415
|
+
previewIconEnd: false,
|
|
416
|
+
previewAvatars: false,
|
|
394
417
|
onClick: undefined,
|
|
395
418
|
},
|
|
396
419
|
};
|
|
@@ -411,8 +434,9 @@ export const Disabled: StoryObj<PreviewStoryArgs> = {
|
|
|
411
434
|
},
|
|
412
435
|
args: {
|
|
413
436
|
disabled: true,
|
|
414
|
-
|
|
415
|
-
|
|
437
|
+
previewIconStart: false,
|
|
438
|
+
previewIconEnd: false,
|
|
439
|
+
previewAvatars: false,
|
|
416
440
|
},
|
|
417
441
|
};
|
|
418
442
|
|
|
@@ -432,8 +456,9 @@ export const Loading: StoryObj<PreviewStoryArgs> = {
|
|
|
432
456
|
},
|
|
433
457
|
args: {
|
|
434
458
|
loading: true,
|
|
435
|
-
|
|
436
|
-
|
|
459
|
+
previewIconStart: false,
|
|
460
|
+
previewIconEnd: false,
|
|
461
|
+
previewAvatars: false,
|
|
437
462
|
},
|
|
438
463
|
};
|
|
439
464
|
|
|
@@ -456,8 +481,9 @@ export const DisplayBlock: StoryObj<PreviewStoryArgs> = {
|
|
|
456
481
|
},
|
|
457
482
|
args: {
|
|
458
483
|
block: true,
|
|
459
|
-
|
|
460
|
-
|
|
484
|
+
previewIconStart: false,
|
|
485
|
+
previewIconEnd: false,
|
|
486
|
+
previewAvatars: false,
|
|
461
487
|
},
|
|
462
488
|
};
|
|
463
489
|
|
|
@@ -471,15 +497,15 @@ export const WithIcons: StoryObj<PreviewStoryArgs> = {
|
|
|
471
497
|
|
|
472
498
|
return (
|
|
473
499
|
<>
|
|
474
|
-
<Button {...props}
|
|
500
|
+
<Button {...props} iconStart={Freeze}>
|
|
475
501
|
With start icon
|
|
476
502
|
</Button>
|
|
477
503
|
|
|
478
|
-
<Button {...props}
|
|
504
|
+
<Button {...props} iconEnd={ArrowRight}>
|
|
479
505
|
With end icon
|
|
480
506
|
</Button>
|
|
481
507
|
|
|
482
|
-
<Button {...props}
|
|
508
|
+
<Button {...props} iconStart={Freeze} iconEnd={ArrowRight}>
|
|
483
509
|
With both icons
|
|
484
510
|
</Button>
|
|
485
511
|
</>
|
|
@@ -491,27 +517,7 @@ export const WithIcons: StoryObj<PreviewStoryArgs> = {
|
|
|
491
517
|
args: {
|
|
492
518
|
size: 'md',
|
|
493
519
|
},
|
|
494
|
-
parameters:
|
|
495
|
-
docs: {
|
|
496
|
-
source: {
|
|
497
|
-
code: `
|
|
498
|
-
<>
|
|
499
|
-
<Button size="md" addonStart={{ icon: <Freeze /> }}>
|
|
500
|
-
With start icon
|
|
501
|
-
</Button>
|
|
502
|
-
|
|
503
|
-
<Button size="md" addonEnd={{ icon: <ArrowRight /> }}>
|
|
504
|
-
With end icon
|
|
505
|
-
</Button>
|
|
506
|
-
|
|
507
|
-
<Button size="md" addonStart={{ icon: <Freeze /> }} addonEnd={{ icon: <ArrowRight /> }}>
|
|
508
|
-
With both icons
|
|
509
|
-
</Button>
|
|
510
|
-
</>
|
|
511
|
-
`,
|
|
512
|
-
},
|
|
513
|
-
},
|
|
514
|
-
},
|
|
520
|
+
parameters: augmentIconProps(),
|
|
515
521
|
decorators: [withComponentGrid()],
|
|
516
522
|
};
|
|
517
523
|
|
|
@@ -525,22 +531,19 @@ export const WithAvatars: StoryObj<PreviewStoryArgs> = {
|
|
|
525
531
|
|
|
526
532
|
return (
|
|
527
533
|
<>
|
|
528
|
-
<Button {...props}
|
|
534
|
+
<Button {...props} avatars={[{ asset: <Freeze /> }]}>
|
|
529
535
|
With single avatar
|
|
530
536
|
</Button>
|
|
531
537
|
|
|
532
|
-
<Button
|
|
533
|
-
{...props}
|
|
534
|
-
addonStart={{ avatars: [{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }] }}
|
|
535
|
-
>
|
|
538
|
+
<Button {...props} avatars={[{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }]}>
|
|
536
539
|
With double avatar
|
|
537
540
|
</Button>
|
|
538
541
|
|
|
539
|
-
<Button {...props}
|
|
542
|
+
<Button {...props} avatars={[{ profileName: 'John Doe' }]}>
|
|
540
543
|
With initials
|
|
541
544
|
</Button>
|
|
542
545
|
|
|
543
|
-
<Button {...props}
|
|
546
|
+
<Button {...props} avatars={[{ imgSrc: '../avatar-square-dude.webp' }]}>
|
|
544
547
|
With an image
|
|
545
548
|
</Button>
|
|
546
549
|
</>
|
|
@@ -549,25 +552,25 @@ export const WithAvatars: StoryObj<PreviewStoryArgs> = {
|
|
|
549
552
|
argTypes: hideControls(['href', 'target', 'priority', 'sentiment', 'as', 'disabled', 'children']),
|
|
550
553
|
args: {
|
|
551
554
|
size: 'md',
|
|
552
|
-
|
|
555
|
+
avatars: [],
|
|
553
556
|
},
|
|
554
557
|
parameters: {
|
|
555
558
|
docs: {
|
|
556
559
|
source: {
|
|
557
560
|
code: `
|
|
558
561
|
<>
|
|
559
|
-
<Button v2 size="md"
|
|
562
|
+
<Button v2 size="md" avatars={[{ asset: <Freeze /> }]}>
|
|
560
563
|
With single avatar
|
|
561
564
|
</Button>
|
|
562
|
-
|
|
565
|
+
|
|
563
566
|
<Button v2 size="md" avatars={[{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }]}>
|
|
564
567
|
With double avatar
|
|
565
568
|
</Button>
|
|
566
|
-
|
|
569
|
+
|
|
567
570
|
<Button v2 size="md" avatars={[{ profileName: 'John Doe' }]}>
|
|
568
571
|
With initials
|
|
569
572
|
</Button>
|
|
570
|
-
|
|
573
|
+
|
|
571
574
|
<Button v2 size="md" avatars={[{ imgSrc: '../avatar-square-dude.webp' }]}>
|
|
572
575
|
With image Avatar
|
|
573
576
|
</Button>
|
|
@@ -580,17 +583,17 @@ export const WithAvatars: StoryObj<PreviewStoryArgs> = {
|
|
|
580
583
|
};
|
|
581
584
|
|
|
582
585
|
/**
|
|
583
|
-
* Avatar will always take precedence over
|
|
586
|
+
* Avatar will always take precedence over `iconStart`
|
|
584
587
|
*/
|
|
585
588
|
export const WithAvatarAndIcon: Story = {
|
|
586
589
|
args: {
|
|
587
590
|
size: 'md',
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
},
|
|
591
|
+
iconStart: Freeze,
|
|
592
|
+
avatars: [{ profileName: 'John Doe' }],
|
|
593
|
+
iconEnd: ArrowRight,
|
|
592
594
|
},
|
|
593
595
|
argTypes: hideControls(['href', 'target', 'as', 'children']),
|
|
596
|
+
parameters: augmentIconProps(),
|
|
594
597
|
};
|
|
595
598
|
|
|
596
599
|
const buttonPriorities = ['primary', 'secondary', 'tertiary', 'minimal'] as const;
|
|
@@ -617,8 +620,9 @@ export const AllVariants = storyConfig(
|
|
|
617
620
|
v2
|
|
618
621
|
priority={priority as ButtonPriority}
|
|
619
622
|
size={size}
|
|
620
|
-
|
|
621
|
-
|
|
623
|
+
iconStart={ArrowLeft}
|
|
624
|
+
iconEnd={ArrowRight}
|
|
625
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
622
626
|
block
|
|
623
627
|
href="https://wise.com"
|
|
624
628
|
target="_blank"
|
|
@@ -630,8 +634,9 @@ export const AllVariants = storyConfig(
|
|
|
630
634
|
v2
|
|
631
635
|
priority={priority as ButtonPriority}
|
|
632
636
|
size={size}
|
|
633
|
-
|
|
634
|
-
|
|
637
|
+
iconStart={ArrowLeft}
|
|
638
|
+
iconEnd={ArrowRight}
|
|
639
|
+
avatars={[{ asset: <Freeze /> }, { asset: <Freeze /> }]}
|
|
635
640
|
block
|
|
636
641
|
disabled
|
|
637
642
|
>
|
|
@@ -641,8 +646,9 @@ export const AllVariants = storyConfig(
|
|
|
641
646
|
v2
|
|
642
647
|
priority={priority as ButtonPriority}
|
|
643
648
|
size={size}
|
|
644
|
-
|
|
645
|
-
|
|
649
|
+
iconStart={ArrowLeft}
|
|
650
|
+
iconEnd={ArrowRight}
|
|
651
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
646
652
|
block
|
|
647
653
|
loading
|
|
648
654
|
>
|
|
@@ -662,8 +668,9 @@ export const AllVariants = storyConfig(
|
|
|
662
668
|
sentiment="negative"
|
|
663
669
|
priority={priority as ButtonPriority}
|
|
664
670
|
size={size}
|
|
665
|
-
|
|
666
|
-
|
|
671
|
+
iconStart={ChevronLeft}
|
|
672
|
+
iconEnd={ChevronRight}
|
|
673
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
667
674
|
block
|
|
668
675
|
href="https://wise.com"
|
|
669
676
|
target="_blank"
|
|
@@ -676,8 +683,9 @@ export const AllVariants = storyConfig(
|
|
|
676
683
|
sentiment="negative"
|
|
677
684
|
priority={priority as ButtonPriority}
|
|
678
685
|
size={size}
|
|
679
|
-
|
|
680
|
-
|
|
686
|
+
iconStart={ChevronLeft}
|
|
687
|
+
iconEnd={ChevronRight}
|
|
688
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
681
689
|
block
|
|
682
690
|
disabled
|
|
683
691
|
>
|
|
@@ -688,8 +696,9 @@ export const AllVariants = storyConfig(
|
|
|
688
696
|
sentiment="negative"
|
|
689
697
|
priority={priority as ButtonPriority}
|
|
690
698
|
size={size}
|
|
691
|
-
|
|
692
|
-
|
|
699
|
+
iconStart={ChevronLeft}
|
|
700
|
+
iconEnd={ChevronRight}
|
|
701
|
+
avatars={[{ asset: <Freeze /> }]}
|
|
693
702
|
block
|
|
694
703
|
loading
|
|
695
704
|
>
|
|
@@ -703,3 +712,14 @@ export const AllVariants = storyConfig(
|
|
|
703
712
|
},
|
|
704
713
|
{ variants: ['default', 'dark', 'bright-green', 'forest-green', 'rtl'] },
|
|
705
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
|
@@ -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,18 +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
|
-
<
|
|
79
|
+
{!avatars && IconStart && (
|
|
80
|
+
<IconStart className="wds-Button-icon wds-Button-icon--start" />
|
|
83
81
|
)}
|
|
84
82
|
{children}
|
|
85
|
-
{
|
|
86
|
-
<span className="wds-Button-icon wds-Button-icon--end">{addonEnd.icon}</span>
|
|
87
|
-
)}
|
|
83
|
+
{IconEnd && <IconEnd className="wds-Button-icon wds-Button-icon--end" />}
|
|
88
84
|
</>
|
|
89
85
|
)}
|
|
90
86
|
</span>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
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';
|
|
@@ -6,15 +7,6 @@ export type ButtonPriority = 'primary' | 'secondary' | 'tertiary' | 'minimal';
|
|
|
6
7
|
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
7
8
|
export type ButtonReferenceType = HTMLButtonElement | HTMLAnchorElement;
|
|
8
9
|
|
|
9
|
-
type ButtonAddonStart = {
|
|
10
|
-
icon?: ReactNode;
|
|
11
|
-
avatars?: AvatarLayoutProps['avatars'];
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
type ButtonAddonEnd = {
|
|
15
|
-
icon?: ReactNode;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
10
|
/**
|
|
19
11
|
* Common properties for the Button component.
|
|
20
12
|
*/
|
|
@@ -63,11 +55,14 @@ export interface CommonProps {
|
|
|
63
55
|
*/
|
|
64
56
|
sentiment?: ButtonSentiment;
|
|
65
57
|
|
|
66
|
-
/**
|
|
67
|
-
|
|
58
|
+
/** Icon to be displayed on the left side of the button */
|
|
59
|
+
iconStart?: React.ElementType;
|
|
68
60
|
|
|
69
|
-
/**
|
|
70
|
-
|
|
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'];
|
|
71
66
|
|
|
72
67
|
/** Content to be displayed inside the button */
|
|
73
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
|
},
|