beez-ui 0.10.0 → 2.0.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 +40 -1
- package/README.md +63 -16
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/assets/fonts/ibmplexmono-LICENSE.txt +93 -93
- package/assets/fonts/{poppins-LICENSE.txt → inter-LICENSE.txt} +2 -2
- package/assets/fonts/inter-latin-variable.woff2 +0 -0
- package/dist/components/account-menu.d.ts +5 -2
- package/dist/components/account-menu.js +150 -145
- package/dist/components/alert-dialog.d.ts +4 -2
- package/dist/components/alert-dialog.js +78 -66
- package/dist/components/animated-collapse.js +106 -36
- package/dist/components/button-interaction.d.ts +23 -0
- package/dist/components/button-interaction.js +22 -0
- package/dist/components/button-label.d.ts +8 -0
- package/dist/components/button-label.js +322 -0
- package/dist/components/button.d.ts +23 -10
- package/dist/components/button.js +111 -64
- package/dist/components/calendar.d.ts +2 -2
- package/dist/components/calendar.js +4 -4
- package/dist/components/carousel.d.ts +3 -3
- package/dist/components/carousel.js +3 -3
- package/dist/components/control-button.d.ts +16 -0
- package/dist/components/control-button.js +215 -0
- package/dist/components/data-table.js +7 -7
- package/dist/components/dialog.js +3 -2
- package/dist/components/dropdown-menu.js +1 -1
- package/dist/components/file-upload.js +5 -5
- package/dist/components/filter-presets-bar.js +6 -6
- package/dist/components/filter-query-bar.js +2 -2
- package/dist/components/input-group.d.ts +2 -2
- package/dist/components/input-group.js +2 -2
- package/dist/components/pagination.d.ts +2 -2
- package/dist/components/pagination.js +2 -2
- package/dist/components/reaction-button.js +2 -2
- package/dist/components/rich-link-editor.js +7 -7
- package/dist/components/rich-text-content.js +1 -1
- package/dist/components/sheet.js +2 -2
- package/dist/components/sidebar-panel-context.d.ts +17 -0
- package/dist/components/sidebar-panel-context.js +14 -0
- package/dist/components/sidebar.d.ts +40 -3
- package/dist/components/sidebar.js +259 -103
- package/dist/components/typing-animation.js +1 -1
- package/dist/constants/button.d.ts +16 -0
- package/dist/constants/button.js +16 -0
- package/dist/hooks/use-sidebar-persistence.d.ts +1 -1
- package/dist/hooks/use-sidebar-persistence.js +2 -2
- package/dist/motion/arc-press.d.ts +6 -0
- package/dist/motion/arc-press.js +59 -0
- package/dist/motion/arc-tokens.d.ts +32 -0
- package/dist/motion/arc-tokens.js +42 -0
- package/dist/providers/beez-ui-provider.d.ts +1 -1
- package/dist/providers/beez-ui-provider.js +6 -1
- package/dist/styles.css +1 -1
- package/fonts.css +5 -5
- package/package.json +3 -2
- package/styles.css +4 -4
- package/theme.css +248 -87
- package/assets/fonts/poppins-latin-600.woff2 +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { c as _c } from "react/compiler-runtime";
|
|
3
3
|
/** Expands and collapses a region by animating its height, then releases overflow. */
|
|
4
4
|
import { useState } from "react";
|
|
5
|
-
import { AnimatePresence, motion } from "motion/react";
|
|
5
|
+
import { AnimatePresence, motion, useIsPresent } from "motion/react";
|
|
6
6
|
import { usePrefersReducedMotion } from "../hooks/use-prefers-reduced-motion.js";
|
|
7
7
|
import { cn } from "../lib/utils.js";
|
|
8
8
|
import { MOTION_EASE, MOTION_EASE_IN_OUT, MOTION_TIMING } from "../motion/tokens.js";
|
|
@@ -26,6 +26,94 @@ const REDUCED_MOTION_COLLAPSE_TRANSITION = {
|
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
/**
|
|
29
|
+
* The animated region. While it collapses out it turns inert and hidden from assistive
|
|
30
|
+
* technology, so stale controls cannot be clicked, focused or announced during the fade.
|
|
31
|
+
* @param props - Content, optional wrapper attributes and whether it mounts with an entrance.
|
|
32
|
+
* @returns The animated region.
|
|
33
|
+
*/
|
|
34
|
+
function AnimatedCollapseRegion(t0) {
|
|
35
|
+
const $ = _c(15);
|
|
36
|
+
const { children, className, id, isEntering } = t0;
|
|
37
|
+
const [isSettled, setIsSettled] = useState(!isEntering);
|
|
38
|
+
const isPresent = useIsPresent();
|
|
39
|
+
const shouldReduceMotion = usePrefersReducedMotion();
|
|
40
|
+
const t1 = isPresent ? undefined : true;
|
|
41
|
+
const t2 = !isPresent || undefined;
|
|
42
|
+
const t3 = isSettled ? "overflow-visible" : "overflow-hidden";
|
|
43
|
+
let t4;
|
|
44
|
+
if ($[0] !== className || $[1] !== t3) {
|
|
45
|
+
t4 = cn(t3, className);
|
|
46
|
+
$[0] = className;
|
|
47
|
+
$[1] = t3;
|
|
48
|
+
$[2] = t4;
|
|
49
|
+
} else {
|
|
50
|
+
t4 = $[2];
|
|
51
|
+
}
|
|
52
|
+
let t5;
|
|
53
|
+
let t6;
|
|
54
|
+
let t7;
|
|
55
|
+
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
|
56
|
+
t5 = {
|
|
57
|
+
height: 0,
|
|
58
|
+
opacity: 0
|
|
59
|
+
};
|
|
60
|
+
t6 = {
|
|
61
|
+
height: "auto",
|
|
62
|
+
opacity: 1
|
|
63
|
+
};
|
|
64
|
+
t7 = {
|
|
65
|
+
height: 0,
|
|
66
|
+
opacity: 0
|
|
67
|
+
};
|
|
68
|
+
$[3] = t5;
|
|
69
|
+
$[4] = t6;
|
|
70
|
+
$[5] = t7;
|
|
71
|
+
} else {
|
|
72
|
+
t5 = $[3];
|
|
73
|
+
t6 = $[4];
|
|
74
|
+
t7 = $[5];
|
|
75
|
+
}
|
|
76
|
+
const t8 = shouldReduceMotion ? REDUCED_MOTION_COLLAPSE_TRANSITION : COLLAPSE_TRANSITION;
|
|
77
|
+
let t10;
|
|
78
|
+
let t9;
|
|
79
|
+
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
|
|
80
|
+
t9 = () => setIsSettled(false);
|
|
81
|
+
t10 = () => setIsSettled(true);
|
|
82
|
+
$[6] = t10;
|
|
83
|
+
$[7] = t9;
|
|
84
|
+
} else {
|
|
85
|
+
t10 = $[6];
|
|
86
|
+
t9 = $[7];
|
|
87
|
+
}
|
|
88
|
+
let t11;
|
|
89
|
+
if ($[8] !== children || $[9] !== id || $[10] !== t1 || $[11] !== t2 || $[12] !== t4 || $[13] !== t8) {
|
|
90
|
+
t11 = /* @__PURE__ */ _jsx(motion.div, {
|
|
91
|
+
"data-slot": "animated-collapse",
|
|
92
|
+
id,
|
|
93
|
+
"aria-hidden": t1,
|
|
94
|
+
inert: t2,
|
|
95
|
+
className: t4,
|
|
96
|
+
initial: t5,
|
|
97
|
+
animate: t6,
|
|
98
|
+
exit: t7,
|
|
99
|
+
transition: t8,
|
|
100
|
+
onAnimationStart: t9,
|
|
101
|
+
onAnimationComplete: t10,
|
|
102
|
+
children
|
|
103
|
+
});
|
|
104
|
+
$[8] = children;
|
|
105
|
+
$[9] = id;
|
|
106
|
+
$[10] = t1;
|
|
107
|
+
$[11] = t2;
|
|
108
|
+
$[12] = t4;
|
|
109
|
+
$[13] = t8;
|
|
110
|
+
$[14] = t11;
|
|
111
|
+
} else {
|
|
112
|
+
t11 = $[14];
|
|
113
|
+
}
|
|
114
|
+
return t11;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
29
117
|
* Renders `children` only while `isOpen`, animating height and opacity.
|
|
30
118
|
* Keep padding inside `children`: the animated wrapper collapses to zero height.
|
|
31
119
|
* Overflow is clipped only while animating, so focus rings and popovers are not cut once settled.
|
|
@@ -33,55 +121,37 @@ const REDUCED_MOTION_COLLAPSE_TRANSITION = {
|
|
|
33
121
|
* @returns The animated region, or nothing when closed.
|
|
34
122
|
*/
|
|
35
123
|
export function AnimatedCollapse(t0) {
|
|
36
|
-
const $ = _c(
|
|
124
|
+
const $ = _c(9);
|
|
37
125
|
const { isOpen, children, className, id, animateOnMount: t1 } = t0;
|
|
38
126
|
const animateOnMount = t1 === undefined ? false : t1;
|
|
39
|
-
const [isSettled, setIsSettled] = useState(!animateOnMount);
|
|
40
|
-
const shouldReduceMotion = usePrefersReducedMotion();
|
|
41
127
|
let t2;
|
|
42
|
-
if ($[0] !==
|
|
43
|
-
t2 = isOpen ? /* @__PURE__ */ _jsx(
|
|
44
|
-
|
|
128
|
+
if ($[0] !== animateOnMount || $[1] !== children || $[2] !== className || $[3] !== id || $[4] !== isOpen) {
|
|
129
|
+
t2 = isOpen ? /* @__PURE__ */ _jsx(AnimatedCollapseRegion, {
|
|
130
|
+
className,
|
|
45
131
|
id,
|
|
46
|
-
|
|
47
|
-
initial: {
|
|
48
|
-
height: 0,
|
|
49
|
-
opacity: 0
|
|
50
|
-
},
|
|
51
|
-
animate: {
|
|
52
|
-
height: "auto",
|
|
53
|
-
opacity: 1
|
|
54
|
-
},
|
|
55
|
-
exit: {
|
|
56
|
-
height: 0,
|
|
57
|
-
opacity: 0
|
|
58
|
-
},
|
|
59
|
-
transition: shouldReduceMotion ? REDUCED_MOTION_COLLAPSE_TRANSITION : COLLAPSE_TRANSITION,
|
|
60
|
-
onAnimationStart: () => setIsSettled(false),
|
|
61
|
-
onAnimationComplete: () => setIsSettled(true),
|
|
132
|
+
isEntering: animateOnMount,
|
|
62
133
|
children
|
|
63
134
|
}, "animated-collapse") : null;
|
|
64
|
-
$[0] =
|
|
65
|
-
$[1] =
|
|
66
|
-
$[2] =
|
|
67
|
-
$[3] =
|
|
68
|
-
$[4] =
|
|
69
|
-
$[5] =
|
|
70
|
-
$[6] = t2;
|
|
135
|
+
$[0] = animateOnMount;
|
|
136
|
+
$[1] = children;
|
|
137
|
+
$[2] = className;
|
|
138
|
+
$[3] = id;
|
|
139
|
+
$[4] = isOpen;
|
|
140
|
+
$[5] = t2;
|
|
71
141
|
} else {
|
|
72
|
-
t2 = $[
|
|
142
|
+
t2 = $[5];
|
|
73
143
|
}
|
|
74
144
|
let t3;
|
|
75
|
-
if ($[
|
|
145
|
+
if ($[6] !== animateOnMount || $[7] !== t2) {
|
|
76
146
|
t3 = /* @__PURE__ */ _jsx(AnimatePresence, {
|
|
77
147
|
initial: animateOnMount,
|
|
78
148
|
children: t2
|
|
79
149
|
});
|
|
80
|
-
$[
|
|
81
|
-
$[
|
|
82
|
-
$[
|
|
150
|
+
$[6] = animateOnMount;
|
|
151
|
+
$[7] = t2;
|
|
152
|
+
$[8] = t3;
|
|
83
153
|
} else {
|
|
84
|
-
t3 = $[
|
|
154
|
+
t3 = $[8];
|
|
85
155
|
}
|
|
86
156
|
return t3;
|
|
87
157
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Interaction states shared by `Button` and the internal `ControlButton`. */
|
|
2
|
+
import type { MouseEvent } from "react";
|
|
3
|
+
/** Swallows activation while loading, keeping the button focusable instead of disabling it. */
|
|
4
|
+
declare function preventActivation(event: MouseEvent<HTMLElement>): void;
|
|
5
|
+
/**
|
|
6
|
+
* While loading, these handlers are dropped: Radix triggers open their layer from pointer and key handlers they
|
|
7
|
+
* inject through `asChild`, so swallowing only the click would leave a busy trigger able to open it. Keyboard focus
|
|
8
|
+
* stays, since nothing here touches focusability.
|
|
9
|
+
*/
|
|
10
|
+
export declare const LOADING_INERT_HANDLERS: {
|
|
11
|
+
readonly onClick: typeof preventActivation;
|
|
12
|
+
readonly onPointerDown: undefined;
|
|
13
|
+
readonly onKeyDown: undefined;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Applied while a parent `AnimatePresence` removes the button, so a stale control can be neither clicked, focused
|
|
17
|
+
* nor announced during the exit animation.
|
|
18
|
+
*/
|
|
19
|
+
export declare const LEAVING_ATTRIBUTES: {
|
|
20
|
+
readonly inert: true;
|
|
21
|
+
readonly "aria-hidden": true;
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Swallows activation while loading, keeping the button focusable instead of disabling it. */
|
|
2
|
+
function preventActivation(event) {
|
|
3
|
+
event.preventDefault();
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* While loading, these handlers are dropped: Radix triggers open their layer from pointer and key handlers they
|
|
7
|
+
* inject through `asChild`, so swallowing only the click would leave a busy trigger able to open it. Keyboard focus
|
|
8
|
+
* stays, since nothing here touches focusability.
|
|
9
|
+
*/
|
|
10
|
+
export const LOADING_INERT_HANDLERS = {
|
|
11
|
+
onClick: preventActivation,
|
|
12
|
+
onPointerDown: undefined,
|
|
13
|
+
onKeyDown: undefined
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Applied while a parent `AnimatePresence` removes the button, so a stale control can be neither clicked, focused
|
|
17
|
+
* nor announced during the exit animation.
|
|
18
|
+
*/
|
|
19
|
+
export const LEAVING_ATTRIBUTES = {
|
|
20
|
+
inert: true,
|
|
21
|
+
"aria-hidden": true
|
|
22
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export type ButtonLabelProps = {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
loading: boolean;
|
|
5
|
+
reduceMotion: boolean;
|
|
6
|
+
};
|
|
7
|
+
/** Button content: a spinner while loading and a label whose width springs when it changes. */
|
|
8
|
+
export declare function ButtonLabel({ children, loading, reduceMotion }: ButtonLabelProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { c as _c } from "react/compiler-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Label morph and loading spinner adapted from Arc (https://uiarc.dev), Copyright (c) 2026 Elia Kuratli,
|
|
5
|
+
* MIT License. The full license text ships in THIRD_PARTY_NOTICES.md. Internal to Button.
|
|
6
|
+
*/
|
|
7
|
+
import { isValidElement, useEffect, useLayoutEffect, useRef } from "react";
|
|
8
|
+
import { AnimatePresence, animate, motion, useIsPresent, useMotionValue } from "motion/react";
|
|
9
|
+
import { BUTTON_MORPH_WINDOW_MS } from "../constants/button.js";
|
|
10
|
+
import { cn } from "../lib/utils.js";
|
|
11
|
+
import { ARC_BLUR, ARC_DURATION, ARC_EASE, ARC_SPRING_MORPH, ARC_SPRING_SNAPPY } from "../motion/arc-tokens.js";
|
|
12
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
const restState = {
|
|
14
|
+
opacity: 1,
|
|
15
|
+
y: 0,
|
|
16
|
+
scale: 1,
|
|
17
|
+
filter: "blur(0px)"
|
|
18
|
+
};
|
|
19
|
+
/** Outgoing labels and icons leave faster than they enter. */
|
|
20
|
+
const exitTransition = {
|
|
21
|
+
duration: ARC_DURATION.fast,
|
|
22
|
+
ease: [...ARC_EASE.standard]
|
|
23
|
+
};
|
|
24
|
+
/** Text rises out of a soft blur; the outgoing label lifts away a little faster. */
|
|
25
|
+
const textEnter = {
|
|
26
|
+
opacity: 0,
|
|
27
|
+
y: 4,
|
|
28
|
+
filter: `blur(${ARC_BLUR.soft}px)`
|
|
29
|
+
};
|
|
30
|
+
const textExit = {
|
|
31
|
+
opacity: 0,
|
|
32
|
+
y: -3,
|
|
33
|
+
filter: `blur(${ARC_BLUR.soft}px)`,
|
|
34
|
+
transition: exitTransition
|
|
35
|
+
};
|
|
36
|
+
const iconEnter = {
|
|
37
|
+
opacity: 0,
|
|
38
|
+
scale: .6,
|
|
39
|
+
filter: `blur(${ARC_BLUR.subtle}px)`
|
|
40
|
+
};
|
|
41
|
+
const iconExit = {
|
|
42
|
+
...iconEnter,
|
|
43
|
+
transition: exitTransition
|
|
44
|
+
};
|
|
45
|
+
const reducedTransition = { duration: ARC_DURATION.instant };
|
|
46
|
+
const reducedEnter = {
|
|
47
|
+
...restState,
|
|
48
|
+
opacity: 0
|
|
49
|
+
};
|
|
50
|
+
const reducedExit = {
|
|
51
|
+
opacity: 0,
|
|
52
|
+
transition: reducedTransition
|
|
53
|
+
};
|
|
54
|
+
/** Scale rides the spring; opacity and blur tween so blur never overshoots below zero. */
|
|
55
|
+
const iconTransition = {
|
|
56
|
+
...ARC_SPRING_SNAPPY,
|
|
57
|
+
opacity: {
|
|
58
|
+
duration: ARC_DURATION.fast,
|
|
59
|
+
ease: [...ARC_EASE.enter]
|
|
60
|
+
},
|
|
61
|
+
filter: {
|
|
62
|
+
duration: ARC_DURATION.fast,
|
|
63
|
+
ease: [...ARC_EASE.enter]
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const textTransition = {
|
|
67
|
+
duration: ARC_DURATION.standard,
|
|
68
|
+
ease: [...ARC_EASE.enter]
|
|
69
|
+
};
|
|
70
|
+
/** Matches markup tags inside a label key so icon-only labels can be detected. */
|
|
71
|
+
const LABEL_KEY_TAG_PATTERN = /<[^>]*>/g;
|
|
72
|
+
/** Detects visible text left in a label key. */
|
|
73
|
+
const VISIBLE_TEXT_PATTERN = /\S/;
|
|
74
|
+
/** Builds a key from text and element names, so a new label crossfades while prop-only updates stay in place. */
|
|
75
|
+
function getLabelKey(node) {
|
|
76
|
+
if (node == null || typeof node === "boolean") return "";
|
|
77
|
+
if (typeof node === "string" || typeof node === "number" || typeof node === "bigint") return String(node);
|
|
78
|
+
if (Array.isArray(node)) return node.map(getLabelKey).join("");
|
|
79
|
+
if (!isValidElement(node)) return "";
|
|
80
|
+
const elementType = node.type;
|
|
81
|
+
const elementName = typeof elementType === "string" ? elementType : elementType?.displayName ?? elementType?.name ?? "";
|
|
82
|
+
return `<${elementName}>${getLabelKey(node.props.children)}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Springs the label slot to the natural width of an incoming label, so a new label never snaps the
|
|
86
|
+
* button's size. Other resizes jump straight to the new width.
|
|
87
|
+
*/
|
|
88
|
+
function useMorphWidth(contentRef, labelKey, reduceMotion) {
|
|
89
|
+
const $ = _c(8);
|
|
90
|
+
const width = useMotionValue("auto");
|
|
91
|
+
const lastLabelKey = useRef(labelKey);
|
|
92
|
+
const morphDeadline = useRef(0);
|
|
93
|
+
let t0;
|
|
94
|
+
let t1;
|
|
95
|
+
if ($[0] !== labelKey) {
|
|
96
|
+
t0 = () => {
|
|
97
|
+
if (lastLabelKey.current === labelKey) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
lastLabelKey.current = labelKey;
|
|
101
|
+
morphDeadline.current = performance.now() + BUTTON_MORPH_WINDOW_MS;
|
|
102
|
+
};
|
|
103
|
+
t1 = [labelKey];
|
|
104
|
+
$[0] = labelKey;
|
|
105
|
+
$[1] = t0;
|
|
106
|
+
$[2] = t1;
|
|
107
|
+
} else {
|
|
108
|
+
t0 = $[1];
|
|
109
|
+
t1 = $[2];
|
|
110
|
+
}
|
|
111
|
+
useLayoutEffect(t0, t1);
|
|
112
|
+
let t2;
|
|
113
|
+
let t3;
|
|
114
|
+
if ($[3] !== contentRef || $[4] !== reduceMotion || $[5] !== width) {
|
|
115
|
+
t2 = () => {
|
|
116
|
+
const content = contentRef.current;
|
|
117
|
+
const slot = content?.parentElement;
|
|
118
|
+
if (!content || !slot || typeof ResizeObserver === "undefined") {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
let hasMeasured = false;
|
|
122
|
+
const observer = new ResizeObserver((t4) => {
|
|
123
|
+
const [entry] = t4;
|
|
124
|
+
if (!entry) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const nextWidth = entry.contentRect.width;
|
|
128
|
+
const shouldJump = !nextWidth || !hasMeasured || reduceMotion || performance.now() > morphDeadline.current;
|
|
129
|
+
if (shouldJump) {
|
|
130
|
+
hasMeasured = nextWidth > 0;
|
|
131
|
+
width.jump(nextWidth || "auto");
|
|
132
|
+
delete slot.dataset.morphing;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
slot.dataset.morphing = "";
|
|
136
|
+
animate(width, nextWidth, {
|
|
137
|
+
...ARC_SPRING_MORPH,
|
|
138
|
+
onComplete: () => {
|
|
139
|
+
delete slot.dataset.morphing;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
observer.observe(content);
|
|
144
|
+
return () => observer.disconnect();
|
|
145
|
+
};
|
|
146
|
+
t3 = [
|
|
147
|
+
contentRef,
|
|
148
|
+
reduceMotion,
|
|
149
|
+
width
|
|
150
|
+
];
|
|
151
|
+
$[3] = contentRef;
|
|
152
|
+
$[4] = reduceMotion;
|
|
153
|
+
$[5] = width;
|
|
154
|
+
$[6] = t2;
|
|
155
|
+
$[7] = t3;
|
|
156
|
+
} else {
|
|
157
|
+
t2 = $[6];
|
|
158
|
+
t3 = $[7];
|
|
159
|
+
}
|
|
160
|
+
useEffect(t2, t3);
|
|
161
|
+
return width;
|
|
162
|
+
}
|
|
163
|
+
/** One generation of the label; the outgoing one is hidden from assistive tech while it leaves. */
|
|
164
|
+
function LabelPhase(t0) {
|
|
165
|
+
const $ = _c(7);
|
|
166
|
+
const { children, isIcon, reduceMotion, ref } = t0;
|
|
167
|
+
const isPresent = useIsPresent();
|
|
168
|
+
const t1 = isPresent ? undefined : true;
|
|
169
|
+
const t2 = reduceMotion ? reducedEnter : isIcon ? iconEnter : textEnter;
|
|
170
|
+
const t3 = reduceMotion ? reducedExit : isIcon ? iconExit : textExit;
|
|
171
|
+
const t4 = reduceMotion ? reducedTransition : isIcon ? iconTransition : textTransition;
|
|
172
|
+
let t5;
|
|
173
|
+
if ($[0] !== children || $[1] !== ref || $[2] !== t1 || $[3] !== t2 || $[4] !== t3 || $[5] !== t4) {
|
|
174
|
+
t5 = /* @__PURE__ */ _jsx(motion.span, {
|
|
175
|
+
ref,
|
|
176
|
+
className: "inline-flex items-center justify-center gap-[inherit] whitespace-nowrap",
|
|
177
|
+
"aria-hidden": t1,
|
|
178
|
+
initial: t2,
|
|
179
|
+
animate: restState,
|
|
180
|
+
exit: t3,
|
|
181
|
+
transition: t4,
|
|
182
|
+
children
|
|
183
|
+
});
|
|
184
|
+
$[0] = children;
|
|
185
|
+
$[1] = ref;
|
|
186
|
+
$[2] = t1;
|
|
187
|
+
$[3] = t2;
|
|
188
|
+
$[4] = t3;
|
|
189
|
+
$[5] = t4;
|
|
190
|
+
$[6] = t5;
|
|
191
|
+
} else {
|
|
192
|
+
t5 = $[6];
|
|
193
|
+
}
|
|
194
|
+
return t5;
|
|
195
|
+
}
|
|
196
|
+
/** Button content: a spinner while loading and a label whose width springs when it changes. */
|
|
197
|
+
export function ButtonLabel(t0) {
|
|
198
|
+
const $ = _c(25);
|
|
199
|
+
const { children, loading, reduceMotion } = t0;
|
|
200
|
+
const contentRef = useRef(null);
|
|
201
|
+
let t1;
|
|
202
|
+
if ($[0] !== children) {
|
|
203
|
+
t1 = getLabelKey(children);
|
|
204
|
+
$[0] = children;
|
|
205
|
+
$[1] = t1;
|
|
206
|
+
} else {
|
|
207
|
+
t1 = $[1];
|
|
208
|
+
}
|
|
209
|
+
const labelKey = t1;
|
|
210
|
+
const width = useMorphWidth(contentRef, labelKey, reduceMotion);
|
|
211
|
+
let t2;
|
|
212
|
+
if ($[2] !== loading || $[3] !== reduceMotion) {
|
|
213
|
+
t2 = loading ? /* @__PURE__ */ _jsx(motion.span, {
|
|
214
|
+
className: "absolute top-1/2 left-1/2 -m-2 grid size-4",
|
|
215
|
+
"aria-hidden": "true",
|
|
216
|
+
initial: reduceMotion ? { opacity: 0 } : {
|
|
217
|
+
opacity: 0,
|
|
218
|
+
scale: .6
|
|
219
|
+
},
|
|
220
|
+
animate: {
|
|
221
|
+
opacity: 1,
|
|
222
|
+
scale: 1
|
|
223
|
+
},
|
|
224
|
+
exit: reduceMotion ? reducedExit : {
|
|
225
|
+
...iconExit,
|
|
226
|
+
scale: .8
|
|
227
|
+
},
|
|
228
|
+
transition: reduceMotion ? reducedTransition : iconTransition,
|
|
229
|
+
children: /* @__PURE__ */ _jsx("span", { className: "animate-spin rounded-full border-[1.5px] border-current border-r-transparent motion-reduce:animate-none" })
|
|
230
|
+
}, "loader") : null;
|
|
231
|
+
$[2] = loading;
|
|
232
|
+
$[3] = reduceMotion;
|
|
233
|
+
$[4] = t2;
|
|
234
|
+
} else {
|
|
235
|
+
t2 = $[4];
|
|
236
|
+
}
|
|
237
|
+
let t3;
|
|
238
|
+
if ($[5] !== t2) {
|
|
239
|
+
t3 = /* @__PURE__ */ _jsx(AnimatePresence, {
|
|
240
|
+
initial: false,
|
|
241
|
+
children: t2
|
|
242
|
+
});
|
|
243
|
+
$[5] = t2;
|
|
244
|
+
$[6] = t3;
|
|
245
|
+
} else {
|
|
246
|
+
t3 = $[6];
|
|
247
|
+
}
|
|
248
|
+
const t4 = loading && "opacity-0";
|
|
249
|
+
let t5;
|
|
250
|
+
if ($[7] !== t4) {
|
|
251
|
+
t5 = cn("inline-flex min-w-0 items-center justify-center gap-[inherit] transition-opacity duration-150 data-morphing:[clip-path:inset(-50%_calc(var(--spacing)*-3))]", t4);
|
|
252
|
+
$[7] = t4;
|
|
253
|
+
$[8] = t5;
|
|
254
|
+
} else {
|
|
255
|
+
t5 = $[8];
|
|
256
|
+
}
|
|
257
|
+
let t6;
|
|
258
|
+
if ($[9] !== width) {
|
|
259
|
+
t6 = { width };
|
|
260
|
+
$[9] = width;
|
|
261
|
+
$[10] = t6;
|
|
262
|
+
} else {
|
|
263
|
+
t6 = $[10];
|
|
264
|
+
}
|
|
265
|
+
let t7;
|
|
266
|
+
if ($[11] !== labelKey) {
|
|
267
|
+
t7 = VISIBLE_TEXT_PATTERN.test(labelKey.replace(LABEL_KEY_TAG_PATTERN, ""));
|
|
268
|
+
$[11] = labelKey;
|
|
269
|
+
$[12] = t7;
|
|
270
|
+
} else {
|
|
271
|
+
t7 = $[12];
|
|
272
|
+
}
|
|
273
|
+
const t8 = !t7;
|
|
274
|
+
let t9;
|
|
275
|
+
if ($[13] !== children || $[14] !== labelKey || $[15] !== reduceMotion || $[16] !== t8) {
|
|
276
|
+
t9 = /* @__PURE__ */ _jsx("span", {
|
|
277
|
+
ref: contentRef,
|
|
278
|
+
className: "inline-flex flex-none items-center gap-[inherit]",
|
|
279
|
+
children: /* @__PURE__ */ _jsx(AnimatePresence, {
|
|
280
|
+
mode: "popLayout",
|
|
281
|
+
initial: false,
|
|
282
|
+
children: /* @__PURE__ */ _jsx(LabelPhase, {
|
|
283
|
+
isIcon: t8,
|
|
284
|
+
reduceMotion,
|
|
285
|
+
children
|
|
286
|
+
}, labelKey)
|
|
287
|
+
})
|
|
288
|
+
});
|
|
289
|
+
$[13] = children;
|
|
290
|
+
$[14] = labelKey;
|
|
291
|
+
$[15] = reduceMotion;
|
|
292
|
+
$[16] = t8;
|
|
293
|
+
$[17] = t9;
|
|
294
|
+
} else {
|
|
295
|
+
t9 = $[17];
|
|
296
|
+
}
|
|
297
|
+
let t10;
|
|
298
|
+
if ($[18] !== t5 || $[19] !== t6 || $[20] !== t9) {
|
|
299
|
+
t10 = /* @__PURE__ */ _jsx(motion.span, {
|
|
300
|
+
"data-slot": "button-label",
|
|
301
|
+
className: t5,
|
|
302
|
+
style: t6,
|
|
303
|
+
children: t9
|
|
304
|
+
});
|
|
305
|
+
$[18] = t5;
|
|
306
|
+
$[19] = t6;
|
|
307
|
+
$[20] = t9;
|
|
308
|
+
$[21] = t10;
|
|
309
|
+
} else {
|
|
310
|
+
t10 = $[21];
|
|
311
|
+
}
|
|
312
|
+
let t11;
|
|
313
|
+
if ($[22] !== t10 || $[23] !== t3) {
|
|
314
|
+
t11 = /* @__PURE__ */ _jsxs(_Fragment, { children: [t3, t10] });
|
|
315
|
+
$[22] = t10;
|
|
316
|
+
$[23] = t3;
|
|
317
|
+
$[24] = t11;
|
|
318
|
+
} else {
|
|
319
|
+
t11 = $[24];
|
|
320
|
+
}
|
|
321
|
+
return t11;
|
|
322
|
+
}
|
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export
|
|
1
|
+
/**
|
|
2
|
+
* Arc's Button (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): its variants, sizes, tokens and motion,
|
|
3
|
+
* with width-aware press feedback, a label that springs to its new width and a loading spinner. It renders a native
|
|
4
|
+
* button; style links as links instead. Composite components that need icon sizes use the internal `ControlButton`.
|
|
5
|
+
*/
|
|
6
|
+
import type { ComponentProps } from "react";
|
|
7
|
+
/** Visual weight, as in Arc: one primary action per surface. */
|
|
8
|
+
export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
|
|
9
|
+
/** Height and padding, from Arc's control heights. */
|
|
10
|
+
export type ButtonSize = "sm" | "md" | "lg";
|
|
11
|
+
export type ButtonProps = ComponentProps<"button"> & {
|
|
12
|
+
variant?: ButtonVariant;
|
|
13
|
+
size?: ButtonSize;
|
|
14
|
+
/** Shows a spinner, sets `aria-busy` and swallows clicks while keeping keyboard focus. */
|
|
15
|
+
loading?: boolean;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* A single action on a page, form or dialog. Defaults to `type="button"`, so it only submits a form when asked to.
|
|
19
|
+
* @param props - Variant, size, loading state and native button attributes, including `ref`.
|
|
20
|
+
* @returns The native button.
|
|
21
|
+
*/
|
|
22
|
+
declare function Button({ className, variant, size, loading, type, children, ref, ...props }: ButtonProps): import("react").JSX.Element;
|
|
23
|
+
export { Button };
|