@edux-design/buttons 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.d.mts +230 -0
- package/dist/index.d.ts +230 -0
- package/dist/index.js +803 -0
- package/dist/index.mjs +777 -0
- package/package.json +7 -1
- package/src/demo/Button.stories.jsx +0 -103
- package/src/demo/ButtonCounter.stories.jsx +0 -101
- package/src/demo/ButtonGroup.stories.jsx +0 -67
- package/src/elements/Button.jsx +0 -127
- package/src/elements/Button.test.jsx +0 -120
- package/src/elements/ButtonCounter.jsx +0 -341
- package/src/elements/ButtonCounter.test.jsx +0 -100
- package/src/elements/ButtonGroup.jsx +0 -389
- package/src/elements/ButtonGroup.test.jsx +0 -69
- package/src/elements/ButtonGroupItem.jsx +0 -8
- package/src/elements/IconButton.jsx +0 -104
- package/src/elements/MenuButton.jsx +0 -44
- package/src/index.js +0 -6
- package/src/util/MenuButtonContext.jsx +0 -3
- package/tsconfig.json +0 -12
package/package.json
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edux-design/buttons",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"**/*.css"
|
|
7
7
|
],
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"CHANGELOG.md"
|
|
12
|
+
],
|
|
8
13
|
"types": "./dist/index.d.ts",
|
|
9
14
|
"exports": {
|
|
10
15
|
".": {
|
|
@@ -17,6 +22,7 @@
|
|
|
17
22
|
"lint": "eslint . --max-warnings 0",
|
|
18
23
|
"build": "tsup src/index.js --format esm,cjs --dts",
|
|
19
24
|
"dev": "tsup src/index.js --watch --format esm,cjs --dts",
|
|
25
|
+
"prepack": "npm run build",
|
|
20
26
|
"generate:component": "turbo gen react-component",
|
|
21
27
|
"check-types": "tsc --noEmit"
|
|
22
28
|
},
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Button, IconButton } from "./../index";
|
|
3
|
-
import { Close, External, Warning } from "@edux-design/icons";
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
title: "Components/Button",
|
|
7
|
-
component: Button,
|
|
8
|
-
argTypes: {
|
|
9
|
-
size: {
|
|
10
|
-
control: { type: "select" },
|
|
11
|
-
options: ["small", "medium", "large"],
|
|
12
|
-
},
|
|
13
|
-
isSecondary: { control: "boolean" },
|
|
14
|
-
isDanger: { control: "boolean" },
|
|
15
|
-
isBare: { control: "boolean" },
|
|
16
|
-
isStretched: { control: "boolean" },
|
|
17
|
-
disabled: { control: "boolean" },
|
|
18
|
-
startIcon: { control: false },
|
|
19
|
-
endIcon: { control: false },
|
|
20
|
-
children: { control: "text" },
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// Base template
|
|
25
|
-
const Template = (args) => <Button {...args} />;
|
|
26
|
-
|
|
27
|
-
// Default story
|
|
28
|
-
export const Primary = Template.bind({});
|
|
29
|
-
Primary.args = {
|
|
30
|
-
children: "Primary Button",
|
|
31
|
-
size: "medium",
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// Variants
|
|
35
|
-
export const Secondary = Template.bind({});
|
|
36
|
-
Secondary.args = {
|
|
37
|
-
children: "Secondary Button",
|
|
38
|
-
isSecondary: true,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const Danger = Template.bind({});
|
|
42
|
-
Danger.args = {
|
|
43
|
-
children: "Delete",
|
|
44
|
-
isDanger: true,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export const Bare = Template.bind({});
|
|
48
|
-
Bare.args = {
|
|
49
|
-
children: "Bare Button",
|
|
50
|
-
isBare: true,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export const DangerBare = Template.bind({});
|
|
54
|
-
DangerBare.args = {
|
|
55
|
-
children: "Log out",
|
|
56
|
-
isBare: true,
|
|
57
|
-
isDanger: true,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export const Disabled = Template.bind({});
|
|
61
|
-
Disabled.args = {
|
|
62
|
-
children: "Disabled",
|
|
63
|
-
disabled: true,
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// Sizes
|
|
67
|
-
export const Small = Template.bind({});
|
|
68
|
-
Small.args = {
|
|
69
|
-
children: "Small",
|
|
70
|
-
size: "small",
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export const Large = Template.bind({});
|
|
74
|
-
Large.args = {
|
|
75
|
-
children: "Large",
|
|
76
|
-
size: "large",
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
// Stretched (full width)
|
|
80
|
-
export const Stretched = Template.bind({});
|
|
81
|
-
Stretched.args = {
|
|
82
|
-
children: "Full Width",
|
|
83
|
-
isStretched: true,
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
export const Default = () => (
|
|
87
|
-
<div className="flex gap-4 items-center">
|
|
88
|
-
<IconButton icon={<Close />} aria-label="Close" isBare />
|
|
89
|
-
<IconButton icon={<Close />} isSecondary aria-label="Close" />
|
|
90
|
-
<IconButton icon={<Close />} isDanger aria-label="Delete" />
|
|
91
|
-
<IconButton icon={<Close />} disabled aria-label="Disabled" />
|
|
92
|
-
</div>
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
export const WithIcons = () => (
|
|
96
|
-
<div className="flex gap-4 items-center">
|
|
97
|
-
<Button startIcon={<Warning />}>Start icon</Button>
|
|
98
|
-
<Button endIcon={<External />}>End icon</Button>
|
|
99
|
-
<Button isDanger isBare endIcon={<External />}>
|
|
100
|
-
Log out
|
|
101
|
-
</Button>
|
|
102
|
-
</div>
|
|
103
|
-
);
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { ButtonCounter } from "./../index";
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
title: "Components/Button",
|
|
6
|
-
component: ButtonCounter,
|
|
7
|
-
argTypes: {
|
|
8
|
-
size: {
|
|
9
|
-
control: { type: "select" },
|
|
10
|
-
options: ["small", "medium", "large"],
|
|
11
|
-
},
|
|
12
|
-
isSecondary: { control: "boolean" },
|
|
13
|
-
isDanger: { control: "boolean" },
|
|
14
|
-
isBare: { control: "boolean" },
|
|
15
|
-
isStretched: { control: "boolean" },
|
|
16
|
-
disabled: { control: "boolean" },
|
|
17
|
-
isEditable: { control: "boolean" },
|
|
18
|
-
inputProps: { control: false },
|
|
19
|
-
defaultValue: { control: "number" },
|
|
20
|
-
min: { control: "number" },
|
|
21
|
-
max: { control: "number" },
|
|
22
|
-
step: { control: "number" },
|
|
23
|
-
value: { control: false },
|
|
24
|
-
onChange: { control: false },
|
|
25
|
-
decrementIcon: { control: false },
|
|
26
|
-
incrementIcon: { control: false },
|
|
27
|
-
decrementButtonProps: { control: false },
|
|
28
|
-
incrementButtonProps: { control: false },
|
|
29
|
-
children: { control: false },
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const Template = (args) => <ButtonCounter {...args} />;
|
|
34
|
-
|
|
35
|
-
export const PrimaryCounter = Template.bind({});
|
|
36
|
-
PrimaryCounter.args = {
|
|
37
|
-
defaultValue: 1,
|
|
38
|
-
size: "medium",
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const EditableCounter = Template.bind({});
|
|
42
|
-
EditableCounter.args = {
|
|
43
|
-
defaultValue: 1,
|
|
44
|
-
isEditable: true,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export const SecondaryCounter = Template.bind({});
|
|
48
|
-
SecondaryCounter.args = {
|
|
49
|
-
defaultValue: 1,
|
|
50
|
-
isSecondary: true,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export const DangerCounter = Template.bind({});
|
|
54
|
-
DangerCounter.args = {
|
|
55
|
-
defaultValue: 1,
|
|
56
|
-
isDanger: true,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export const BareCounter = Template.bind({});
|
|
60
|
-
BareCounter.args = {
|
|
61
|
-
defaultValue: 1,
|
|
62
|
-
isBare: true,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const DangerBareCounter = Template.bind({});
|
|
66
|
-
DangerBareCounter.args = {
|
|
67
|
-
defaultValue: 1,
|
|
68
|
-
isBare: true,
|
|
69
|
-
isDanger: true,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export const DisabledCounter = Template.bind({});
|
|
73
|
-
DisabledCounter.args = {
|
|
74
|
-
defaultValue: 1,
|
|
75
|
-
disabled: true,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export const SmallCounter = Template.bind({});
|
|
79
|
-
SmallCounter.args = {
|
|
80
|
-
defaultValue: 1,
|
|
81
|
-
size: "small",
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const LargeCounter = Template.bind({});
|
|
85
|
-
LargeCounter.args = {
|
|
86
|
-
defaultValue: 1,
|
|
87
|
-
size: "large",
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export const StretchedCounter = Template.bind({});
|
|
91
|
-
StretchedCounter.args = {
|
|
92
|
-
defaultValue: 1,
|
|
93
|
-
isStretched: true,
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
export const WithBoundsCounter = Template.bind({});
|
|
97
|
-
WithBoundsCounter.args = {
|
|
98
|
-
defaultValue: 2,
|
|
99
|
-
min: 0,
|
|
100
|
-
max: 3,
|
|
101
|
-
};
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { ButtonGroup, ButtonGroupItem } from "./../index";
|
|
3
|
-
import { Warning } from "@edux-design/icons";
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
title: "Components/ButtonGroup",
|
|
7
|
-
component: ButtonGroup,
|
|
8
|
-
parameters: {
|
|
9
|
-
layout: "centered",
|
|
10
|
-
},
|
|
11
|
-
argTypes: {
|
|
12
|
-
size: {
|
|
13
|
-
control: { type: "select" },
|
|
14
|
-
options: ["small", "medium", "large"],
|
|
15
|
-
},
|
|
16
|
-
isStretched: { control: "boolean" },
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const Template = (args) => {
|
|
21
|
-
const [value, setValue] = useState(args.value ?? args.defaultValue ?? "one");
|
|
22
|
-
return (
|
|
23
|
-
<ButtonGroup
|
|
24
|
-
{...args}
|
|
25
|
-
value={value}
|
|
26
|
-
onChange={(nextValue) => {
|
|
27
|
-
setValue(nextValue);
|
|
28
|
-
args.onChange?.(nextValue);
|
|
29
|
-
}}
|
|
30
|
-
>
|
|
31
|
-
<ButtonGroupItem value="one">Label (11)</ButtonGroupItem>
|
|
32
|
-
<ButtonGroupItem value="two">Label (11)</ButtonGroupItem>
|
|
33
|
-
<ButtonGroupItem
|
|
34
|
-
value="alert"
|
|
35
|
-
endIcon={<Warning className="h-4 w-4 text-warning-600" />}
|
|
36
|
-
>
|
|
37
|
-
Label
|
|
38
|
-
</ButtonGroupItem>
|
|
39
|
-
</ButtonGroup>
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const Playground = Template.bind({});
|
|
44
|
-
Playground.args = { defaultValue: "one" };
|
|
45
|
-
|
|
46
|
-
export const WithIconCounts = () => {
|
|
47
|
-
const [value, setValue] = useState("inbox");
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<div className="w-[360px]">
|
|
51
|
-
<ButtonGroup
|
|
52
|
-
isStretched
|
|
53
|
-
value={value}
|
|
54
|
-
onChange={(next) => setValue(next)}
|
|
55
|
-
>
|
|
56
|
-
<ButtonGroupItem value="inbox">Inbox (11)</ButtonGroupItem>
|
|
57
|
-
<ButtonGroupItem value="drafts">Drafts (11)</ButtonGroupItem>
|
|
58
|
-
<ButtonGroupItem
|
|
59
|
-
value="alerts"
|
|
60
|
-
endAdornment={<Warning className="h-3.5 w-3.5 text-warning-600" />}
|
|
61
|
-
>
|
|
62
|
-
Alerts
|
|
63
|
-
</ButtonGroupItem>
|
|
64
|
-
</ButtonGroup>
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
67
|
-
};
|
package/src/elements/Button.jsx
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import React, { forwardRef } from "react";
|
|
2
|
-
import { cx } from "@edux-design/utils";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Props for the Button component.
|
|
6
|
-
*
|
|
7
|
-
* Extends all native HTML `<button>` attributes, while adding
|
|
8
|
-
* design-system variants and state controls.
|
|
9
|
-
*
|
|
10
|
-
* @typedef {React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
11
|
-
* children?: React.ReactNode,
|
|
12
|
-
* startIcon?: React.ReactNode,
|
|
13
|
-
* endIcon?: React.ReactNode,
|
|
14
|
-
* size?: "small"|"medium"|"large",
|
|
15
|
-
* isSecondary?: boolean,
|
|
16
|
-
* isDanger?: boolean,
|
|
17
|
-
* isBare?: boolean,
|
|
18
|
-
* isStretched?: boolean,
|
|
19
|
-
* disabled?: boolean,
|
|
20
|
-
* className?: string
|
|
21
|
-
* }} ButtonProps
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Button component.
|
|
26
|
-
*
|
|
27
|
-
* Provides design-system styled button with support for
|
|
28
|
-
* multiple visual variants, sizing, and states.
|
|
29
|
-
*
|
|
30
|
-
* @component
|
|
31
|
-
* @type {React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>}
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```jsx
|
|
35
|
-
* <Button size="small">Save</Button>
|
|
36
|
-
* <Button isSecondary>Cancel</Button>
|
|
37
|
-
* <Button isDanger disabled>Delete</Button>
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
export const Button = forwardRef(
|
|
41
|
-
(
|
|
42
|
-
{
|
|
43
|
-
children,
|
|
44
|
-
startIcon,
|
|
45
|
-
endIcon,
|
|
46
|
-
size = "medium",
|
|
47
|
-
isSecondary,
|
|
48
|
-
isDanger,
|
|
49
|
-
isBare,
|
|
50
|
-
isStretched,
|
|
51
|
-
disabled,
|
|
52
|
-
className,
|
|
53
|
-
...props
|
|
54
|
-
},
|
|
55
|
-
ref
|
|
56
|
-
) => {
|
|
57
|
-
let variant = "primary";
|
|
58
|
-
if (disabled) {
|
|
59
|
-
variant = "disabled";
|
|
60
|
-
} else if (isDanger && isBare) {
|
|
61
|
-
variant = "dangerBare";
|
|
62
|
-
} else if (isDanger) {
|
|
63
|
-
variant = "danger";
|
|
64
|
-
} else if (isSecondary) {
|
|
65
|
-
variant = "secondary";
|
|
66
|
-
} else if (isBare) {
|
|
67
|
-
variant = "bare";
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// handle conflicting props - the last bool wins
|
|
71
|
-
if (process.env.NODE_ENV !== "production") {
|
|
72
|
-
const count = [isSecondary, isDanger, isBare].filter(Boolean).length;
|
|
73
|
-
const hasAllowedCombo = isDanger && isBare && count === 2;
|
|
74
|
-
if (count > 1 && !hasAllowedCombo) {
|
|
75
|
-
console.warn(
|
|
76
|
-
"[Button]: Multiple variant props passed. Using the highest priority only."
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const defaults =
|
|
82
|
-
"flex justify-center items-center gap-8 focus:shadow-focus focus-visible:shadow-focus outline-none transition-all duration-300 ease-in-out cursor-pointer";
|
|
83
|
-
|
|
84
|
-
const fonts =
|
|
85
|
-
"text-bold tracking-normal hover:underline hover:underline-offset-(--underline-offset-btn) active:underline active:underline-offset-(--underline-offset-btn)";
|
|
86
|
-
|
|
87
|
-
const sizes = {
|
|
88
|
-
small: "h-control-sm py-8 px-16 rounded-lg text-sm",
|
|
89
|
-
medium: "h-control-md py-8 px-16 rounded-lg text-base",
|
|
90
|
-
large: "h-control-lg py-8 px-16 rounded-lg text-lg",
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const width = isStretched ? "w-full" : "w-fit-content";
|
|
94
|
-
|
|
95
|
-
const variants = {
|
|
96
|
-
primary:
|
|
97
|
-
"border-2 border-border-primary-emphasis bg-bg-primary-base text-white hover:bg-border-focus hover:text-fg-focus hover:border-border-emphasis hover:shadow-md active:bg-border-focus active:bg-bg-focus-overlay active:text-fg-focus",
|
|
98
|
-
secondary:
|
|
99
|
-
"border-2 border-border-primary-base bg-bg-base text-fg-primary-emphasis hover:shadow-md hover:bg-bg-primary-subtle active:bg-bg-primary-subtle-90",
|
|
100
|
-
bare: "bg-bg-base text-fg-primary-emphasis hover:bg-bg-minimal active:bg-bg-minimal-5",
|
|
101
|
-
dangerBare:
|
|
102
|
-
"bg-bg-base text-fg-danger-emphasis hover:bg-bg-danger-subtle active:bg-bg-danger-subtle",
|
|
103
|
-
danger:
|
|
104
|
-
"bg-bg-danger-base border-2 border-border-danger-emphasis text-white hover:bg-bg-danger-base-5 active:bg-bg-danger-base-10",
|
|
105
|
-
disabled:
|
|
106
|
-
"border-2 border-border-subtle bg-bg-inactive text-fg-inactive hover:no-underline",
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const STYLES = cx(defaults, sizes[size], width, fonts, variants[variant]);
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
<button
|
|
113
|
-
role="button"
|
|
114
|
-
type="button"
|
|
115
|
-
aria-disabled={disabled}
|
|
116
|
-
disabled={disabled}
|
|
117
|
-
className={STYLES}
|
|
118
|
-
ref={ref}
|
|
119
|
-
{...props}
|
|
120
|
-
>
|
|
121
|
-
{startIcon}
|
|
122
|
-
{children ? <span>{children}</span> : null}
|
|
123
|
-
{endIcon}
|
|
124
|
-
</button>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
);
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
3
|
-
import { Button } from "./Button";
|
|
4
|
-
|
|
5
|
-
describe("Button", () => {
|
|
6
|
-
it("renders children", () => {
|
|
7
|
-
render(<Button>Click me</Button>);
|
|
8
|
-
expect(screen.getByRole("button")).toHaveTextContent("Click me");
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it("applies medium size by default", () => {
|
|
12
|
-
render(<Button>Default size</Button>);
|
|
13
|
-
const btn = screen.getByRole("button");
|
|
14
|
-
expect(btn.className).toMatch(/h-control-md/);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it("applies small size when size='small'", () => {
|
|
18
|
-
render(<Button size="small">Small</Button>);
|
|
19
|
-
expect(screen.getByRole("button").className).toMatch(/h-control-sm/);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it("applies large size when size='large'", () => {
|
|
23
|
-
render(<Button size="large">Large</Button>);
|
|
24
|
-
expect(screen.getByRole("button").className).toMatch(/h-control-lg/);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("uses stretched width when isStretched=true", () => {
|
|
28
|
-
render(<Button isStretched>Stretch</Button>);
|
|
29
|
-
expect(screen.getByRole("button").className).toMatch(/w-full/);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("applies primary variant by default", () => {
|
|
33
|
-
render(<Button>Primary</Button>);
|
|
34
|
-
expect(screen.getByRole("button").className).toMatch(/bg-bg-primary-base/);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("applies secondary variant when isSecondary=true", () => {
|
|
38
|
-
render(<Button isSecondary>Secondary</Button>);
|
|
39
|
-
expect(screen.getByRole("button").className).toMatch(/bg-bg-base/);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("applies bare variant when isBare=true", () => {
|
|
43
|
-
render(<Button isBare>Bare</Button>);
|
|
44
|
-
expect(screen.getByRole("button").className).toMatch(/bg-bg-base/);
|
|
45
|
-
expect(screen.getByRole("button").className).toMatch(
|
|
46
|
-
/text-fg-primary-emphasis/
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("applies danger variant when isDanger=true", () => {
|
|
51
|
-
render(<Button isDanger>Danger</Button>);
|
|
52
|
-
expect(screen.getByRole("button").className).toMatch(/bg-bg-danger-base/);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("applies danger bare variant when isDanger and isBare", () => {
|
|
56
|
-
render(
|
|
57
|
-
<Button isDanger isBare>
|
|
58
|
-
Danger Bare
|
|
59
|
-
</Button>
|
|
60
|
-
);
|
|
61
|
-
const btn = screen.getByRole("button");
|
|
62
|
-
expect(btn.className).toMatch(/text-fg-danger-emphasis/);
|
|
63
|
-
expect(btn.className).toMatch(/bg-bg-base/);
|
|
64
|
-
expect(btn.className).not.toMatch(/bg-bg-danger-base/);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("applies disabled variant when disabled=true", () => {
|
|
68
|
-
render(<Button disabled>Disabled</Button>);
|
|
69
|
-
const btn = screen.getByRole("button");
|
|
70
|
-
expect(btn).toBeDisabled();
|
|
71
|
-
expect(btn).toHaveAttribute("aria-disabled", "true");
|
|
72
|
-
expect(btn.className).toMatch(/bg-bg-inactive/);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("logs a warning in dev mode if multiple variants are passed", () => {
|
|
76
|
-
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
77
|
-
process.env.NODE_ENV = "development";
|
|
78
|
-
|
|
79
|
-
render(
|
|
80
|
-
<Button isSecondary isDanger>
|
|
81
|
-
Conflict
|
|
82
|
-
</Button>
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
86
|
-
"[Button]: Multiple variant props passed. Using the highest priority only."
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
warnSpy.mockRestore();
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it("renders start and end icons when provided", () => {
|
|
93
|
-
render(
|
|
94
|
-
<Button
|
|
95
|
-
startIcon={<span data-testid="start-icon">S</span>}
|
|
96
|
-
endIcon={<span data-testid="end-icon">E</span>}
|
|
97
|
-
>
|
|
98
|
-
With icons
|
|
99
|
-
</Button>
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
expect(screen.getByTestId("start-icon")).toBeInTheDocument();
|
|
103
|
-
expect(screen.getByTestId("end-icon")).toBeInTheDocument();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it("does not warn for the danger bare combination", () => {
|
|
107
|
-
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
108
|
-
process.env.NODE_ENV = "development";
|
|
109
|
-
|
|
110
|
-
render(
|
|
111
|
-
<Button isDanger isBare>
|
|
112
|
-
Allowed
|
|
113
|
-
</Button>
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
117
|
-
|
|
118
|
-
warnSpy.mockRestore();
|
|
119
|
-
});
|
|
120
|
-
});
|