@edux-design/buttons 0.0.6 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +38 -1835
- package/dist/index.mjs +39 -1836
- package/package.json +5 -3
- package/src/demo/Button.stories.jsx +20 -1
- package/src/elements/Button.jsx +23 -7
- package/src/elements/Button.test.jsx +41 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edux-design/buttons",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"**/*.css"
|
|
@@ -29,8 +29,10 @@
|
|
|
29
29
|
"@tailwindcss/postcss": "^4.1.12"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"react": "^19.1.0",
|
|
33
|
-
"react-dom": "^19.1.0",
|
|
34
32
|
"@edux-design/utils": "*"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": "^19.1.0",
|
|
36
|
+
"react-dom": "^19.1.0"
|
|
35
37
|
}
|
|
36
38
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Button, IconButton } from "./../index";
|
|
3
|
-
import { Close } from "@edux-design/icons";
|
|
3
|
+
import { Close, External, Warning } from "@edux-design/icons";
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
title: "Components/Button",
|
|
@@ -15,6 +15,8 @@ export default {
|
|
|
15
15
|
isBare: { control: "boolean" },
|
|
16
16
|
isStretched: { control: "boolean" },
|
|
17
17
|
disabled: { control: "boolean" },
|
|
18
|
+
startIcon: { control: false },
|
|
19
|
+
endIcon: { control: false },
|
|
18
20
|
children: { control: "text" },
|
|
19
21
|
},
|
|
20
22
|
};
|
|
@@ -48,6 +50,13 @@ Bare.args = {
|
|
|
48
50
|
isBare: true,
|
|
49
51
|
};
|
|
50
52
|
|
|
53
|
+
export const DangerBare = Template.bind({});
|
|
54
|
+
DangerBare.args = {
|
|
55
|
+
children: "Log out",
|
|
56
|
+
isBare: true,
|
|
57
|
+
isDanger: true,
|
|
58
|
+
};
|
|
59
|
+
|
|
51
60
|
export const Disabled = Template.bind({});
|
|
52
61
|
Disabled.args = {
|
|
53
62
|
children: "Disabled",
|
|
@@ -82,3 +91,13 @@ export const Default = () => (
|
|
|
82
91
|
<IconButton icon={<Close />} disabled aria-label="Disabled" />
|
|
83
92
|
</div>
|
|
84
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
|
+
);
|
package/src/elements/Button.jsx
CHANGED
|
@@ -9,6 +9,8 @@ import { cx } from "@edux-design/utils";
|
|
|
9
9
|
*
|
|
10
10
|
* @typedef {React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
11
11
|
* children?: React.ReactNode,
|
|
12
|
+
* startIcon?: React.ReactNode,
|
|
13
|
+
* endIcon?: React.ReactNode,
|
|
12
14
|
* size?: "small"|"medium"|"large",
|
|
13
15
|
* isSecondary?: boolean,
|
|
14
16
|
* isDanger?: boolean,
|
|
@@ -39,6 +41,8 @@ export const Button = forwardRef(
|
|
|
39
41
|
(
|
|
40
42
|
{
|
|
41
43
|
children,
|
|
44
|
+
startIcon,
|
|
45
|
+
endIcon,
|
|
42
46
|
size = "medium",
|
|
43
47
|
isSecondary,
|
|
44
48
|
isDanger,
|
|
@@ -51,15 +55,23 @@ export const Button = forwardRef(
|
|
|
51
55
|
ref
|
|
52
56
|
) => {
|
|
53
57
|
let variant = "primary";
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
if (isDanger
|
|
57
|
-
|
|
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
|
+
}
|
|
58
69
|
|
|
59
70
|
// handle conflicting props - the last bool wins
|
|
60
71
|
if (process.env.NODE_ENV !== "production") {
|
|
61
72
|
const count = [isSecondary, isDanger, isBare].filter(Boolean).length;
|
|
62
|
-
|
|
73
|
+
const hasAllowedCombo = isDanger && isBare && count === 2;
|
|
74
|
+
if (count > 1 && !hasAllowedCombo) {
|
|
63
75
|
console.warn(
|
|
64
76
|
"[Button]: Multiple variant props passed. Using the highest priority only."
|
|
65
77
|
);
|
|
@@ -67,7 +79,7 @@ export const Button = forwardRef(
|
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
const defaults =
|
|
70
|
-
"flex justify-center items-center focus:shadow-focus focus-visible:shadow-focus outline-none transition-all duration-300 ease-in-out cursor-pointer";
|
|
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";
|
|
71
83
|
|
|
72
84
|
const fonts =
|
|
73
85
|
"text-bold tracking-normal hover:underline hover:underline-offset-(--underline-offset-btn) active:underline active:underline-offset-(--underline-offset-btn)";
|
|
@@ -86,6 +98,8 @@ export const Button = forwardRef(
|
|
|
86
98
|
secondary:
|
|
87
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",
|
|
88
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",
|
|
89
103
|
danger:
|
|
90
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",
|
|
91
105
|
disabled:
|
|
@@ -104,7 +118,9 @@ export const Button = forwardRef(
|
|
|
104
118
|
ref={ref}
|
|
105
119
|
{...props}
|
|
106
120
|
>
|
|
107
|
-
{
|
|
121
|
+
{startIcon}
|
|
122
|
+
{children ? <span>{children}</span> : null}
|
|
123
|
+
{endIcon}
|
|
108
124
|
</button>
|
|
109
125
|
);
|
|
110
126
|
}
|
|
@@ -52,6 +52,18 @@ describe("Button", () => {
|
|
|
52
52
|
expect(screen.getByRole("button").className).toMatch(/bg-bg-danger-base/);
|
|
53
53
|
});
|
|
54
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
|
+
|
|
55
67
|
it("applies disabled variant when disabled=true", () => {
|
|
56
68
|
render(<Button disabled>Disabled</Button>);
|
|
57
69
|
const btn = screen.getByRole("button");
|
|
@@ -76,4 +88,33 @@ describe("Button", () => {
|
|
|
76
88
|
|
|
77
89
|
warnSpy.mockRestore();
|
|
78
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
|
+
});
|
|
79
120
|
});
|