@edux-design/buttons 0.0.2 → 0.0.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 +15 -0
- package/README.md +110 -0
- package/dist/index.d.mts +159 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.js +425 -26
- package/dist/index.mjs +429 -25
- package/package.json +6 -4
- package/src/demo/Button.stories.jsx +84 -0
- package/src/demo/ButtonGroup.stories.jsx +67 -0
- package/src/elements/Button.jsx +35 -3
- package/src/elements/ButtonGroup.jsx +387 -0
- package/src/elements/ButtonGroup.test.jsx +69 -0
- package/src/elements/ButtonGroupItem.jsx +8 -0
- package/src/elements/IconButton.jsx +104 -0
- package/src/elements/MenuButton.jsx +25 -1
- package/src/index.js +3 -0
- package/tsconfig.json +12 -0
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,66 @@
|
|
|
1
|
-
// src/elements/
|
|
1
|
+
// src/elements/IconButton.jsx
|
|
2
2
|
import React, { forwardRef } from "react";
|
|
3
3
|
import { cx } from "@edux-design/utils";
|
|
4
|
-
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
var IconButton = forwardRef(
|
|
6
|
+
({
|
|
7
|
+
icon,
|
|
8
|
+
size = "medium",
|
|
9
|
+
isSecondary,
|
|
10
|
+
isDanger,
|
|
11
|
+
isBare,
|
|
12
|
+
disabled,
|
|
13
|
+
className,
|
|
14
|
+
...props
|
|
15
|
+
}, ref) => {
|
|
16
|
+
let variant = "primary";
|
|
17
|
+
if (isBare) variant = "bare";
|
|
18
|
+
if (isSecondary) variant = "secondary";
|
|
19
|
+
if (isDanger) variant = "danger";
|
|
20
|
+
if (disabled) variant = "disabled";
|
|
21
|
+
if (process.env.NODE_ENV !== "production") {
|
|
22
|
+
const count = [isSecondary, isDanger, isBare].filter(Boolean).length;
|
|
23
|
+
if (count > 1) {
|
|
24
|
+
console.warn(
|
|
25
|
+
"[IconButton]: Multiple variant props passed. Using the highest priority only."
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
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";
|
|
30
|
+
const sizes = {
|
|
31
|
+
small: "h-[36px] w-[36px] text-sm",
|
|
32
|
+
medium: "h-[44px] w-[44px] text-base",
|
|
33
|
+
large: "h-[56px] w-[56px] text-lg"
|
|
34
|
+
};
|
|
35
|
+
const variants = {
|
|
36
|
+
primary: "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",
|
|
37
|
+
secondary: "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",
|
|
38
|
+
bare: "bg-bg-base text-fg-primary-emphasis hover:bg-bg-minimal active:bg-bg-minimal-5",
|
|
39
|
+
danger: "bg-bg-danger-base border-2 border-border-danger-emphasis text-white hover:bg-bg-danger-base-5 active:bg-bg-danger-base-10",
|
|
40
|
+
disabled: "border-2 border-border-subtle bg-bg-inactive text-fg-inactive hover:no-underline cursor-not-allowed"
|
|
41
|
+
};
|
|
42
|
+
const STYLES = cx(defaults, sizes[size], variants[variant], className);
|
|
43
|
+
return /* @__PURE__ */ jsx(
|
|
44
|
+
"button",
|
|
45
|
+
{
|
|
46
|
+
role: "button",
|
|
47
|
+
type: "button",
|
|
48
|
+
"aria-disabled": disabled,
|
|
49
|
+
disabled,
|
|
50
|
+
className: STYLES,
|
|
51
|
+
ref,
|
|
52
|
+
...props,
|
|
53
|
+
children: icon
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// src/elements/Button.jsx
|
|
60
|
+
import React2, { forwardRef as forwardRef2 } from "react";
|
|
61
|
+
import { cx as cx2 } from "@edux-design/utils";
|
|
62
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
63
|
+
var Button = forwardRef2(
|
|
5
64
|
({
|
|
6
65
|
children,
|
|
7
66
|
size = "medium",
|
|
@@ -41,8 +100,8 @@ var Button = forwardRef(
|
|
|
41
100
|
danger: "bg-bg-danger-base border-2 border-border-danger-emphasis text-white hover:bg-bg-danger-base-5 active:bg-bg-danger-base-10",
|
|
42
101
|
disabled: "border-2 border-border-subtle bg-bg-inactive text-fg-inactive hover:no-underline"
|
|
43
102
|
};
|
|
44
|
-
const STYLES =
|
|
45
|
-
return /* @__PURE__ */
|
|
103
|
+
const STYLES = cx2(defaults, sizes[size], width, fonts, variants[variant]);
|
|
104
|
+
return /* @__PURE__ */ jsx2(
|
|
46
105
|
"button",
|
|
47
106
|
{
|
|
48
107
|
role: "button",
|
|
@@ -51,22 +110,22 @@ var Button = forwardRef(
|
|
|
51
110
|
disabled,
|
|
52
111
|
className: STYLES,
|
|
53
112
|
ref,
|
|
54
|
-
...props
|
|
55
|
-
|
|
56
|
-
|
|
113
|
+
...props,
|
|
114
|
+
children
|
|
115
|
+
}
|
|
57
116
|
);
|
|
58
117
|
}
|
|
59
118
|
);
|
|
60
119
|
|
|
61
120
|
// src/elements/MenuButton.jsx
|
|
62
|
-
import
|
|
121
|
+
import React4 from "react";
|
|
63
122
|
|
|
64
123
|
// src/util/MenuButtonContext.jsx
|
|
65
|
-
import
|
|
124
|
+
import React3, { createContext, useContext } from "react";
|
|
66
125
|
var MenuButtonContext = createContext();
|
|
67
126
|
|
|
68
127
|
// src/elements/MenuButton.jsx
|
|
69
|
-
import { cx as
|
|
128
|
+
import { cx as cx3 } from "@edux-design/utils";
|
|
70
129
|
|
|
71
130
|
// ../icons/dist/index.mjs
|
|
72
131
|
var __create = Object.create;
|
|
@@ -1723,19 +1782,19 @@ var require_react_jsx_runtime_development = __commonJS({
|
|
|
1723
1782
|
function validateChildKeys(node) {
|
|
1724
1783
|
"object" === typeof node && null !== node && node.$$typeof === REACT_ELEMENT_TYPE && node._store && (node._store.validated = 1);
|
|
1725
1784
|
}
|
|
1726
|
-
var
|
|
1727
|
-
var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals =
|
|
1785
|
+
var React7 = require_react(), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler");
|
|
1786
|
+
var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React7.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
|
|
1728
1787
|
return null;
|
|
1729
1788
|
};
|
|
1730
|
-
|
|
1789
|
+
React7 = {
|
|
1731
1790
|
react_stack_bottom_frame: function(callStackForError) {
|
|
1732
1791
|
return callStackForError();
|
|
1733
1792
|
}
|
|
1734
1793
|
};
|
|
1735
1794
|
var specialPropKeyWarningShown;
|
|
1736
1795
|
var didWarnAboutElementRef = {};
|
|
1737
|
-
var unknownOwnerDebugStack =
|
|
1738
|
-
|
|
1796
|
+
var unknownOwnerDebugStack = React7.react_stack_bottom_frame.bind(
|
|
1797
|
+
React7,
|
|
1739
1798
|
UnknownOwner
|
|
1740
1799
|
)();
|
|
1741
1800
|
var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
|
|
@@ -1779,10 +1838,13 @@ var require_jsx_runtime = __commonJS({
|
|
|
1779
1838
|
}
|
|
1780
1839
|
}
|
|
1781
1840
|
});
|
|
1782
|
-
var import_jsx_runtime = __toESM(require_jsx_runtime());
|
|
1783
|
-
var import_jsx_runtime2 = __toESM(require_jsx_runtime());
|
|
1784
1841
|
var import_jsx_runtime3 = __toESM(require_jsx_runtime());
|
|
1785
|
-
var
|
|
1842
|
+
var import_jsx_runtime22 = __toESM(require_jsx_runtime());
|
|
1843
|
+
var import_jsx_runtime32 = __toESM(require_jsx_runtime());
|
|
1844
|
+
var import_jsx_runtime4 = __toESM(require_jsx_runtime());
|
|
1845
|
+
var import_jsx_runtime5 = __toESM(require_jsx_runtime());
|
|
1846
|
+
var import_jsx_runtime6 = __toESM(require_jsx_runtime());
|
|
1847
|
+
var SvgChevron = (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1786
1848
|
"svg",
|
|
1787
1849
|
{
|
|
1788
1850
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -1791,7 +1853,7 @@ var SvgChevron = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
|
1791
1853
|
fill: "none",
|
|
1792
1854
|
viewBox: "0 0 24 24",
|
|
1793
1855
|
...props,
|
|
1794
|
-
children: /* @__PURE__ */ (0,
|
|
1856
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1795
1857
|
"path",
|
|
1796
1858
|
{
|
|
1797
1859
|
fill: "currentColor",
|
|
@@ -1803,9 +1865,6 @@ var SvgChevron = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
|
1803
1865
|
}
|
|
1804
1866
|
);
|
|
1805
1867
|
var Chevron_default = SvgChevron;
|
|
1806
|
-
var import_jsx_runtime4 = __toESM(require_jsx_runtime());
|
|
1807
|
-
var import_jsx_runtime5 = __toESM(require_jsx_runtime());
|
|
1808
|
-
var import_jsx_runtime6 = __toESM(require_jsx_runtime());
|
|
1809
1868
|
var import_jsx_runtime7 = __toESM(require_jsx_runtime());
|
|
1810
1869
|
var import_jsx_runtime8 = __toESM(require_jsx_runtime());
|
|
1811
1870
|
var import_jsx_runtime9 = __toESM(require_jsx_runtime());
|
|
@@ -1821,7 +1880,7 @@ var import_jsx_runtime18 = __toESM(require_jsx_runtime());
|
|
|
1821
1880
|
var import_jsx_runtime19 = __toESM(require_jsx_runtime());
|
|
1822
1881
|
var import_jsx_runtime20 = __toESM(require_jsx_runtime());
|
|
1823
1882
|
var import_jsx_runtime21 = __toESM(require_jsx_runtime());
|
|
1824
|
-
var
|
|
1883
|
+
var import_jsx_runtime222 = __toESM(require_jsx_runtime());
|
|
1825
1884
|
var import_jsx_runtime23 = __toESM(require_jsx_runtime());
|
|
1826
1885
|
var import_jsx_runtime24 = __toESM(require_jsx_runtime());
|
|
1827
1886
|
var import_jsx_runtime25 = __toESM(require_jsx_runtime());
|
|
@@ -1830,20 +1889,365 @@ var import_jsx_runtime27 = __toESM(require_jsx_runtime());
|
|
|
1830
1889
|
var import_jsx_runtime28 = __toESM(require_jsx_runtime());
|
|
1831
1890
|
var import_jsx_runtime29 = __toESM(require_jsx_runtime());
|
|
1832
1891
|
var import_jsx_runtime30 = __toESM(require_jsx_runtime());
|
|
1892
|
+
var import_jsx_runtime31 = __toESM(require_jsx_runtime());
|
|
1893
|
+
var import_jsx_runtime322 = __toESM(require_jsx_runtime());
|
|
1894
|
+
var import_jsx_runtime33 = __toESM(require_jsx_runtime());
|
|
1895
|
+
var import_jsx_runtime34 = __toESM(require_jsx_runtime());
|
|
1896
|
+
var import_jsx_runtime35 = __toESM(require_jsx_runtime());
|
|
1897
|
+
var import_jsx_runtime36 = __toESM(require_jsx_runtime());
|
|
1898
|
+
var import_jsx_runtime37 = __toESM(require_jsx_runtime());
|
|
1899
|
+
var import_jsx_runtime38 = __toESM(require_jsx_runtime());
|
|
1900
|
+
var import_jsx_runtime39 = __toESM(require_jsx_runtime());
|
|
1901
|
+
var import_jsx_runtime40 = __toESM(require_jsx_runtime());
|
|
1902
|
+
var import_jsx_runtime41 = __toESM(require_jsx_runtime());
|
|
1903
|
+
var import_jsx_runtime42 = __toESM(require_jsx_runtime());
|
|
1904
|
+
var import_jsx_runtime43 = __toESM(require_jsx_runtime());
|
|
1905
|
+
var import_jsx_runtime44 = __toESM(require_jsx_runtime());
|
|
1906
|
+
var import_jsx_runtime45 = __toESM(require_jsx_runtime());
|
|
1907
|
+
var import_jsx_runtime46 = __toESM(require_jsx_runtime());
|
|
1908
|
+
var import_jsx_runtime47 = __toESM(require_jsx_runtime());
|
|
1909
|
+
var import_jsx_runtime48 = __toESM(require_jsx_runtime());
|
|
1910
|
+
var import_jsx_runtime49 = __toESM(require_jsx_runtime());
|
|
1911
|
+
var import_jsx_runtime50 = __toESM(require_jsx_runtime());
|
|
1912
|
+
var import_jsx_runtime51 = __toESM(require_jsx_runtime());
|
|
1913
|
+
var import_jsx_runtime52 = __toESM(require_jsx_runtime());
|
|
1914
|
+
var import_jsx_runtime53 = __toESM(require_jsx_runtime());
|
|
1915
|
+
var import_jsx_runtime54 = __toESM(require_jsx_runtime());
|
|
1916
|
+
var import_jsx_runtime55 = __toESM(require_jsx_runtime());
|
|
1833
1917
|
|
|
1834
1918
|
// src/elements/MenuButton.jsx
|
|
1919
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
1835
1920
|
function MenuButton({ children, size }) {
|
|
1836
|
-
const SPLIT_BUTTON_STYLES =
|
|
1921
|
+
const SPLIT_BUTTON_STYLES = cx3(
|
|
1837
1922
|
"w-[36px] border-l-[1px] border-l-black flex flex-row justify-center items-center",
|
|
1838
1923
|
{
|
|
1839
1924
|
"h-[32px]": size === "small",
|
|
1840
1925
|
"h-[40px] py-2": size === "medium" || size === void 0
|
|
1841
1926
|
}
|
|
1842
1927
|
);
|
|
1843
|
-
return /* @__PURE__ */
|
|
1928
|
+
return /* @__PURE__ */ jsxs(MenuButtonContext.Provider, { value: true, children: [
|
|
1929
|
+
/* @__PURE__ */ jsx3("div", { className: SPLIT_BUTTON_STYLES, children }),
|
|
1930
|
+
/* @__PURE__ */ jsx3(Chevron_default, {})
|
|
1931
|
+
] });
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
// src/elements/ButtonGroup.jsx
|
|
1935
|
+
import React5, {
|
|
1936
|
+
forwardRef as forwardRef3,
|
|
1937
|
+
useCallback,
|
|
1938
|
+
useEffect,
|
|
1939
|
+
useLayoutEffect,
|
|
1940
|
+
useMemo,
|
|
1941
|
+
useRef,
|
|
1942
|
+
useState
|
|
1943
|
+
} from "react";
|
|
1944
|
+
import { cx as cx4, filterChildrenByDisplayName } from "@edux-design/utils";
|
|
1945
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1946
|
+
var SIZE_STYLES = {
|
|
1947
|
+
small: {
|
|
1948
|
+
button: "text-xs px-12 py-6 rounded-md "
|
|
1949
|
+
},
|
|
1950
|
+
medium: {
|
|
1951
|
+
button: "text-sm px-12 py-6 rounded-md "
|
|
1952
|
+
},
|
|
1953
|
+
large: {
|
|
1954
|
+
button: "text-base px-12 py-6 rounded-md"
|
|
1955
|
+
}
|
|
1956
|
+
};
|
|
1957
|
+
var isBrowser = typeof window !== "undefined";
|
|
1958
|
+
var useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
|
|
1959
|
+
var ButtonGroup = forwardRef3(function ButtonGroup2({
|
|
1960
|
+
value,
|
|
1961
|
+
defaultValue,
|
|
1962
|
+
onChange,
|
|
1963
|
+
size = "medium",
|
|
1964
|
+
isStretched = false,
|
|
1965
|
+
className,
|
|
1966
|
+
children,
|
|
1967
|
+
...rest
|
|
1968
|
+
}, forwardedRef) {
|
|
1969
|
+
const normalizedOptions = useMemo(() => {
|
|
1970
|
+
const childItems = filterChildrenByDisplayName(children, "ButtonGroupItem");
|
|
1971
|
+
return childItems.map((child, index) => {
|
|
1972
|
+
const props = child.props || {};
|
|
1973
|
+
const hasValue = props.value !== void 0;
|
|
1974
|
+
const safeValue = hasValue && props.value !== null ? props.value : index;
|
|
1975
|
+
return {
|
|
1976
|
+
...props,
|
|
1977
|
+
label: props.label ?? props.children ?? `Option ${index + 1}`,
|
|
1978
|
+
value: safeValue
|
|
1979
|
+
};
|
|
1980
|
+
});
|
|
1981
|
+
}, [children]);
|
|
1982
|
+
const sizeStyles = SIZE_STYLES[size] ?? SIZE_STYLES.medium;
|
|
1983
|
+
const initialValue = value ?? defaultValue ?? (normalizedOptions.length ? normalizedOptions[0].value : void 0);
|
|
1984
|
+
const [internalValue, setInternalValue] = useState(initialValue);
|
|
1985
|
+
const isControlled = value !== void 0;
|
|
1986
|
+
const selectedValue = isControlled ? value : internalValue;
|
|
1987
|
+
useEffect(() => {
|
|
1988
|
+
if (!isControlled && defaultValue !== void 0) {
|
|
1989
|
+
setInternalValue(defaultValue);
|
|
1990
|
+
}
|
|
1991
|
+
}, [defaultValue, isControlled]);
|
|
1992
|
+
useEffect(() => {
|
|
1993
|
+
if (isControlled) return;
|
|
1994
|
+
if (normalizedOptions.length && !normalizedOptions.some((option) => option.value === internalValue)) {
|
|
1995
|
+
setInternalValue(normalizedOptions[0].value);
|
|
1996
|
+
}
|
|
1997
|
+
}, [internalValue, isControlled, normalizedOptions]);
|
|
1998
|
+
const buttonRefs = useRef(/* @__PURE__ */ new Map());
|
|
1999
|
+
const containerRef = useRef(null);
|
|
2000
|
+
const indicatorRef = useRef({ width: 0, height: 0, x: 0, y: 0 });
|
|
2001
|
+
const [indicator, setIndicator] = useState({
|
|
2002
|
+
width: 0,
|
|
2003
|
+
height: 0,
|
|
2004
|
+
x: 0,
|
|
2005
|
+
y: 0
|
|
2006
|
+
});
|
|
2007
|
+
const setContainerRef = useCallback(
|
|
2008
|
+
(node) => {
|
|
2009
|
+
containerRef.current = node;
|
|
2010
|
+
if (typeof forwardedRef === "function") {
|
|
2011
|
+
forwardedRef(node);
|
|
2012
|
+
} else if (forwardedRef) {
|
|
2013
|
+
forwardedRef.current = node;
|
|
2014
|
+
}
|
|
2015
|
+
},
|
|
2016
|
+
[forwardedRef]
|
|
2017
|
+
);
|
|
2018
|
+
const registerButtonRef = useCallback((optionValue) => {
|
|
2019
|
+
return (node) => {
|
|
2020
|
+
if (!buttonRefs.current) return;
|
|
2021
|
+
if (node) {
|
|
2022
|
+
buttonRefs.current.set(optionValue, node);
|
|
2023
|
+
} else {
|
|
2024
|
+
buttonRefs.current.delete(optionValue);
|
|
2025
|
+
}
|
|
2026
|
+
};
|
|
2027
|
+
}, []);
|
|
2028
|
+
const updateIndicator = useCallback(() => {
|
|
2029
|
+
const container = containerRef.current;
|
|
2030
|
+
const target = buttonRefs.current.get(selectedValue);
|
|
2031
|
+
if (!container || !target) {
|
|
2032
|
+
if (indicatorRef.current.width !== 0) {
|
|
2033
|
+
indicatorRef.current = { width: 0, height: 0, x: 0, y: 0 };
|
|
2034
|
+
setIndicator(indicatorRef.current);
|
|
2035
|
+
}
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
const containerRect = container.getBoundingClientRect();
|
|
2039
|
+
const targetRect = target.getBoundingClientRect();
|
|
2040
|
+
const next = {
|
|
2041
|
+
width: targetRect.width,
|
|
2042
|
+
height: targetRect.height,
|
|
2043
|
+
x: targetRect.left - containerRect.left,
|
|
2044
|
+
y: targetRect.top - containerRect.top
|
|
2045
|
+
};
|
|
2046
|
+
const prev = indicatorRef.current;
|
|
2047
|
+
if (prev.width !== next.width || prev.height !== next.height || prev.x !== next.x || prev.y !== next.y) {
|
|
2048
|
+
indicatorRef.current = next;
|
|
2049
|
+
setIndicator(next);
|
|
2050
|
+
}
|
|
2051
|
+
}, [selectedValue]);
|
|
2052
|
+
useIsomorphicLayoutEffect(() => {
|
|
2053
|
+
updateIndicator();
|
|
2054
|
+
}, [updateIndicator, normalizedOptions.length, size]);
|
|
2055
|
+
useEffect(() => {
|
|
2056
|
+
if (!isBrowser) return;
|
|
2057
|
+
const handleResize = () => updateIndicator();
|
|
2058
|
+
window.addEventListener("resize", handleResize);
|
|
2059
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
2060
|
+
}, [updateIndicator]);
|
|
2061
|
+
useEffect(() => {
|
|
2062
|
+
if (!isBrowser) return;
|
|
2063
|
+
const node = containerRef.current;
|
|
2064
|
+
if (!node || typeof ResizeObserver === "undefined") return;
|
|
2065
|
+
const observer = new ResizeObserver(() => {
|
|
2066
|
+
updateIndicator();
|
|
2067
|
+
});
|
|
2068
|
+
observer.observe(node);
|
|
2069
|
+
return () => observer.disconnect();
|
|
2070
|
+
}, [updateIndicator]);
|
|
2071
|
+
const focusOption = useCallback((option) => {
|
|
2072
|
+
const node = buttonRefs.current.get(option.value);
|
|
2073
|
+
if (node) {
|
|
2074
|
+
node.focus();
|
|
2075
|
+
}
|
|
2076
|
+
}, []);
|
|
2077
|
+
const handleSelect = useCallback(
|
|
2078
|
+
(option) => {
|
|
2079
|
+
if (option.disabled || option.value === selectedValue) {
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2082
|
+
if (!isControlled) {
|
|
2083
|
+
setInternalValue(option.value);
|
|
2084
|
+
}
|
|
2085
|
+
if (typeof onChange === "function") {
|
|
2086
|
+
onChange(option.value, option);
|
|
2087
|
+
}
|
|
2088
|
+
},
|
|
2089
|
+
[isControlled, onChange, selectedValue]
|
|
2090
|
+
);
|
|
2091
|
+
const getNextEnabledIndex = useCallback(
|
|
2092
|
+
(startIndex, direction) => {
|
|
2093
|
+
if (!normalizedOptions.length) return -1;
|
|
2094
|
+
let nextIndex = startIndex;
|
|
2095
|
+
for (let i = 0; i < normalizedOptions.length; i += 1) {
|
|
2096
|
+
nextIndex = (nextIndex + direction + normalizedOptions.length) % normalizedOptions.length;
|
|
2097
|
+
if (!normalizedOptions[nextIndex].disabled) {
|
|
2098
|
+
return nextIndex;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
return startIndex;
|
|
2102
|
+
},
|
|
2103
|
+
[normalizedOptions]
|
|
2104
|
+
);
|
|
2105
|
+
const findFirstEnabledIndex = useCallback(() => {
|
|
2106
|
+
return normalizedOptions.findIndex((option) => !option.disabled);
|
|
2107
|
+
}, [normalizedOptions]);
|
|
2108
|
+
const findLastEnabledIndex = useCallback(() => {
|
|
2109
|
+
for (let i = normalizedOptions.length - 1; i >= 0; i -= 1) {
|
|
2110
|
+
if (!normalizedOptions[i].disabled) {
|
|
2111
|
+
return i;
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
return -1;
|
|
2115
|
+
}, [normalizedOptions]);
|
|
2116
|
+
const indicatorVisible = indicator.width > 0 && indicator.height > 0;
|
|
2117
|
+
const rootClasses = cx4(
|
|
2118
|
+
"inline-flex h-[44px] rounded-lg border-2 border-border-subtle bg-bg-base/90 p-2 shadow-inner",
|
|
2119
|
+
isStretched ? "w-full" : "w-auto",
|
|
2120
|
+
className
|
|
2121
|
+
);
|
|
2122
|
+
const trackClasses = cx4(
|
|
2123
|
+
"relative isolate flex w-full items-center gap-8",
|
|
2124
|
+
!isStretched && "w-auto"
|
|
2125
|
+
);
|
|
2126
|
+
const buttonBaseClasses = cx4(
|
|
2127
|
+
"relative z-10 h-[36px] 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",
|
|
2128
|
+
sizeStyles.button,
|
|
2129
|
+
isStretched ? "flex-1" : "w-auto"
|
|
2130
|
+
);
|
|
2131
|
+
return /* @__PURE__ */ jsx4(
|
|
2132
|
+
"div",
|
|
2133
|
+
{
|
|
2134
|
+
...rest,
|
|
2135
|
+
ref: setContainerRef,
|
|
2136
|
+
role: "radiogroup",
|
|
2137
|
+
className: rootClasses,
|
|
2138
|
+
children: /* @__PURE__ */ jsxs2("div", { className: trackClasses, children: [
|
|
2139
|
+
/* @__PURE__ */ jsx4(
|
|
2140
|
+
"span",
|
|
2141
|
+
{
|
|
2142
|
+
"aria-hidden": "true",
|
|
2143
|
+
className: cx4(
|
|
2144
|
+
"pointer-events-none h-[44px] 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",
|
|
2145
|
+
!indicatorVisible && "opacity-0"
|
|
2146
|
+
),
|
|
2147
|
+
style: {
|
|
2148
|
+
width: indicator.width || void 0,
|
|
2149
|
+
height: indicator.height || void 0,
|
|
2150
|
+
transform: `translate(${indicator.x - 4}px`
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
),
|
|
2154
|
+
normalizedOptions.map((option, index) => {
|
|
2155
|
+
const isActive = option.value === selectedValue;
|
|
2156
|
+
const handleKeyDown = (event) => {
|
|
2157
|
+
if (option.disabled) return;
|
|
2158
|
+
if (event.key === "ArrowRight" || event.key === "ArrowDown") {
|
|
2159
|
+
event.preventDefault();
|
|
2160
|
+
const nextIndex = getNextEnabledIndex(index, 1);
|
|
2161
|
+
const nextOption = normalizedOptions[nextIndex];
|
|
2162
|
+
if (nextOption && nextOption !== option) {
|
|
2163
|
+
focusOption(nextOption);
|
|
2164
|
+
handleSelect(nextOption);
|
|
2165
|
+
}
|
|
2166
|
+
} else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
|
|
2167
|
+
event.preventDefault();
|
|
2168
|
+
const prevIndex = getNextEnabledIndex(index, -1);
|
|
2169
|
+
const prevOption = normalizedOptions[prevIndex];
|
|
2170
|
+
if (prevOption && prevOption !== option) {
|
|
2171
|
+
focusOption(prevOption);
|
|
2172
|
+
handleSelect(prevOption);
|
|
2173
|
+
}
|
|
2174
|
+
} else if (event.key === "Home") {
|
|
2175
|
+
event.preventDefault();
|
|
2176
|
+
const firstIndex = findFirstEnabledIndex();
|
|
2177
|
+
const firstOption = firstIndex >= 0 ? normalizedOptions[firstIndex] : void 0;
|
|
2178
|
+
if (firstOption && firstOption !== option) {
|
|
2179
|
+
focusOption(firstOption);
|
|
2180
|
+
handleSelect(firstOption);
|
|
2181
|
+
}
|
|
2182
|
+
} else if (event.key === "End") {
|
|
2183
|
+
event.preventDefault();
|
|
2184
|
+
const lastIndex = findLastEnabledIndex();
|
|
2185
|
+
const lastOption = lastIndex >= 0 ? normalizedOptions[lastIndex] : void 0;
|
|
2186
|
+
if (lastOption && lastOption !== option) {
|
|
2187
|
+
focusOption(lastOption);
|
|
2188
|
+
handleSelect(lastOption);
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
};
|
|
2192
|
+
const buttonClasses = cx4(
|
|
2193
|
+
buttonBaseClasses,
|
|
2194
|
+
option.disabled ? "cursor-not-allowed text-fg-inactive opacity-60" : "cursor-pointer text-fg-subtle hover:text-fg-base",
|
|
2195
|
+
isActive && "text-fg-primary-emphasis",
|
|
2196
|
+
!isActive && "hover:bg-bg-minimal-5 active:bg-bg-inactive"
|
|
2197
|
+
);
|
|
2198
|
+
const hasStartAdornment = option.startAdornment !== void 0 && option.startAdornment !== null;
|
|
2199
|
+
const hasendIcon = option.endIcon !== void 0 && option.endIcon !== null;
|
|
2200
|
+
return /* @__PURE__ */ jsxs2(
|
|
2201
|
+
"button",
|
|
2202
|
+
{
|
|
2203
|
+
ref: registerButtonRef(option.value),
|
|
2204
|
+
type: "button",
|
|
2205
|
+
role: "radio",
|
|
2206
|
+
"aria-checked": isActive,
|
|
2207
|
+
disabled: option.disabled,
|
|
2208
|
+
className: buttonClasses,
|
|
2209
|
+
onClick: () => handleSelect(option),
|
|
2210
|
+
onKeyDown: handleKeyDown,
|
|
2211
|
+
"data-state": isActive ? "active" : "inactive",
|
|
2212
|
+
children: [
|
|
2213
|
+
hasStartAdornment && /* @__PURE__ */ jsx4(
|
|
2214
|
+
"span",
|
|
2215
|
+
{
|
|
2216
|
+
"aria-hidden": "true",
|
|
2217
|
+
className: "flex items-center text-current",
|
|
2218
|
+
children: option.startAdornment
|
|
2219
|
+
}
|
|
2220
|
+
),
|
|
2221
|
+
/* @__PURE__ */ jsx4("span", { className: "flex items-center gap-1 leading-none text-current", children: option.label ?? `Option ${index + 1}` }),
|
|
2222
|
+
hasendIcon && /* @__PURE__ */ jsx4(
|
|
2223
|
+
"span",
|
|
2224
|
+
{
|
|
2225
|
+
"aria-hidden": "true",
|
|
2226
|
+
className: "flex items-center text-current",
|
|
2227
|
+
children: option.endIcon
|
|
2228
|
+
}
|
|
2229
|
+
)
|
|
2230
|
+
]
|
|
2231
|
+
},
|
|
2232
|
+
String(option.value)
|
|
2233
|
+
);
|
|
2234
|
+
})
|
|
2235
|
+
] })
|
|
2236
|
+
}
|
|
2237
|
+
);
|
|
2238
|
+
});
|
|
2239
|
+
|
|
2240
|
+
// src/elements/ButtonGroupItem.jsx
|
|
2241
|
+
import React6 from "react";
|
|
2242
|
+
function ButtonGroupItem(_props) {
|
|
2243
|
+
return null;
|
|
1844
2244
|
}
|
|
2245
|
+
ButtonGroupItem.displayName = "ButtonGroupItem";
|
|
1845
2246
|
export {
|
|
1846
2247
|
Button,
|
|
2248
|
+
ButtonGroup,
|
|
2249
|
+
ButtonGroupItem,
|
|
2250
|
+
IconButton,
|
|
1847
2251
|
MenuButton
|
|
1848
2252
|
};
|
|
1849
2253
|
/*! Bundled license information:
|
package/package.json
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edux-design/buttons",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"**/*.css"
|
|
7
7
|
],
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
8
9
|
"exports": {
|
|
9
10
|
".": {
|
|
10
11
|
"import": "./dist/index.mjs",
|
|
11
|
-
"require": "./dist/index.js"
|
|
12
|
+
"require": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
12
14
|
}
|
|
13
15
|
},
|
|
14
16
|
"scripts": {
|
|
15
17
|
"lint": "eslint . --max-warnings 0",
|
|
16
|
-
"build": "tsup src/index.js --format esm,cjs",
|
|
17
|
-
"dev": "tsup src/index.js --watch --format esm,cjs",
|
|
18
|
+
"build": "tsup src/index.js --format esm,cjs --dts",
|
|
19
|
+
"dev": "tsup src/index.js --watch --format esm,cjs --dts",
|
|
18
20
|
"generate:component": "turbo gen react-component",
|
|
19
21
|
"check-types": "tsc --noEmit"
|
|
20
22
|
},
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Button, IconButton } from "./../index";
|
|
3
|
+
import { Close } 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
|
+
children: { control: "text" },
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Base template
|
|
23
|
+
const Template = (args) => <Button {...args} />;
|
|
24
|
+
|
|
25
|
+
// Default story
|
|
26
|
+
export const Primary = Template.bind({});
|
|
27
|
+
Primary.args = {
|
|
28
|
+
children: "Primary Button",
|
|
29
|
+
size: "medium",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Variants
|
|
33
|
+
export const Secondary = Template.bind({});
|
|
34
|
+
Secondary.args = {
|
|
35
|
+
children: "Secondary Button",
|
|
36
|
+
isSecondary: true,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const Danger = Template.bind({});
|
|
40
|
+
Danger.args = {
|
|
41
|
+
children: "Delete",
|
|
42
|
+
isDanger: true,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const Bare = Template.bind({});
|
|
46
|
+
Bare.args = {
|
|
47
|
+
children: "Bare Button",
|
|
48
|
+
isBare: true,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const Disabled = Template.bind({});
|
|
52
|
+
Disabled.args = {
|
|
53
|
+
children: "Disabled",
|
|
54
|
+
disabled: true,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Sizes
|
|
58
|
+
export const Small = Template.bind({});
|
|
59
|
+
Small.args = {
|
|
60
|
+
children: "Small",
|
|
61
|
+
size: "small",
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const Large = Template.bind({});
|
|
65
|
+
Large.args = {
|
|
66
|
+
children: "Large",
|
|
67
|
+
size: "large",
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Stretched (full width)
|
|
71
|
+
export const Stretched = Template.bind({});
|
|
72
|
+
Stretched.args = {
|
|
73
|
+
children: "Full Width",
|
|
74
|
+
isStretched: true,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const Default = () => (
|
|
78
|
+
<div className="flex gap-4 items-center">
|
|
79
|
+
<IconButton icon={<Close />} aria-label="Close" isBare />
|
|
80
|
+
<IconButton icon={<Close />} isSecondary aria-label="Close" />
|
|
81
|
+
<IconButton icon={<Close />} isDanger aria-label="Delete" />
|
|
82
|
+
<IconButton icon={<Close />} disabled aria-label="Disabled" />
|
|
83
|
+
</div>
|
|
84
|
+
);
|