@edux-design/buttons 0.1.4 → 0.3.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 +11 -6
- package/README.md +64 -48
- package/dist/index.d.mts +115 -19
- package/dist/index.d.ts +115 -19
- package/dist/index.js +401 -92
- package/dist/index.mjs +378 -68
- package/docs/toolbar.md +146 -0
- package/package.json +13 -25
package/dist/index.mjs
CHANGED
|
@@ -25,21 +25,29 @@ 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
|
-
const
|
|
31
|
-
small: "
|
|
32
|
-
medium: "
|
|
33
|
-
large: "
|
|
38
|
+
const sizes2 = {
|
|
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
|
-
primary: "border-2 border-border-primary-emphasis bg-bg-primary-base text-
|
|
44
|
+
primary: "border-2 border-border-primary-emphasis bg-bg-primary-base text-fg-invert 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",
|
|
37
45
|
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
46
|
bare: "bg-bg-base text-fg-primary-emphasis hover:bg-bg-minimal active:bg-bg-minimal-5",
|
|
39
47
|
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
48
|
disabled: "border-2 border-border-subtle bg-bg-inactive text-fg-inactive hover:no-underline cursor-not-allowed"
|
|
41
49
|
};
|
|
42
|
-
const STYLES = cx(defaults,
|
|
50
|
+
const STYLES = cx(defaults, sizes2[size], variants[variant], className);
|
|
43
51
|
return /* @__PURE__ */ jsx(
|
|
44
52
|
"button",
|
|
45
53
|
{
|
|
@@ -97,21 +105,21 @@ var Button = forwardRef2(
|
|
|
97
105
|
}
|
|
98
106
|
const defaults = "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";
|
|
99
107
|
const fonts = "text-bold tracking-normal hover:underline hover:underline-offset-(--underline-offset-btn) active:underline active:underline-offset-(--underline-offset-btn)";
|
|
100
|
-
const
|
|
108
|
+
const sizes2 = {
|
|
101
109
|
small: "h-control-sm py-8 px-16 rounded-lg text-sm",
|
|
102
110
|
medium: "h-control-md py-8 px-16 rounded-lg text-base",
|
|
103
111
|
large: "h-control-lg py-8 px-16 rounded-lg text-lg"
|
|
104
112
|
};
|
|
105
113
|
const width = isStretched ? "w-full" : "w-fit-content";
|
|
106
114
|
const variants = {
|
|
107
|
-
primary: "border-2 border-border-primary-emphasis bg-bg-primary-base text-
|
|
115
|
+
primary: "border-2 border-border-primary-emphasis bg-bg-primary-base text-fg-invert 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",
|
|
108
116
|
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",
|
|
109
117
|
bare: "bg-bg-base text-fg-primary-emphasis hover:bg-bg-minimal active:bg-bg-minimal-5",
|
|
110
118
|
dangerBare: "bg-bg-base text-fg-danger-emphasis hover:bg-bg-danger-subtle active:bg-bg-danger-subtle",
|
|
111
119
|
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",
|
|
112
120
|
disabled: "border-2 border-border-subtle bg-bg-inactive text-fg-inactive hover:no-underline"
|
|
113
121
|
};
|
|
114
|
-
const STYLES = cx2(defaults,
|
|
122
|
+
const STYLES = cx2(defaults, sizes2[size], width, fonts, variants[variant]);
|
|
115
123
|
return /* @__PURE__ */ jsxs(
|
|
116
124
|
"button",
|
|
117
125
|
{
|
|
@@ -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;
|
|
@@ -543,7 +575,7 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
543
575
|
(next) => {
|
|
544
576
|
const clamped = Math.min(max, Math.max(min, next));
|
|
545
577
|
if (!isControlled) setInternalValue(clamped);
|
|
546
|
-
onChange
|
|
578
|
+
onChange?.(clamped);
|
|
547
579
|
},
|
|
548
580
|
[isControlled, max, min, onChange]
|
|
549
581
|
);
|
|
@@ -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-48 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-56 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-72 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";
|
|
@@ -592,8 +624,8 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
592
624
|
const width = isStretched ? "w-full" : "w-fit-content";
|
|
593
625
|
const variants = {
|
|
594
626
|
primary: {
|
|
595
|
-
button: "border-2 border-border-primary-emphasis bg-bg-primary-base text-
|
|
596
|
-
display: "border-y-2 border-x-2 border-border-primary-emphasis bg-bg-primary-base text-
|
|
627
|
+
button: "border-2 border-border-primary-emphasis bg-bg-primary-base text-fg-invert 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",
|
|
628
|
+
display: "border-y-2 border-x-2 border-border-primary-emphasis bg-bg-primary-base text-fg-invert"
|
|
597
629
|
},
|
|
598
630
|
secondary: {
|
|
599
631
|
button: "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",
|
|
@@ -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?.id ?? generatedValueId;
|
|
679
|
+
const valueAriaLabel = 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);
|
|
@@ -674,17 +709,17 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
674
709
|
{
|
|
675
710
|
...decrementButtonProps,
|
|
676
711
|
type: "button",
|
|
677
|
-
"aria-label":
|
|
712
|
+
"aria-label": decrementButtonProps?.["aria-label"] ?? "Decrease",
|
|
713
|
+
"aria-controls": valueElementId,
|
|
678
714
|
"aria-disabled": decrementDisabled,
|
|
679
715
|
disabled: decrementDisabled,
|
|
680
716
|
className: cx5(
|
|
681
717
|
leftButtonStyles,
|
|
682
718
|
decrementDisabled && variant !== "disabled" ? variants.disabled.button : null,
|
|
683
|
-
decrementButtonProps
|
|
719
|
+
decrementButtonProps?.className
|
|
684
720
|
),
|
|
685
721
|
onClick: (event) => {
|
|
686
|
-
|
|
687
|
-
(_a = decrementButtonProps == null ? void 0 : decrementButtonProps.onClick) == null ? void 0 : _a.call(decrementButtonProps, event);
|
|
722
|
+
decrementButtonProps?.onClick?.(event);
|
|
688
723
|
if (event.defaultPrevented) return;
|
|
689
724
|
commitValue(clampedValue - step);
|
|
690
725
|
},
|
|
@@ -698,38 +733,35 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
698
733
|
ref: inputRef,
|
|
699
734
|
type: "number",
|
|
700
735
|
inputMode: "numeric",
|
|
736
|
+
id: valueElementId,
|
|
701
737
|
disabled: !!disabled,
|
|
702
|
-
"aria-label":
|
|
738
|
+
"aria-label": valueAriaLabel,
|
|
703
739
|
className: cx5(
|
|
704
740
|
displayStyles,
|
|
705
|
-
"w-
|
|
741
|
+
"w-control-md text-center outline-none bg-transparent text-fg-base",
|
|
706
742
|
"[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",
|
|
707
743
|
"focus:shadow-focus focus-visible:shadow-focus focus:z-15 focus-within:z-15",
|
|
708
|
-
inputProps
|
|
744
|
+
inputProps?.className
|
|
709
745
|
),
|
|
710
746
|
value: draftValue,
|
|
711
747
|
onChange: (event) => {
|
|
712
|
-
|
|
713
|
-
(_a = inputProps == null ? void 0 : inputProps.onChange) == null ? void 0 : _a.call(inputProps, event);
|
|
748
|
+
inputProps?.onChange?.(event);
|
|
714
749
|
if (event.defaultPrevented) return;
|
|
715
750
|
setDraftValue(event.target.value);
|
|
716
751
|
},
|
|
717
752
|
onFocus: (event) => {
|
|
718
|
-
|
|
719
|
-
(_a = inputProps == null ? void 0 : inputProps.onFocus) == null ? void 0 : _a.call(inputProps, event);
|
|
753
|
+
inputProps?.onFocus?.(event);
|
|
720
754
|
if (event.defaultPrevented) return;
|
|
721
755
|
setIsEditing(true);
|
|
722
756
|
},
|
|
723
757
|
onBlur: (event) => {
|
|
724
|
-
|
|
725
|
-
(_a = inputProps == null ? void 0 : inputProps.onBlur) == null ? void 0 : _a.call(inputProps, event);
|
|
758
|
+
inputProps?.onBlur?.(event);
|
|
726
759
|
if (event.defaultPrevented) return;
|
|
727
760
|
setIsEditing(false);
|
|
728
761
|
commitDraft();
|
|
729
762
|
},
|
|
730
763
|
onKeyDown: (event) => {
|
|
731
|
-
|
|
732
|
-
(_a = inputProps == null ? void 0 : inputProps.onKeyDown) == null ? void 0 : _a.call(inputProps, event);
|
|
764
|
+
inputProps?.onKeyDown?.(event);
|
|
733
765
|
if (event.defaultPrevented) return;
|
|
734
766
|
if (event.key === "Enter") {
|
|
735
767
|
event.currentTarget.blur();
|
|
@@ -740,23 +772,33 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
740
772
|
}
|
|
741
773
|
}
|
|
742
774
|
}
|
|
743
|
-
) : /* @__PURE__ */ jsx6(
|
|
775
|
+
) : /* @__PURE__ */ jsx6(
|
|
776
|
+
"output",
|
|
777
|
+
{
|
|
778
|
+
id: valueElementId,
|
|
779
|
+
"aria-label": valueAriaLabel,
|
|
780
|
+
"aria-live": "polite",
|
|
781
|
+
"aria-atomic": "true",
|
|
782
|
+
className: cx5(displayStyles, "select-none"),
|
|
783
|
+
children: children ?? clampedValue
|
|
784
|
+
}
|
|
785
|
+
),
|
|
744
786
|
/* @__PURE__ */ jsx6(
|
|
745
787
|
"button",
|
|
746
788
|
{
|
|
747
789
|
...incrementButtonProps,
|
|
748
790
|
type: "button",
|
|
749
|
-
"aria-label":
|
|
791
|
+
"aria-label": incrementButtonProps?.["aria-label"] ?? "Increase",
|
|
792
|
+
"aria-controls": valueElementId,
|
|
750
793
|
"aria-disabled": incrementDisabled,
|
|
751
794
|
disabled: incrementDisabled,
|
|
752
795
|
className: cx5(
|
|
753
796
|
rightButtonStyles,
|
|
754
797
|
incrementDisabled && variant !== "disabled" ? variants.disabled.button : null,
|
|
755
|
-
incrementButtonProps
|
|
798
|
+
incrementButtonProps?.className
|
|
756
799
|
),
|
|
757
800
|
onClick: (event) => {
|
|
758
|
-
|
|
759
|
-
(_a = incrementButtonProps == null ? void 0 : incrementButtonProps.onClick) == null ? void 0 : _a.call(incrementButtonProps, event);
|
|
801
|
+
incrementButtonProps?.onClick?.(event);
|
|
760
802
|
if (event.defaultPrevented) return;
|
|
761
803
|
commitValue(clampedValue + step);
|
|
762
804
|
},
|
|
@@ -767,11 +809,279 @@ var ButtonCounter = forwardRef4(function ButtonCounter2({
|
|
|
767
809
|
}
|
|
768
810
|
);
|
|
769
811
|
});
|
|
812
|
+
|
|
813
|
+
// src/elements/Toolbar.tsx
|
|
814
|
+
import {
|
|
815
|
+
forwardRef as forwardRef6,
|
|
816
|
+
useEffect as useEffect3,
|
|
817
|
+
useImperativeHandle,
|
|
818
|
+
useRef as useRef3
|
|
819
|
+
} from "react";
|
|
820
|
+
import { cx as cx6 } from "@edux-design/utils";
|
|
821
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
822
|
+
function toolbarButtons(root) {
|
|
823
|
+
return Array.from(
|
|
824
|
+
root.querySelectorAll("[data-edux-toolbar-button]")
|
|
825
|
+
).filter((button) => {
|
|
826
|
+
if (button.closest("[data-edux-toolbar]") !== root) return false;
|
|
827
|
+
if (button.disabled || button.getAttribute("aria-disabled") === "true")
|
|
828
|
+
return false;
|
|
829
|
+
for (let node = button; node; node = node.parentElement) {
|
|
830
|
+
if (node.hidden || node.hasAttribute("inert") || node.getAttribute("aria-hidden") === "true")
|
|
831
|
+
return false;
|
|
832
|
+
const styles = node.ownerDocument.defaultView?.getComputedStyle(node);
|
|
833
|
+
if (styles?.display === "none" || styles?.visibility === "hidden")
|
|
834
|
+
return false;
|
|
835
|
+
if (node === root) break;
|
|
836
|
+
}
|
|
837
|
+
return true;
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
var Toolbar = forwardRef6(
|
|
841
|
+
function Toolbar2({
|
|
842
|
+
keyboardNavigation = "native",
|
|
843
|
+
orientation = "horizontal",
|
|
844
|
+
loop = true,
|
|
845
|
+
className,
|
|
846
|
+
children,
|
|
847
|
+
onKeyDown,
|
|
848
|
+
onFocusCapture,
|
|
849
|
+
...props
|
|
850
|
+
}, forwardedRef) {
|
|
851
|
+
const rootRef = useRef3(null);
|
|
852
|
+
useImperativeHandle(forwardedRef, () => rootRef.current);
|
|
853
|
+
const lastFocused = useRef3(null);
|
|
854
|
+
const originalTabIndexes = useRef3(
|
|
855
|
+
/* @__PURE__ */ new Map()
|
|
856
|
+
);
|
|
857
|
+
function syncTabStops() {
|
|
858
|
+
const root = rootRef.current;
|
|
859
|
+
if (!root || keyboardNavigation !== "roving") return;
|
|
860
|
+
const buttons = toolbarButtons(root);
|
|
861
|
+
const active = buttons.includes(lastFocused.current) ? lastFocused.current : buttons[0];
|
|
862
|
+
root.querySelectorAll("[data-edux-toolbar-button]").forEach((button) => {
|
|
863
|
+
const nextTabIndex = button === active ? 0 : -1;
|
|
864
|
+
if (button.closest("[data-edux-toolbar]") !== root) return;
|
|
865
|
+
if (!originalTabIndexes.current.has(button))
|
|
866
|
+
originalTabIndexes.current.set(
|
|
867
|
+
button,
|
|
868
|
+
button.getAttribute("tabindex")
|
|
869
|
+
);
|
|
870
|
+
if (button.tabIndex !== nextTabIndex) button.tabIndex = nextTabIndex;
|
|
871
|
+
});
|
|
872
|
+
lastFocused.current = active ?? null;
|
|
873
|
+
}
|
|
874
|
+
useEffect3(() => {
|
|
875
|
+
const root = rootRef.current;
|
|
876
|
+
if (!root || keyboardNavigation !== "roving") return;
|
|
877
|
+
syncTabStops();
|
|
878
|
+
const observer = typeof MutationObserver === "undefined" ? null : new MutationObserver(syncTabStops);
|
|
879
|
+
observer?.observe(root, {
|
|
880
|
+
subtree: true,
|
|
881
|
+
childList: true,
|
|
882
|
+
attributes: true,
|
|
883
|
+
attributeFilter: [
|
|
884
|
+
"disabled",
|
|
885
|
+
"aria-disabled",
|
|
886
|
+
"hidden",
|
|
887
|
+
"inert",
|
|
888
|
+
"aria-hidden",
|
|
889
|
+
"class",
|
|
890
|
+
"style",
|
|
891
|
+
"tabindex"
|
|
892
|
+
]
|
|
893
|
+
});
|
|
894
|
+
return () => {
|
|
895
|
+
observer?.disconnect();
|
|
896
|
+
originalTabIndexes.current.forEach((value, button) => {
|
|
897
|
+
if (value === null) button.removeAttribute("tabindex");
|
|
898
|
+
else button.setAttribute("tabindex", value);
|
|
899
|
+
});
|
|
900
|
+
originalTabIndexes.current.clear();
|
|
901
|
+
};
|
|
902
|
+
}, [keyboardNavigation]);
|
|
903
|
+
return /* @__PURE__ */ jsx7(
|
|
904
|
+
"div",
|
|
905
|
+
{
|
|
906
|
+
...props,
|
|
907
|
+
ref: rootRef,
|
|
908
|
+
role: "toolbar",
|
|
909
|
+
"aria-orientation": orientation,
|
|
910
|
+
"data-edux-toolbar": "",
|
|
911
|
+
className: cx6(
|
|
912
|
+
"flex min-w-0 flex-wrap gap-8",
|
|
913
|
+
orientation === "vertical" ? "flex-col items-start" : "items-center",
|
|
914
|
+
className
|
|
915
|
+
),
|
|
916
|
+
onFocusCapture: (event) => {
|
|
917
|
+
onFocusCapture?.(event);
|
|
918
|
+
const target = event.target;
|
|
919
|
+
if (target instanceof HTMLButtonElement && target.closest("[data-edux-toolbar]") === event.currentTarget) {
|
|
920
|
+
if (toolbarButtons(event.currentTarget).includes(target))
|
|
921
|
+
lastFocused.current = target;
|
|
922
|
+
syncTabStops();
|
|
923
|
+
}
|
|
924
|
+
},
|
|
925
|
+
onKeyDown: (event) => {
|
|
926
|
+
onKeyDown?.(event);
|
|
927
|
+
if (keyboardNavigation !== "roving" || event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
|
|
928
|
+
return;
|
|
929
|
+
const root = event.currentTarget;
|
|
930
|
+
const target = event.target;
|
|
931
|
+
if (!(target instanceof HTMLButtonElement) || target.closest("[data-edux-toolbar]") !== root)
|
|
932
|
+
return;
|
|
933
|
+
const buttons = toolbarButtons(root);
|
|
934
|
+
const index = buttons.indexOf(target);
|
|
935
|
+
if (index === -1) return;
|
|
936
|
+
let next;
|
|
937
|
+
if (event.key === "Home") next = 0;
|
|
938
|
+
else if (event.key === "End") next = buttons.length - 1;
|
|
939
|
+
else {
|
|
940
|
+
const directionValue = root.ownerDocument.defaultView?.getComputedStyle(root).direction || root.closest("[dir]")?.getAttribute("dir");
|
|
941
|
+
const rtl = directionValue === "rtl";
|
|
942
|
+
const forward = orientation === "vertical" ? "ArrowDown" : rtl ? "ArrowLeft" : "ArrowRight";
|
|
943
|
+
const backward = orientation === "vertical" ? "ArrowUp" : rtl ? "ArrowRight" : "ArrowLeft";
|
|
944
|
+
if (event.key !== forward && event.key !== backward) return;
|
|
945
|
+
const direction = event.key === forward ? 1 : -1;
|
|
946
|
+
next = loop ? (index + direction + buttons.length) % buttons.length : Math.max(0, Math.min(buttons.length - 1, index + direction));
|
|
947
|
+
}
|
|
948
|
+
event.preventDefault();
|
|
949
|
+
buttons[next]?.focus();
|
|
950
|
+
},
|
|
951
|
+
children
|
|
952
|
+
}
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
);
|
|
956
|
+
var ToolbarGroup = forwardRef6(
|
|
957
|
+
function ToolbarGroup2({ orientation = "horizontal", className, ...props }, ref) {
|
|
958
|
+
return /* @__PURE__ */ jsx7(
|
|
959
|
+
"div",
|
|
960
|
+
{
|
|
961
|
+
...props,
|
|
962
|
+
ref,
|
|
963
|
+
role: "group",
|
|
964
|
+
className: cx6(
|
|
965
|
+
"inline-flex gap-4",
|
|
966
|
+
orientation === "vertical" ? "flex-col" : "flex-wrap items-center",
|
|
967
|
+
className
|
|
968
|
+
)
|
|
969
|
+
}
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
);
|
|
973
|
+
var ToolbarSeparator = forwardRef6(function ToolbarSeparator2({ orientation = "vertical", className, ...props }, ref) {
|
|
974
|
+
return /* @__PURE__ */ jsx7(
|
|
975
|
+
"div",
|
|
976
|
+
{
|
|
977
|
+
...props,
|
|
978
|
+
ref,
|
|
979
|
+
role: "separator",
|
|
980
|
+
"aria-orientation": orientation,
|
|
981
|
+
className: cx6(
|
|
982
|
+
"shrink-0 border-border-subtle",
|
|
983
|
+
orientation === "vertical" ? "h-control-sm border-l" : "w-full border-t",
|
|
984
|
+
className
|
|
985
|
+
)
|
|
986
|
+
}
|
|
987
|
+
);
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
// src/elements/ToolbarButton.tsx
|
|
991
|
+
import { forwardRef as forwardRef7, useState as useState3 } from "react";
|
|
992
|
+
import { cx as cx7 } from "@edux-design/utils";
|
|
993
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
994
|
+
var sizes = {
|
|
995
|
+
small: "h-control-sm min-w-control-sm text-sm",
|
|
996
|
+
medium: "h-control-md min-w-control-md text-base",
|
|
997
|
+
large: "h-control-lg min-w-control-lg text-lg"
|
|
998
|
+
};
|
|
999
|
+
var ToolbarButton = forwardRef7(
|
|
1000
|
+
function ToolbarButton2({
|
|
1001
|
+
active = false,
|
|
1002
|
+
size = "small",
|
|
1003
|
+
variant = "neutral",
|
|
1004
|
+
icon,
|
|
1005
|
+
iconOnly = false,
|
|
1006
|
+
children,
|
|
1007
|
+
className,
|
|
1008
|
+
type = "button",
|
|
1009
|
+
onClick,
|
|
1010
|
+
...props
|
|
1011
|
+
}, ref) {
|
|
1012
|
+
const pressed = active || props["aria-pressed"] === true || props["aria-pressed"] === "true" || props["aria-pressed"] === "mixed";
|
|
1013
|
+
const disabled = props.disabled || props["aria-disabled"] === true || props["aria-disabled"] === "true";
|
|
1014
|
+
const colours = {
|
|
1015
|
+
neutral: pressed ? "border-border-primary-base bg-bg-primary-subtle text-fg-primary-emphasis" : "border-transparent bg-transparent text-fg-base hover:bg-bg-minimal active:bg-bg-inactive",
|
|
1016
|
+
primary: pressed ? "border-border-primary-emphasis bg-bg-primary-subtle text-fg-primary-emphasis" : "border-transparent bg-transparent text-fg-primary-emphasis hover:bg-bg-primary-subtle active:bg-bg-primary-subtle-90",
|
|
1017
|
+
danger: pressed ? "border-border-danger-emphasis bg-bg-danger-subtle text-fg-danger-emphasis" : "border-transparent bg-transparent text-fg-danger-emphasis hover:bg-bg-danger-subtle active:bg-bg-danger-subtle"
|
|
1018
|
+
};
|
|
1019
|
+
return /* @__PURE__ */ jsxs6(
|
|
1020
|
+
"button",
|
|
1021
|
+
{
|
|
1022
|
+
"aria-pressed": active ? true : void 0,
|
|
1023
|
+
...props,
|
|
1024
|
+
ref,
|
|
1025
|
+
type,
|
|
1026
|
+
"data-edux-toolbar-button": "",
|
|
1027
|
+
"data-state": pressed ? "on" : "off",
|
|
1028
|
+
className: cx7(
|
|
1029
|
+
"inline-flex shrink-0 items-center justify-center gap-8 whitespace-nowrap rounded-md border-2 font-semibold cursor-pointer outline-none transition-colors duration-150 motion-reduce:transition-none focus-visible:shadow-focus disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50",
|
|
1030
|
+
sizes[size],
|
|
1031
|
+
iconOnly ? "aspect-square p-0" : "px-8",
|
|
1032
|
+
disabled ? "border-border-subtle bg-bg-inactive text-fg-inactive" : colours[variant],
|
|
1033
|
+
className
|
|
1034
|
+
),
|
|
1035
|
+
onClick: (event) => {
|
|
1036
|
+
if (disabled) {
|
|
1037
|
+
event.preventDefault();
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
onClick?.(event);
|
|
1041
|
+
},
|
|
1042
|
+
children: [
|
|
1043
|
+
icon && /* @__PURE__ */ jsx8(
|
|
1044
|
+
"span",
|
|
1045
|
+
{
|
|
1046
|
+
"aria-hidden": "true",
|
|
1047
|
+
className: "inline-flex shrink-0 items-center",
|
|
1048
|
+
children: icon
|
|
1049
|
+
}
|
|
1050
|
+
),
|
|
1051
|
+
children
|
|
1052
|
+
]
|
|
1053
|
+
}
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
);
|
|
1057
|
+
var ToolbarToggleButton = forwardRef7(function ToolbarToggleButton2({ pressed, defaultPressed = false, onPressedChange, onClick, ...props }, ref) {
|
|
1058
|
+
const [internalPressed, setInternalPressed] = useState3(defaultPressed);
|
|
1059
|
+
const isPressed = pressed ?? internalPressed;
|
|
1060
|
+
return /* @__PURE__ */ jsx8(
|
|
1061
|
+
ToolbarButton,
|
|
1062
|
+
{
|
|
1063
|
+
...props,
|
|
1064
|
+
ref,
|
|
1065
|
+
"aria-pressed": isPressed,
|
|
1066
|
+
onClick: (event) => {
|
|
1067
|
+
onClick?.(event);
|
|
1068
|
+
if (event.defaultPrevented) return;
|
|
1069
|
+
if (pressed === void 0) setInternalPressed(!isPressed);
|
|
1070
|
+
onPressedChange?.(!isPressed, event);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
);
|
|
1074
|
+
});
|
|
770
1075
|
export {
|
|
771
1076
|
Button,
|
|
772
1077
|
ButtonCounter,
|
|
773
1078
|
ButtonGroup,
|
|
774
1079
|
ButtonGroupItem,
|
|
775
1080
|
IconButton,
|
|
776
|
-
MenuButton
|
|
1081
|
+
MenuButton,
|
|
1082
|
+
Toolbar,
|
|
1083
|
+
ToolbarButton,
|
|
1084
|
+
ToolbarGroup,
|
|
1085
|
+
ToolbarSeparator,
|
|
1086
|
+
ToolbarToggleButton
|
|
777
1087
|
};
|