@edux-design/buttons 0.1.1 → 0.1.3

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @edux-design/buttons
2
2
 
3
+ ## 0.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Add shared control height tokens and update Button to use token-backed size classes.
8
+
9
+ ## 0.1.2
10
+
11
+ ### Patch Changes
12
+
13
+ - Button Counter
14
+
3
15
  ## 0.1.1
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edux-design/buttons",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -0,0 +1,101 @@
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
+ };
@@ -85,16 +85,16 @@ export const Button = forwardRef(
85
85
  "text-bold tracking-normal hover:underline hover:underline-offset-(--underline-offset-btn) active:underline active:underline-offset-(--underline-offset-btn)";
86
86
 
87
87
  const sizes = {
88
- small: "h-[36px] py-8 px-16 rounded-lg text-sm",
89
- medium: "h-[44px] py-8 px-16 rounded-lg text-base",
90
- large: "h-[56px] py-8 px-16 rounded-lg text-lg",
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
91
  };
92
92
 
93
93
  const width = isStretched ? "w-full" : "w-fit-content";
94
94
 
95
95
  const variants = {
96
96
  primary:
97
- "border-2 border-border-primary-emphasis bg-bg-primary-base text-white hover:bg-border-focus hover:text-fg-base hover:border-border-emphasis hover:shadow-md active:bg-border-focus active:bg-bg-focus-overlay active:text-fg-base",
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
98
  secondary:
99
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
100
  bare: "bg-bg-base text-fg-primary-emphasis hover:bg-bg-minimal active:bg-bg-minimal-5",
@@ -11,17 +11,17 @@ describe("Button", () => {
11
11
  it("applies medium size by default", () => {
12
12
  render(<Button>Default size</Button>);
13
13
  const btn = screen.getByRole("button");
14
- expect(btn.className).toMatch(/h-\[44px\]/); // medium height
14
+ expect(btn.className).toMatch(/h-control-md/);
15
15
  });
16
16
 
17
17
  it("applies small size when size='small'", () => {
18
18
  render(<Button size="small">Small</Button>);
19
- expect(screen.getByRole("button").className).toMatch(/h-\[36px\]/);
19
+ expect(screen.getByRole("button").className).toMatch(/h-control-sm/);
20
20
  });
21
21
 
22
22
  it("applies large size when size='large'", () => {
23
23
  render(<Button size="large">Large</Button>);
24
- expect(screen.getByRole("button").className).toMatch(/h-\[56px\]/);
24
+ expect(screen.getByRole("button").className).toMatch(/h-control-lg/);
25
25
  });
26
26
 
27
27
  it("uses stretched width when isStretched=true", () => {
@@ -0,0 +1,341 @@
1
+ import React, {
2
+ forwardRef,
3
+ useCallback,
4
+ useEffect,
5
+ useMemo,
6
+ useRef,
7
+ useState,
8
+ } from "react";
9
+ import { cx } from "@edux-design/utils";
10
+
11
+ /**
12
+ * ButtonCounter (stepper) component.
13
+ *
14
+ * Renders decrement/increment buttons with a central value display.
15
+ * Supports the same size + variant flags as the main Button.
16
+ *
17
+ * @typedef {React.HTMLAttributes<HTMLDivElement> & {
18
+ * value?: number,
19
+ * defaultValue?: number,
20
+ * onChange?: (value: number) => void,
21
+ * min?: number,
22
+ * max?: number,
23
+ * step?: number,
24
+ * children?: React.ReactNode,
25
+ * size?: "small"|"medium"|"large",
26
+ * isSecondary?: boolean,
27
+ * isDanger?: boolean,
28
+ * isBare?: boolean,
29
+ * isStretched?: boolean,
30
+ * disabled?: boolean,
31
+ * isEditable?: boolean,
32
+ * inputProps?: Omit<React.InputHTMLAttributes<HTMLInputElement>, "value"|"defaultValue"|"onChange"|"type">,
33
+ * decrementIcon?: React.ReactNode,
34
+ * incrementIcon?: React.ReactNode,
35
+ * startIcon?: React.ReactNode,
36
+ * endIcon?: React.ReactNode,
37
+ * decrementButtonProps?: React.ButtonHTMLAttributes<HTMLButtonElement>,
38
+ * incrementButtonProps?: React.ButtonHTMLAttributes<HTMLButtonElement>,
39
+ * className?: string,
40
+ * }} ButtonCounterProps
41
+ */
42
+
43
+ /**
44
+ * @type {React.ForwardRefExoticComponent<ButtonCounterProps & React.RefAttributes<HTMLDivElement>>}
45
+ */
46
+ export const ButtonCounter = forwardRef(function ButtonCounter(
47
+ {
48
+ value,
49
+ defaultValue = 1,
50
+ onChange,
51
+ min = Number.NEGATIVE_INFINITY,
52
+ max = Number.POSITIVE_INFINITY,
53
+ step = 1,
54
+ children,
55
+ size = "medium",
56
+ isSecondary,
57
+ isDanger,
58
+ isBare,
59
+ isStretched,
60
+ disabled,
61
+ isEditable = false,
62
+ inputProps,
63
+ decrementIcon,
64
+ incrementIcon,
65
+ startIcon,
66
+ endIcon,
67
+ decrementButtonProps,
68
+ incrementButtonProps,
69
+ className,
70
+ ...rest
71
+ },
72
+ ref,
73
+ ) {
74
+ const isControlled = value !== undefined;
75
+ const [internalValue, setInternalValue] = useState(defaultValue);
76
+ const currentValue = isControlled ? value : internalValue;
77
+
78
+ const clampedValue = useMemo(() => {
79
+ const safe = Number.isFinite(currentValue) ? currentValue : defaultValue;
80
+ return Math.min(max, Math.max(min, safe));
81
+ }, [currentValue, defaultValue, max, min]);
82
+
83
+ const commitValue = useCallback(
84
+ (next) => {
85
+ const clamped = Math.min(max, Math.max(min, next));
86
+ if (!isControlled) setInternalValue(clamped);
87
+ onChange?.(clamped);
88
+ },
89
+ [isControlled, max, min, onChange],
90
+ );
91
+
92
+ const decrementDisabled =
93
+ !!disabled || !Number.isFinite(clampedValue) || clampedValue - step < min;
94
+ const incrementDisabled =
95
+ !!disabled || !Number.isFinite(clampedValue) || clampedValue + step > max;
96
+
97
+ let variant = "primary";
98
+ if (disabled) {
99
+ variant = "disabled";
100
+ } else if (isDanger && isBare) {
101
+ variant = "dangerBare";
102
+ } else if (isDanger) {
103
+ variant = "danger";
104
+ } else if (isSecondary) {
105
+ variant = "secondary";
106
+ } else if (isBare) {
107
+ variant = "bare";
108
+ }
109
+
110
+ if (process.env.NODE_ENV !== "production") {
111
+ const count = [isSecondary, isDanger, isBare].filter(Boolean).length;
112
+ const hasAllowedCombo = isDanger && isBare && count === 2;
113
+ if (count > 1 && !hasAllowedCombo) {
114
+ console.warn(
115
+ "[ButtonCounter]: Multiple variant props passed. Using the highest priority only.",
116
+ );
117
+ }
118
+
119
+ if (step <= 0) {
120
+ console.warn("[ButtonCounter]: step should be > 0.");
121
+ }
122
+ }
123
+
124
+ const CONTROL_SIZES = {
125
+ small: {
126
+ button: "h-[36px] w-[36px] text-sm",
127
+ display: "h-[36px] min-w-[48px] px-12 text-sm",
128
+ },
129
+ medium: {
130
+ button: "h-[44px] w-[44px] text-base",
131
+ display: "h-[44px] min-w-[56px] px-12 text-base",
132
+ },
133
+ large: {
134
+ button: "h-[56px] w-[56px] text-lg",
135
+ display: "h-[56px] min-w-[72px] px-16 text-lg",
136
+ },
137
+ };
138
+
139
+ const defaultsButton =
140
+ "flex justify-center items-center focus:shadow-focus focus-visible:shadow-focus outline-none transition-all duration-300 ease-in-out cursor-pointer";
141
+
142
+ const defaultsDisplay =
143
+ "flex items-center justify-center text-bold tracking-normal";
144
+
145
+ const width = isStretched ? "w-full" : "w-fit-content";
146
+
147
+ const variants = {
148
+ primary: {
149
+ button:
150
+ "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",
151
+ display:
152
+ "border-y-2 border-x-2 border-border-primary-emphasis bg-bg-primary-base text-white",
153
+ },
154
+ secondary: {
155
+ button:
156
+ "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",
157
+ display:
158
+ "border-y-2 border-x-2 border-border-primary-base bg-bg-base text-fg-primary-emphasis",
159
+ },
160
+ bare: {
161
+ button:
162
+ "bg-bg-base text-fg-primary-emphasis hover:bg-bg-minimal active:bg-bg-minimal-5",
163
+ display: "bg-bg-base text-fg-primary-emphasis",
164
+ },
165
+ dangerBare: {
166
+ button:
167
+ "bg-bg-base text-fg-danger-emphasis hover:bg-bg-danger-subtle active:bg-bg-danger-subtle",
168
+ display: "bg-bg-base text-fg-danger-emphasis",
169
+ },
170
+ danger: {
171
+ button:
172
+ "bg-bg-danger-base border-2 border-border-danger-emphasis text-white hover:bg-bg-danger-base-5 active:bg-bg-danger-base-10",
173
+ display:
174
+ "border-y-2 border-x-2 border-border-danger-emphasis bg-bg-danger-base text-white",
175
+ },
176
+ disabled: {
177
+ button:
178
+ "border-2 border-border-subtle bg-bg-inactive text-fg-inactive hover:no-underline cursor-not-allowed",
179
+ display:
180
+ "border-y-2 border-x-2 border-border-subtle bg-bg-inactive text-fg-inactive",
181
+ },
182
+ };
183
+
184
+ const sizeStyles = CONTROL_SIZES[size] ?? CONTROL_SIZES.medium;
185
+ const variantStyles = variants[variant] ?? variants.primary;
186
+
187
+ const leftButtonStyles = cx(
188
+ defaultsButton,
189
+ sizeStyles.button,
190
+ "rounded-l-lg",
191
+ "relative z-10",
192
+ variantStyles.button,
193
+ variant !== "bare" && variant !== "dangerBare" ? "border-r-0" : null,
194
+ );
195
+
196
+ const rightButtonStyles = cx(
197
+ defaultsButton,
198
+ sizeStyles.button,
199
+ "rounded-r-lg",
200
+ variantStyles.button,
201
+ variant !== "bare" && variant !== "dangerBare" ? "border-l-0" : null,
202
+ );
203
+
204
+ const displayStyles = cx(
205
+ defaultsDisplay,
206
+ sizeStyles.display,
207
+ "relative z-0",
208
+ variantStyles.display,
209
+ isStretched ? "flex-1" : null,
210
+ );
211
+
212
+ const effectiveDecrementIcon = decrementIcon ?? startIcon ?? "-";
213
+ const effectiveIncrementIcon = incrementIcon ?? endIcon ?? "+";
214
+
215
+ const [draftValue, setDraftValue] = useState(String(clampedValue));
216
+ const [isEditing, setIsEditing] = useState(false);
217
+ const inputRef = useRef(null);
218
+
219
+ useEffect(() => {
220
+ if (isEditing) return;
221
+ setDraftValue(String(clampedValue));
222
+ }, [clampedValue, isEditing]);
223
+
224
+ const commitDraft = useCallback(() => {
225
+ const trimmed = String(draftValue).trim();
226
+ if (trimmed === "") {
227
+ setDraftValue(String(clampedValue));
228
+ return;
229
+ }
230
+
231
+ const next = Number(trimmed);
232
+ if (!Number.isFinite(next)) {
233
+ setDraftValue(String(clampedValue));
234
+ return;
235
+ }
236
+
237
+ commitValue(next);
238
+ }, [clampedValue, commitValue, draftValue]);
239
+
240
+ return (
241
+ <div
242
+ ref={ref}
243
+ className={cx("inline-flex items-stretch", width, className)}
244
+ {...rest}
245
+ >
246
+ <button
247
+ {...decrementButtonProps}
248
+ type="button"
249
+ aria-label={decrementButtonProps?.["aria-label"] ?? "Decrease"}
250
+ aria-disabled={decrementDisabled}
251
+ disabled={decrementDisabled}
252
+ className={cx(
253
+ leftButtonStyles,
254
+ decrementDisabled && variant !== "disabled"
255
+ ? variants.disabled.button
256
+ : null,
257
+ decrementButtonProps?.className,
258
+ )}
259
+ onClick={(event) => {
260
+ decrementButtonProps?.onClick?.(event);
261
+ if (event.defaultPrevented) return;
262
+ commitValue(clampedValue - step);
263
+ }}
264
+ >
265
+ {effectiveDecrementIcon}
266
+ </button>
267
+
268
+ {isEditable && children == null ? (
269
+ <input
270
+ {...inputProps}
271
+ ref={inputRef}
272
+ type="number"
273
+ inputMode="numeric"
274
+ disabled={!!disabled}
275
+ aria-label={inputProps?.["aria-label"] ?? "Value"}
276
+ className={cx(
277
+ displayStyles,
278
+ "w-[44px] text-center outline-none bg-transparent text-fg-base",
279
+ "[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-inner-spin-button]:m-0",
280
+ "focus:shadow-focus focus-visible:shadow-focus focus:z-15 focus-within:z-15",
281
+ inputProps?.className,
282
+ )}
283
+ value={draftValue}
284
+ onChange={(event) => {
285
+ inputProps?.onChange?.(event);
286
+ if (event.defaultPrevented) return;
287
+ setDraftValue(event.target.value);
288
+ }}
289
+ onFocus={(event) => {
290
+ inputProps?.onFocus?.(event);
291
+ if (event.defaultPrevented) return;
292
+ setIsEditing(true);
293
+ }}
294
+ onBlur={(event) => {
295
+ inputProps?.onBlur?.(event);
296
+ if (event.defaultPrevented) return;
297
+ setIsEditing(false);
298
+ commitDraft();
299
+ }}
300
+ onKeyDown={(event) => {
301
+ inputProps?.onKeyDown?.(event);
302
+ if (event.defaultPrevented) return;
303
+ if (event.key === "Enter") {
304
+ event.currentTarget.blur();
305
+ }
306
+ if (event.key === "Escape") {
307
+ setDraftValue(String(clampedValue));
308
+ event.currentTarget.blur();
309
+ }
310
+ }}
311
+ />
312
+ ) : (
313
+ <div className={cx(displayStyles, "select-none")}>
314
+ {children ?? clampedValue}
315
+ </div>
316
+ )}
317
+
318
+ <button
319
+ {...incrementButtonProps}
320
+ type="button"
321
+ aria-label={incrementButtonProps?.["aria-label"] ?? "Increase"}
322
+ aria-disabled={incrementDisabled}
323
+ disabled={incrementDisabled}
324
+ className={cx(
325
+ rightButtonStyles,
326
+ incrementDisabled && variant !== "disabled"
327
+ ? variants.disabled.button
328
+ : null,
329
+ incrementButtonProps?.className,
330
+ )}
331
+ onClick={(event) => {
332
+ incrementButtonProps?.onClick?.(event);
333
+ if (event.defaultPrevented) return;
334
+ commitValue(clampedValue + step);
335
+ }}
336
+ >
337
+ {effectiveIncrementIcon}
338
+ </button>
339
+ </div>
340
+ );
341
+ });
@@ -0,0 +1,100 @@
1
+ import React from "react";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import { ButtonCounter } from "./ButtonCounter";
4
+
5
+ describe("ButtonCounter", () => {
6
+ it("renders defaultValue", () => {
7
+ render(<ButtonCounter defaultValue={5} />);
8
+ expect(screen.getByText("5")).toBeInTheDocument();
9
+ });
10
+
11
+ it("increments and decrements", () => {
12
+ render(<ButtonCounter defaultValue={1} />);
13
+
14
+ fireEvent.click(screen.getByRole("button", { name: "Increase" }));
15
+ expect(screen.getByText("2")).toBeInTheDocument();
16
+
17
+ fireEvent.click(screen.getByRole("button", { name: "Decrease" }));
18
+ expect(screen.getByText("1")).toBeInTheDocument();
19
+ });
20
+
21
+ it("renders an editable input when isEditable=true", () => {
22
+ const onChange = vi.fn();
23
+ render(<ButtonCounter defaultValue={3} isEditable onChange={onChange} />);
24
+
25
+ const input = screen.getByRole("spinbutton", { name: "Value" });
26
+ expect(input).toHaveValue(3);
27
+
28
+ fireEvent.change(input, { target: { value: "7" } });
29
+ fireEvent.blur(input);
30
+
31
+ expect(onChange).toHaveBeenCalledWith(7);
32
+ expect(screen.getByRole("spinbutton", { name: "Value" })).toHaveValue(7);
33
+ });
34
+
35
+ it("applies medium size by default", () => {
36
+ render(<ButtonCounter defaultValue={1} />);
37
+ const buttons = screen.getAllByRole("button");
38
+ expect(buttons[0].className).toMatch(/h-\[44px\]/);
39
+ expect(buttons[1].className).toMatch(/h-\[44px\]/);
40
+ });
41
+
42
+ it("applies small and large sizes", () => {
43
+ const { rerender } = render(<ButtonCounter size="small" defaultValue={1} />);
44
+ expect(screen.getAllByRole("button")[0].className).toMatch(/h-\[36px\]/);
45
+
46
+ rerender(<ButtonCounter size="large" defaultValue={1} />);
47
+ expect(screen.getAllByRole("button")[0].className).toMatch(/h-\[56px\]/);
48
+ });
49
+
50
+ it("applies variants", () => {
51
+ const { rerender } = render(<ButtonCounter defaultValue={1} />);
52
+ expect(screen.getAllByRole("button")[0].className).toMatch(/bg-bg-primary-base/);
53
+
54
+ rerender(<ButtonCounter isSecondary defaultValue={1} />);
55
+ expect(screen.getAllByRole("button")[0].className).toMatch(/bg-bg-base/);
56
+
57
+ rerender(<ButtonCounter isDanger defaultValue={1} />);
58
+ expect(screen.getAllByRole("button")[0].className).toMatch(/bg-bg-danger-base/);
59
+
60
+ rerender(<ButtonCounter isDanger isBare defaultValue={1} />);
61
+ expect(screen.getAllByRole("button")[0].className).toMatch(/text-fg-danger-emphasis/);
62
+ });
63
+
64
+ it("applies disabled state", () => {
65
+ render(<ButtonCounter disabled defaultValue={1} />);
66
+ const buttons = screen.getAllByRole("button");
67
+ expect(buttons[0]).toBeDisabled();
68
+ expect(buttons[1]).toBeDisabled();
69
+ expect(buttons[0].className).toMatch(/bg-bg-inactive/);
70
+ });
71
+
72
+ it("uses stretched width when isStretched=true", () => {
73
+ const { container } = render(<ButtonCounter isStretched defaultValue={1} />);
74
+ expect(container.firstChild.className).toMatch(/w-full/);
75
+ });
76
+
77
+ it("logs a warning in dev mode if multiple variants are passed", () => {
78
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
79
+ process.env.NODE_ENV = "development";
80
+
81
+ render(<ButtonCounter isSecondary isDanger defaultValue={1} />);
82
+
83
+ expect(warnSpy).toHaveBeenCalledWith(
84
+ "[ButtonCounter]: Multiple variant props passed. Using the highest priority only."
85
+ );
86
+
87
+ warnSpy.mockRestore();
88
+ });
89
+
90
+ it("does not warn for the danger bare combination", () => {
91
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
92
+ process.env.NODE_ENV = "development";
93
+
94
+ render(<ButtonCounter isDanger isBare defaultValue={1} />);
95
+
96
+ expect(warnSpy).not.toHaveBeenCalled();
97
+
98
+ warnSpy.mockRestore();
99
+ });
100
+ });
@@ -75,7 +75,7 @@ export const IconButton = forwardRef(
75
75
 
76
76
  const variants = {
77
77
  primary:
78
- "border-2 border-border-primary-emphasis bg-bg-primary-base text-white hover:bg-border-focus hover:text-fg-base hover:border-border-emphasis hover:shadow-md active:bg-border-focus active:bg-bg-focus-overlay active:text-fg-base",
78
+ "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",
79
79
  secondary:
80
80
  "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",
81
81
  bare: "bg-bg-base text-fg-primary-emphasis hover:bg-bg-minimal active:bg-bg-minimal-5",
package/src/index.js CHANGED
@@ -3,3 +3,4 @@ export { Button } from "./elements/Button";
3
3
  export { MenuButton } from "./elements/MenuButton";
4
4
  export { ButtonGroup } from "./elements/ButtonGroup";
5
5
  export { ButtonGroupItem } from "./elements/ButtonGroupItem";
6
+ export { ButtonCounter } from "./elements/ButtonCounter";
@@ -1,4 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none"
2
- xmlns="http://www.w3.org/2000/svg">
3
- <path fill-rule="evenodd" clip-rule="evenodd" d="M13.5858 12L9.29289 7.70711C8.90237 7.31658 8.90237 6.68342 9.29289 6.29289C9.68342 5.90237 10.3166 5.90237 10.7071 6.29289L15.7071 11.2929C16.0976 11.6834 16.0976 12.3166 15.7071 12.7071L10.7071 17.7071C10.3166 18.0976 9.68342 18.0976 9.29289 17.7071C8.90237 17.3166 8.90237 16.6834 9.29289 16.2929L13.5858 12Z" fill="currentColor"/>
4
- </svg>
@@ -1,10 +0,0 @@
1
- // src/elements/Button.jsx
2
- import React from "react";
3
- function Button() {
4
- return /* @__PURE__ */ React.createElement("div", { className: "border-2 border-primary-700" }, "Button");
5
- }
6
- var Button_default = Button;
7
-
8
- export {
9
- Button_default
10
- };
@@ -1,39 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
-
29
- // src/elements/Button.jsx
30
- var Button_exports = {};
31
- __export(Button_exports, {
32
- default: () => Button_default
33
- });
34
- module.exports = __toCommonJS(Button_exports);
35
- var import_react = __toESM(require("react"));
36
- function Button() {
37
- return /* @__PURE__ */ import_react.default.createElement("div", { className: "border-2 border-primary-700" }, "Button");
38
- }
39
- var Button_default = Button;