@edux-design/buttons 0.1.4 → 0.2.0
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 +4 -9
- package/README.md +62 -50
- package/dist/chevron-EVM4GL6D.svg +4 -0
- package/dist/chunk-M47FNL4P.mjs +10 -0
- package/dist/elements/Button.js +39 -0
- package/dist/elements/Button.mjs +6 -0
- package/dist/index.d.mts +29 -15
- package/dist/index.d.ts +29 -15
- package/dist/index.js +110 -63
- package/dist/index.mjs +88 -40
- package/package.json +4 -9
- package/src/demo/Button.stories.jsx +103 -0
- package/src/demo/ButtonCompatibility.stories.jsx +115 -0
- package/src/demo/ButtonCounter.stories.jsx +101 -0
- package/src/demo/ButtonGroup.stories.jsx +67 -0
- package/src/elements/Button.a11y.test.jsx +60 -0
- package/src/elements/Button.jsx +127 -0
- package/src/elements/Button.test.jsx +120 -0
- package/src/elements/ButtonCounter.jsx +356 -0
- package/src/elements/ButtonCounter.test.jsx +121 -0
- package/src/elements/ButtonGroup.jsx +404 -0
- package/src/elements/ButtonGroup.test.jsx +130 -0
- package/src/elements/ButtonGroupItem.jsx +8 -0
- package/src/elements/IconButton.jsx +115 -0
- package/src/elements/IconButton.test.jsx +62 -0
- package/src/elements/MenuButton.jsx +68 -0
- package/src/elements/MenuButton.test.jsx +40 -0
- package/src/elements/testA11y.js +14 -0
- package/src/index.js +6 -0
- package/src/util/MenuButtonContext.jsx +3 -0
- package/tsconfig.json +12 -0
package/dist/index.mjs
CHANGED
|
@@ -25,12 +25,20 @@ var IconButton = forwardRef(
|
|
|
25
25
|
"[IconButton]: Multiple variant props passed. Using the highest priority only."
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
|
+
const hasAccessibleName = Boolean(
|
|
29
|
+
props["aria-label"] || props["aria-labelledby"]
|
|
30
|
+
);
|
|
31
|
+
if (!hasAccessibleName) {
|
|
32
|
+
console.warn(
|
|
33
|
+
"[IconButton]: Provide an accessible name with aria-label or aria-labelledby."
|
|
34
|
+
);
|
|
35
|
+
}
|
|
28
36
|
}
|
|
29
37
|
const defaults = "flex justify-center items-center focus:shadow-focus focus-visible:shadow-focus outline-none transition-all duration-300 ease-in-out rounded-full cursor-pointer";
|
|
30
38
|
const sizes = {
|
|
31
|
-
small: "
|
|
32
|
-
medium: "
|
|
33
|
-
large: "
|
|
39
|
+
small: "size-control-sm text-sm",
|
|
40
|
+
medium: "size-control-md text-base",
|
|
41
|
+
large: "size-control-lg text-lg"
|
|
34
42
|
};
|
|
35
43
|
const variants = {
|
|
36
44
|
primary: "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",
|
|
@@ -133,17 +141,11 @@ var Button = forwardRef2(
|
|
|
133
141
|
);
|
|
134
142
|
|
|
135
143
|
// src/elements/MenuButton.jsx
|
|
136
|
-
import
|
|
137
|
-
|
|
138
|
-
// src/util/MenuButtonContext.jsx
|
|
139
|
-
import React3, { createContext, useContext } from "react";
|
|
140
|
-
var MenuButtonContext = createContext();
|
|
141
|
-
|
|
142
|
-
// src/elements/MenuButton.jsx
|
|
144
|
+
import React3, { forwardRef as forwardRef3 } from "react";
|
|
143
145
|
import { cx as cx3 } from "@edux-design/utils";
|
|
144
146
|
|
|
145
147
|
// ../icons/dist/index.mjs
|
|
146
|
-
import {
|
|
148
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
147
149
|
var SvgChevron = (props) => /* @__PURE__ */ jsx3(
|
|
148
150
|
"svg",
|
|
149
151
|
{
|
|
@@ -168,23 +170,42 @@ var Chevron_default = SvgChevron;
|
|
|
168
170
|
|
|
169
171
|
// src/elements/MenuButton.jsx
|
|
170
172
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
var MenuButton = forwardRef3(function MenuButton2({
|
|
174
|
+
children,
|
|
175
|
+
caret,
|
|
176
|
+
size = "medium",
|
|
177
|
+
className,
|
|
178
|
+
type = "button",
|
|
179
|
+
"aria-haspopup": ariaHasPopup = "menu",
|
|
180
|
+
...props
|
|
181
|
+
}, ref) {
|
|
182
|
+
const styles = cx3(
|
|
183
|
+
"inline-flex items-center justify-center gap-8 rounded-lg border-2 border-border-primary-base bg-bg-base px-16 text-fg-primary-emphasis transition-all duration-300 ease-in-out outline-none focus:shadow-focus focus-visible:shadow-focus disabled:cursor-not-allowed disabled:border-border-subtle disabled:bg-bg-inactive disabled:text-fg-inactive",
|
|
174
184
|
{
|
|
175
|
-
"h-
|
|
176
|
-
"h-
|
|
185
|
+
"min-h-control-sm text-sm": size === "small",
|
|
186
|
+
"min-h-control-md text-base": size === "medium"
|
|
187
|
+
},
|
|
188
|
+
className
|
|
189
|
+
);
|
|
190
|
+
return /* @__PURE__ */ jsxs3(
|
|
191
|
+
"button",
|
|
192
|
+
{
|
|
193
|
+
...props,
|
|
194
|
+
ref,
|
|
195
|
+
type,
|
|
196
|
+
"aria-haspopup": ariaHasPopup,
|
|
197
|
+
className: styles,
|
|
198
|
+
children: [
|
|
199
|
+
children ? /* @__PURE__ */ jsx4("span", { children }) : null,
|
|
200
|
+
/* @__PURE__ */ jsx4("span", { "aria-hidden": "true", className: "flex items-center text-current", children: caret ?? /* @__PURE__ */ jsx4(Chevron_default, {}) })
|
|
201
|
+
]
|
|
177
202
|
}
|
|
178
203
|
);
|
|
179
|
-
|
|
180
|
-
/* @__PURE__ */ jsx4("div", { className: SPLIT_BUTTON_STYLES, children }),
|
|
181
|
-
/* @__PURE__ */ jsx4(Chevron_default, {})
|
|
182
|
-
] });
|
|
183
|
-
}
|
|
204
|
+
});
|
|
184
205
|
|
|
185
206
|
// src/elements/ButtonGroup.jsx
|
|
186
|
-
import
|
|
187
|
-
forwardRef as
|
|
207
|
+
import React4, {
|
|
208
|
+
forwardRef as forwardRef4,
|
|
188
209
|
useCallback,
|
|
189
210
|
useEffect,
|
|
190
211
|
useLayoutEffect,
|
|
@@ -207,7 +228,7 @@ var SIZE_STYLES = {
|
|
|
207
228
|
};
|
|
208
229
|
var isBrowser = typeof window !== "undefined";
|
|
209
230
|
var useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
|
|
210
|
-
var ButtonGroup =
|
|
231
|
+
var ButtonGroup = forwardRef4(function ButtonGroup2({
|
|
211
232
|
value,
|
|
212
233
|
defaultValue,
|
|
213
234
|
onChange,
|
|
@@ -365,8 +386,15 @@ var ButtonGroup = forwardRef3(function ButtonGroup2({
|
|
|
365
386
|
return -1;
|
|
366
387
|
}, [normalizedOptions]);
|
|
367
388
|
const indicatorVisible = indicator.width > 0 && indicator.height > 0;
|
|
389
|
+
const selectedIndex = normalizedOptions.findIndex(
|
|
390
|
+
(option) => option.value === selectedValue && !option.disabled
|
|
391
|
+
);
|
|
392
|
+
const firstEnabledIndex = normalizedOptions.findIndex(
|
|
393
|
+
(option) => !option.disabled
|
|
394
|
+
);
|
|
395
|
+
const activeTabStopIndex = selectedIndex >= 0 ? selectedIndex : firstEnabledIndex;
|
|
368
396
|
const rootClasses = cx4(
|
|
369
|
-
"inline-flex h-
|
|
397
|
+
"inline-flex h-control-md rounded-lg border-2 border-border-subtle bg-bg-base/90 p-2 shadow-inner",
|
|
370
398
|
isStretched ? "w-full" : "w-auto",
|
|
371
399
|
className
|
|
372
400
|
);
|
|
@@ -375,7 +403,7 @@ var ButtonGroup = forwardRef3(function ButtonGroup2({
|
|
|
375
403
|
!isStretched && "w-auto"
|
|
376
404
|
);
|
|
377
405
|
const buttonBaseClasses = cx4(
|
|
378
|
-
"relative z-10 h-
|
|
406
|
+
"relative z-10 h-control-sm inline-flex items-center justify-center gap-2 whitespace-nowrap font-semibold tracking-tight transition-colors duration-200 ease-out focus-visible:outline-none focus-visible:shadow-focus motion-reduce:duration-0",
|
|
379
407
|
sizeStyles.button,
|
|
380
408
|
isStretched ? "flex-1" : "w-auto"
|
|
381
409
|
);
|
|
@@ -385,6 +413,7 @@ var ButtonGroup = forwardRef3(function ButtonGroup2({
|
|
|
385
413
|
...rest,
|
|
386
414
|
ref: setContainerRef,
|
|
387
415
|
role: "radiogroup",
|
|
416
|
+
"aria-orientation": "horizontal",
|
|
388
417
|
className: rootClasses,
|
|
389
418
|
children: /* @__PURE__ */ jsxs4("div", { className: trackClasses, children: [
|
|
390
419
|
/* @__PURE__ */ jsx5(
|
|
@@ -392,13 +421,13 @@ var ButtonGroup = forwardRef3(function ButtonGroup2({
|
|
|
392
421
|
{
|
|
393
422
|
"aria-hidden": "true",
|
|
394
423
|
className: cx4(
|
|
395
|
-
"pointer-events-none h-
|
|
424
|
+
"pointer-events-none h-control-md absolute rounded-md border-2 border-border-primary-emphasis bg-bg-base shadow-[0_8px_20px_rgb(22_92_131/0.18)] transition-[transform,width,height] duration-300 ease-out motion-reduce:duration-0",
|
|
396
425
|
!indicatorVisible && "opacity-0"
|
|
397
426
|
),
|
|
398
427
|
style: {
|
|
399
428
|
width: indicator.width || void 0,
|
|
400
429
|
height: indicator.height || void 0,
|
|
401
|
-
transform: `translate(${indicator.x - 4}px`
|
|
430
|
+
transform: `translate(${indicator.x - 4}px, ${indicator.y - 4}px)`
|
|
402
431
|
}
|
|
403
432
|
}
|
|
404
433
|
),
|
|
@@ -456,6 +485,7 @@ var ButtonGroup = forwardRef3(function ButtonGroup2({
|
|
|
456
485
|
type: "button",
|
|
457
486
|
role: "radio",
|
|
458
487
|
"aria-checked": isActive,
|
|
488
|
+
tabIndex: option.disabled ? -1 : index === activeTabStopIndex ? 0 : -1,
|
|
459
489
|
disabled: option.disabled,
|
|
460
490
|
className: buttonClasses,
|
|
461
491
|
onClick: () => handleSelect(option),
|
|
@@ -490,24 +520,25 @@ var ButtonGroup = forwardRef3(function ButtonGroup2({
|
|
|
490
520
|
});
|
|
491
521
|
|
|
492
522
|
// src/elements/ButtonGroupItem.jsx
|
|
493
|
-
import
|
|
523
|
+
import React5 from "react";
|
|
494
524
|
function ButtonGroupItem(_props) {
|
|
495
525
|
return null;
|
|
496
526
|
}
|
|
497
527
|
ButtonGroupItem.displayName = "ButtonGroupItem";
|
|
498
528
|
|
|
499
529
|
// src/elements/ButtonCounter.jsx
|
|
500
|
-
import
|
|
501
|
-
forwardRef as
|
|
530
|
+
import React6, {
|
|
531
|
+
forwardRef as forwardRef5,
|
|
502
532
|
useCallback as useCallback2,
|
|
503
533
|
useEffect as useEffect2,
|
|
534
|
+
useId,
|
|
504
535
|
useMemo as useMemo2,
|
|
505
536
|
useRef as useRef2,
|
|
506
537
|
useState as useState2
|
|
507
538
|
} from "react";
|
|
508
539
|
import { cx as cx5 } from "@edux-design/utils";
|
|
509
540
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
510
|
-
var ButtonCounter =
|
|
541
|
+
var ButtonCounter = forwardRef5(function ButtonCounter2({
|
|
511
542
|
value,
|
|
512
543
|
defaultValue = 1,
|
|
513
544
|
onChange,
|
|
@@ -530,6 +561,7 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
530
561
|
decrementButtonProps,
|
|
531
562
|
incrementButtonProps,
|
|
532
563
|
className,
|
|
564
|
+
"aria-label": ariaLabel,
|
|
533
565
|
...rest
|
|
534
566
|
}, ref) {
|
|
535
567
|
const isControlled = value !== void 0;
|
|
@@ -575,16 +607,16 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
575
607
|
}
|
|
576
608
|
const CONTROL_SIZES = {
|
|
577
609
|
small: {
|
|
578
|
-
button: "
|
|
579
|
-
display: "h-
|
|
610
|
+
button: "size-control-sm text-sm",
|
|
611
|
+
display: "h-control-sm min-w-[48px] px-12 text-sm"
|
|
580
612
|
},
|
|
581
613
|
medium: {
|
|
582
|
-
button: "
|
|
583
|
-
display: "h-
|
|
614
|
+
button: "size-control-md text-base",
|
|
615
|
+
display: "h-control-md min-w-[56px] px-12 text-base"
|
|
584
616
|
},
|
|
585
617
|
large: {
|
|
586
|
-
button: "
|
|
587
|
-
display: "h-
|
|
618
|
+
button: "size-control-lg text-lg",
|
|
619
|
+
display: "h-control-lg min-w-[72px] px-16 text-lg"
|
|
588
620
|
}
|
|
589
621
|
};
|
|
590
622
|
const defaultsButton = "flex justify-center items-center focus:shadow-focus focus-visible:shadow-focus outline-none transition-all duration-300 ease-in-out cursor-pointer";
|
|
@@ -642,6 +674,9 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
642
674
|
);
|
|
643
675
|
const effectiveDecrementIcon = decrementIcon ?? startIcon ?? "-";
|
|
644
676
|
const effectiveIncrementIcon = incrementIcon ?? endIcon ?? "+";
|
|
677
|
+
const generatedValueId = useId();
|
|
678
|
+
const valueElementId = (inputProps == null ? void 0 : inputProps.id) ?? generatedValueId;
|
|
679
|
+
const valueAriaLabel = (inputProps == null ? void 0 : inputProps["aria-label"]) ?? ariaLabel ?? "Value";
|
|
645
680
|
const [draftValue, setDraftValue] = useState2(String(clampedValue));
|
|
646
681
|
const [isEditing, setIsEditing] = useState2(false);
|
|
647
682
|
const inputRef = useRef2(null);
|
|
@@ -675,6 +710,7 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
675
710
|
...decrementButtonProps,
|
|
676
711
|
type: "button",
|
|
677
712
|
"aria-label": (decrementButtonProps == null ? void 0 : decrementButtonProps["aria-label"]) ?? "Decrease",
|
|
713
|
+
"aria-controls": valueElementId,
|
|
678
714
|
"aria-disabled": decrementDisabled,
|
|
679
715
|
disabled: decrementDisabled,
|
|
680
716
|
className: cx5(
|
|
@@ -698,8 +734,9 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
698
734
|
ref: inputRef,
|
|
699
735
|
type: "number",
|
|
700
736
|
inputMode: "numeric",
|
|
737
|
+
id: valueElementId,
|
|
701
738
|
disabled: !!disabled,
|
|
702
|
-
"aria-label":
|
|
739
|
+
"aria-label": valueAriaLabel,
|
|
703
740
|
className: cx5(
|
|
704
741
|
displayStyles,
|
|
705
742
|
"w-[44px] text-center outline-none bg-transparent text-fg-base",
|
|
@@ -740,13 +777,24 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
740
777
|
}
|
|
741
778
|
}
|
|
742
779
|
}
|
|
743
|
-
) : /* @__PURE__ */ jsx6(
|
|
780
|
+
) : /* @__PURE__ */ jsx6(
|
|
781
|
+
"output",
|
|
782
|
+
{
|
|
783
|
+
id: valueElementId,
|
|
784
|
+
"aria-label": valueAriaLabel,
|
|
785
|
+
"aria-live": "polite",
|
|
786
|
+
"aria-atomic": "true",
|
|
787
|
+
className: cx5(displayStyles, "select-none"),
|
|
788
|
+
children: children ?? clampedValue
|
|
789
|
+
}
|
|
790
|
+
),
|
|
744
791
|
/* @__PURE__ */ jsx6(
|
|
745
792
|
"button",
|
|
746
793
|
{
|
|
747
794
|
...incrementButtonProps,
|
|
748
795
|
type: "button",
|
|
749
796
|
"aria-label": (incrementButtonProps == null ? void 0 : incrementButtonProps["aria-label"]) ?? "Increase",
|
|
797
|
+
"aria-controls": valueElementId,
|
|
750
798
|
"aria-disabled": incrementDisabled,
|
|
751
799
|
disabled: incrementDisabled,
|
|
752
800
|
className: cx5(
|
package/package.json
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edux-design/buttons",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"**/*.css"
|
|
7
7
|
],
|
|
8
|
-
"files": [
|
|
9
|
-
"dist",
|
|
10
|
-
"README.md",
|
|
11
|
-
"CHANGELOG.md"
|
|
12
|
-
],
|
|
13
8
|
"types": "./dist/index.d.ts",
|
|
14
9
|
"exports": {
|
|
15
10
|
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
16
12
|
"import": "./dist/index.mjs",
|
|
17
|
-
"require": "./dist/index.js"
|
|
18
|
-
"types": "./dist/index.d.ts"
|
|
13
|
+
"require": "./dist/index.js"
|
|
19
14
|
}
|
|
20
15
|
},
|
|
21
16
|
"scripts": {
|
|
22
17
|
"lint": "eslint . --max-warnings 0",
|
|
23
18
|
"build": "tsup src/index.js --format esm,cjs --dts",
|
|
24
19
|
"dev": "tsup src/index.js --watch --format esm,cjs --dts",
|
|
25
|
-
"prepack": "npm run build",
|
|
26
20
|
"generate:component": "turbo gen react-component",
|
|
27
21
|
"check-types": "tsc --noEmit"
|
|
28
22
|
},
|
|
@@ -38,6 +32,7 @@
|
|
|
38
32
|
"@edux-design/utils": "*"
|
|
39
33
|
},
|
|
40
34
|
"peerDependencies": {
|
|
35
|
+
"@edux-design/tokens": ">=0.2.0 <0.3.0",
|
|
41
36
|
"react": "^19.1.0",
|
|
42
37
|
"react-dom": "^19.1.0"
|
|
43
38
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
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
|
+
);
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
ButtonCounter,
|
|
5
|
+
ButtonGroup,
|
|
6
|
+
ButtonGroupItem,
|
|
7
|
+
IconButton,
|
|
8
|
+
MenuButton,
|
|
9
|
+
} from "./../index";
|
|
10
|
+
|
|
11
|
+
const sizes = ["small", "medium", "large"];
|
|
12
|
+
const variants = [
|
|
13
|
+
{ label: "Primary", props: {} },
|
|
14
|
+
{ label: "Secondary", props: { isSecondary: true } },
|
|
15
|
+
{ label: "Bare", props: { isBare: true } },
|
|
16
|
+
{ label: "Danger", props: { isDanger: true } },
|
|
17
|
+
{ label: "Danger bare", props: { isDanger: true, isBare: true } },
|
|
18
|
+
{ label: "Disabled", props: { disabled: true } },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function GroupExample() {
|
|
22
|
+
const [value, setValue] = useState("one");
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<ButtonGroup value={value} onChange={setValue}>
|
|
26
|
+
<ButtonGroupItem value="one">One</ButtonGroupItem>
|
|
27
|
+
<ButtonGroupItem value="two">Two</ButtonGroupItem>
|
|
28
|
+
<ButtonGroupItem value="three">Three</ButtonGroupItem>
|
|
29
|
+
</ButtonGroup>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function ControlMatrix() {
|
|
34
|
+
return (
|
|
35
|
+
<div className="space-y-24">
|
|
36
|
+
<section className="space-y-12">
|
|
37
|
+
<h3 className="text-lg font-semibold text-fg-emphasis">
|
|
38
|
+
Button variants
|
|
39
|
+
</h3>
|
|
40
|
+
<div className="grid gap-12">
|
|
41
|
+
{variants.map(({ label, props }) => (
|
|
42
|
+
<div key={label} className="flex flex-wrap items-center gap-12">
|
|
43
|
+
{sizes.map((size) => (
|
|
44
|
+
<Button key={size} size={size} {...props}>
|
|
45
|
+
{label} {size}
|
|
46
|
+
</Button>
|
|
47
|
+
))}
|
|
48
|
+
</div>
|
|
49
|
+
))}
|
|
50
|
+
</div>
|
|
51
|
+
</section>
|
|
52
|
+
|
|
53
|
+
<section className="space-y-12">
|
|
54
|
+
<h3 className="text-lg font-semibold text-fg-emphasis">
|
|
55
|
+
Related controls
|
|
56
|
+
</h3>
|
|
57
|
+
<div className="flex flex-wrap items-center gap-12">
|
|
58
|
+
{sizes.map((size) => (
|
|
59
|
+
<IconButton
|
|
60
|
+
key={size}
|
|
61
|
+
size={size}
|
|
62
|
+
icon={<span aria-hidden="true">×</span>}
|
|
63
|
+
aria-label={`Close ${size}`}
|
|
64
|
+
/>
|
|
65
|
+
))}
|
|
66
|
+
<MenuButton size="small" aria-expanded="false">
|
|
67
|
+
Small menu
|
|
68
|
+
</MenuButton>
|
|
69
|
+
<MenuButton size="medium" aria-expanded="false">
|
|
70
|
+
Medium menu
|
|
71
|
+
</MenuButton>
|
|
72
|
+
</div>
|
|
73
|
+
<div className="flex flex-wrap items-center gap-12">
|
|
74
|
+
{sizes.map((size) => (
|
|
75
|
+
<ButtonCounter
|
|
76
|
+
key={size}
|
|
77
|
+
size={size}
|
|
78
|
+
defaultValue={2}
|
|
79
|
+
aria-label={`${size} quantity`}
|
|
80
|
+
/>
|
|
81
|
+
))}
|
|
82
|
+
</div>
|
|
83
|
+
<GroupExample />
|
|
84
|
+
</section>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const themeCases = [
|
|
90
|
+
{ label: "Light · Blue", className: "theme--light brand--blue" },
|
|
91
|
+
{ label: "Light · Teal", className: "theme--light brand--teal" },
|
|
92
|
+
{ label: "Dark · Blue", className: "theme--dark brand--blue" },
|
|
93
|
+
{ label: "Dark · Teal", className: "theme--dark brand--teal" },
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
export default {
|
|
97
|
+
title: "Components/Button/Compatibility",
|
|
98
|
+
parameters: {
|
|
99
|
+
layout: "fullscreen",
|
|
100
|
+
chromatic: { disableSnapshot: false },
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const CompatibilityMatrix = {
|
|
105
|
+
render: () => (
|
|
106
|
+
<div className="grid grid-cols-1 2xl:grid-cols-2">
|
|
107
|
+
{themeCases.map(({ label, className }) => (
|
|
108
|
+
<div key={label} className={`${className} bg-bg-base p-24`}>
|
|
109
|
+
<h2 className="mb-16 text-xl font-bold text-fg-emphasis">{label}</h2>
|
|
110
|
+
<ControlMatrix />
|
|
111
|
+
</div>
|
|
112
|
+
))}
|
|
113
|
+
</div>
|
|
114
|
+
),
|
|
115
|
+
};
|
|
@@ -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
|
+
};
|