@anyknown/ui 0.3.0 → 0.4.1
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/dist/components/badge/Badge.d.ts +3 -1
- package/dist/components/badge/Badge.js +2 -2
- package/dist/components/button/Button.d.ts +6 -2
- package/dist/components/button/Button.js +14 -2
- package/dist/components/checkbox/Checkbox.d.ts +3 -1
- package/dist/components/checkbox/Checkbox.js +2 -2
- package/dist/components/dialog/Dialog.js +3 -4
- package/dist/components/input/Input.d.ts +3 -1
- package/dist/components/input/Input.js +2 -2
- package/dist/components/label/Label.d.ts +3 -1
- package/dist/components/label/Label.js +2 -2
- package/dist/components/switch/Switch.d.ts +3 -1
- package/dist/components/switch/Switch.js +2 -2
- package/dist/components/textarea/Textarea.d.ts +3 -1
- package/dist/components/textarea/Textarea.js +2 -2
- package/dist/components/toast/Toast.js +2 -2
- package/dist/components/tooltip/Tooltip.js +2 -2
- package/dist/lib/popup.d.ts +36 -1
- package/dist/lib/popup.js +26 -1
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as stylex from "@stylexjs/stylex";
|
|
2
2
|
import type { ComponentProps } from "react";
|
|
3
|
+
import { type StyleArg } from "../../lib/styled.js";
|
|
3
4
|
declare const DOT_TONES: {
|
|
4
5
|
readonly accent: Readonly<{
|
|
5
6
|
readonly color: stylex.StyleXClassNameFor<"color", string>;
|
|
@@ -18,8 +19,9 @@ export type BadgeProps = Omit<ComponentProps<"span">, "color"> & {
|
|
|
18
19
|
variant?: "neutral" | "accent" | "success" | "danger" | "outline" | "mono";
|
|
19
20
|
dot?: keyof typeof DOT_TONES;
|
|
20
21
|
count?: number;
|
|
22
|
+
sx?: StyleArg;
|
|
21
23
|
};
|
|
22
|
-
export declare function Badge({ variant, dot, count, children, ...props }: BadgeProps): import("react").JSX.Element;
|
|
24
|
+
export declare function Badge({ variant, dot, count, children, sx, ...props }: BadgeProps): import("react").JSX.Element;
|
|
23
25
|
export type ChipProps = BadgeProps & {
|
|
24
26
|
onRemove?: () => void;
|
|
25
27
|
removeLabel: string;
|
|
@@ -71,8 +71,8 @@ const DOT_TONES = {
|
|
|
71
71
|
danger: styles.dotDanger,
|
|
72
72
|
warning: styles.dotWarning,
|
|
73
73
|
};
|
|
74
|
-
export function Badge({ variant = "neutral", dot, count, children, ...props }) {
|
|
75
|
-
return (_jsxs("span", { ...props, ...styled(props, styles.base, styles[variant]), children: [dot != null && _jsx("span", { "aria-hidden": "true", ...stylex.props(styles.dot, DOT_TONES[dot]) }), children, count != null && _jsx("span", { ...stylex.props(styles.count), children: count })] }));
|
|
74
|
+
export function Badge({ variant = "neutral", dot, count, children, sx, ...props }) {
|
|
75
|
+
return (_jsxs("span", { ...props, ...styled(props, styles.base, styles[variant], sx), children: [dot != null && _jsx("span", { "aria-hidden": "true", ...stylex.props(styles.dot, DOT_TONES[dot]) }), children, count != null && _jsx("span", { ...stylex.props(styles.count), children: count })] }));
|
|
76
76
|
}
|
|
77
77
|
export function Chip({ onRemove, removeLabel, variant = "outline", children, ...props }) {
|
|
78
78
|
return (_jsxs(Badge, { variant: variant, ...props, children: [children, onRemove != null && (_jsx("button", { type: "button", "aria-label": removeLabel, onClick: onRemove, ...stylex.props(reset.control, styles.remove), children: _jsx("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", "aria-hidden": "true", children: _jsx("path", { d: "m1 1 6 6M7 1 1 7" }) }) }))] }));
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { type ComponentProps } from "react";
|
|
2
|
+
import { type StyleArg } from "../../lib/styled.js";
|
|
2
3
|
type ButtonProps = ComponentProps<"button"> & {
|
|
3
4
|
variant?: "primary" | "secondary" | "ghost" | "danger" | "dangerGhost";
|
|
4
|
-
size?: "sm" | "md";
|
|
5
|
+
size?: "xs" | "sm" | "md";
|
|
6
|
+
/** Square, no side padding — for a button whose whole label is one icon. */
|
|
7
|
+
icon?: boolean;
|
|
8
|
+
sx?: StyleArg;
|
|
5
9
|
};
|
|
6
|
-
export declare function Button({ variant, size, children, ref, ...props }: ButtonProps): import("react").JSX.Element;
|
|
10
|
+
export declare function Button({ variant, size, icon, children, ref, sx, ...props }: ButtonProps): import("react").JSX.Element;
|
|
7
11
|
export {};
|
|
@@ -40,6 +40,17 @@ const styles = stylex.create({
|
|
|
40
40
|
minHeight: "1.75rem",
|
|
41
41
|
fontSize: text.xs,
|
|
42
42
|
},
|
|
43
|
+
xs: {
|
|
44
|
+
paddingBlock: 0,
|
|
45
|
+
paddingInline: space.xs,
|
|
46
|
+
minHeight: "1.5rem",
|
|
47
|
+
fontSize: text.xs,
|
|
48
|
+
gap: space.xxs,
|
|
49
|
+
},
|
|
50
|
+
// 圖示鈕:正方,邊長跟著該階的高,沒有左右內距
|
|
51
|
+
iconMd: { paddingInline: 0, width: "2.25rem" },
|
|
52
|
+
iconSm: { paddingInline: 0, width: "1.75rem" },
|
|
53
|
+
iconXs: { paddingInline: 0, width: "1.5rem" },
|
|
43
54
|
// filter = 整塊布的落影(§3.3);ghost 是疏織,不落影
|
|
44
55
|
primary: { color: color.accentText, filter: yarn.shadow },
|
|
45
56
|
secondary: { color: color.text, filter: yarnSecondary.shadow },
|
|
@@ -69,7 +80,8 @@ const SILK = {
|
|
|
69
80
|
danger: { palette: palette(yarnDanger), bandMax: 0.75 },
|
|
70
81
|
dangerGhost: { palette: palette(yarnGhost), ghost: true, bandMax: 0.5 },
|
|
71
82
|
};
|
|
72
|
-
|
|
83
|
+
const ICON_SIZE = { xs: "iconXs", sm: "iconSm", md: "iconMd" };
|
|
84
|
+
export function Button({ variant = "primary", size = "md", icon = false, children, ref, sx, ...props }) {
|
|
73
85
|
// ref callback + cleanup(React 19)管生命週期,不用 effect;
|
|
74
86
|
// useCallback 鎖 identity,只有 variant 變了才重建織體
|
|
75
87
|
const silk = useCallback((node) => {
|
|
@@ -82,5 +94,5 @@ export function Button({ variant = "primary", size = "md", children, ref, ...pro
|
|
|
82
94
|
});
|
|
83
95
|
return () => body.destroy();
|
|
84
96
|
}, [variant]);
|
|
85
|
-
return (_jsxs("button", { type: "button", ...props, ref: (element) => assignRef(ref, element), ...styled(props, styles.base, styles[size], styles[variant]), children: [_jsx("svg", { ref: silk, "aria-hidden": "true", ...stylex.props(styles.silk) }), _jsx("span", { ...stylex.props(styles.label), children: children })] }));
|
|
97
|
+
return (_jsxs("button", { type: "button", ...props, ref: (element) => assignRef(ref, element), ...styled(props, styles.base, styles[size], icon && styles[ICON_SIZE[size]], styles[variant], sx), children: [_jsx("svg", { ref: silk, "aria-hidden": "true", ...stylex.props(styles.silk) }), _jsx("span", { ...stylex.props(styles.label), children: children })] }));
|
|
86
98
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type ComponentProps, type ReactNode } from "react";
|
|
2
|
+
import { type StyleArg } from "../../lib/styled.js";
|
|
2
3
|
export type CheckboxProps = Omit<ComponentProps<"input">, "type" | "children"> & {
|
|
3
4
|
indeterminate?: boolean;
|
|
4
5
|
label?: ReactNode;
|
|
5
6
|
description?: ReactNode;
|
|
6
7
|
onCheckedChange?: (checked: boolean) => void;
|
|
8
|
+
sx?: StyleArg;
|
|
7
9
|
};
|
|
8
|
-
export declare function Checkbox({ indeterminate, label, description, onCheckedChange, checked, defaultChecked, onChange, ref, ...props }: CheckboxProps): import("react").JSX.Element;
|
|
10
|
+
export declare function Checkbox({ indeterminate, label, description, onCheckedChange, checked, defaultChecked, onChange, ref, sx, ...props }: CheckboxProps): import("react").JSX.Element;
|
|
@@ -77,7 +77,7 @@ const styles = stylex.create({
|
|
|
77
77
|
description: { display: "block", fontSize: text.xs, color: color.textMuted },
|
|
78
78
|
});
|
|
79
79
|
const BUCKETS = [styles.y0, styles.y1, styles.y2, styles.y3, styles.y4];
|
|
80
|
-
export function Checkbox({ indeterminate = false, label, description, onCheckedChange, checked, defaultChecked, onChange, ref, ...props }) {
|
|
80
|
+
export function Checkbox({ indeterminate = false, label, description, onCheckedChange, checked, defaultChecked, onChange, ref, sx, ...props }) {
|
|
81
81
|
const clipId = useSvgId("ak-weave");
|
|
82
82
|
const base = useId();
|
|
83
83
|
const labelId = `${base}label`;
|
|
@@ -95,7 +95,7 @@ export function Checkbox({ indeterminate = false, label, description, onCheckedC
|
|
|
95
95
|
const describedBy = [description != null ? descriptionId : null, field["aria-describedby"]]
|
|
96
96
|
.filter(Boolean)
|
|
97
97
|
.join(" ");
|
|
98
|
-
return (_jsxs("label", { ...stylex.props(styles.root), children: [_jsxs("span", { ...stylex.props(styles.box, filled && styles.boxOn), children: [_jsx("input", { type: "checkbox", ...props, ...field, "aria-invalid": invalid || undefined, "aria-labelledby": label != null ? labelId : undefined, "aria-describedby": describedBy || undefined, ref: setNode, checked: isChecked, onChange: (event) => {
|
|
98
|
+
return (_jsxs("label", { ...stylex.props(styles.root, sx), children: [_jsxs("span", { ...stylex.props(styles.box, filled && styles.boxOn), children: [_jsx("input", { type: "checkbox", ...props, ...field, "aria-invalid": invalid || undefined, "aria-labelledby": label != null ? labelId : undefined, "aria-describedby": describedBy || undefined, ref: setNode, checked: isChecked, onChange: (event) => {
|
|
99
99
|
setChecked(event.currentTarget.checked);
|
|
100
100
|
onChange?.(event);
|
|
101
101
|
}, ...styled(props, styles.input) }), _jsxs("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", ...stylex.props(styles.svg), children: [_jsx("defs", { children: _jsx("clipPath", { id: clipId, children: _jsx("rect", { rx: "3", ...stylex.props(styles.weave, filled && styles.weaveOn) }) }) }), _jsxs("g", { clipPath: `url(#${clipId})`, children: [_jsxs("g", { ...stylex.props(styles.cloth), children: [_jsx("g", { ...stylex.props(styles.un), children: CLOTH.under.map((t, i) => (_jsx("path", { d: t.d, strokeWidth: t.sw }, i))) }), _jsx("g", { ...stylex.props(styles.sh), children: CLOTH.seams.map((t, i) => (_jsx("path", { d: t.d, strokeWidth: t.sw }, i))) }), CLOTH.face.map((t, i) => (_jsx("path", { d: t.d, strokeWidth: t.sw, ...stylex.props(BUCKETS[t.bucket]) }, i))), _jsx("g", { ...stylex.props(styles.hi), children: CLOTH.hi.map((t, i) => (_jsx("path", { d: t.d, strokeWidth: t.sw }, i))) })] }), _jsxs("g", { ...stylex.props(styles.mark), children: [_jsx("path", { d: indeterminate ? DASH_D : CHECK_D, strokeWidth: "2.1", transform: "translate(0.35 0.5)", ...stylex.props(styles.threadShadow) }), _jsx("path", { d: indeterminate ? DASH_D : CHECK_D, strokeWidth: "1.95", ...stylex.props(styles.threadCore) })] })] })] })] }), (label != null || description != null) && (_jsxs("span", { children: [label != null && (_jsx("span", { id: labelId, ...stylex.props(styles.labelText), children: label })), description != null && (_jsx("span", { id: descriptionId, ...stylex.props(styles.description), children: description }))] }))] }));
|
|
@@ -3,6 +3,7 @@ import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
|
3
3
|
import { Dialog as BaseDialog } from "@base-ui/react/dialog";
|
|
4
4
|
import * as stylex from "@stylexjs/stylex";
|
|
5
5
|
import { useRef } from "react";
|
|
6
|
+
import { layerStyles } from "../../lib/popup.js";
|
|
6
7
|
import { color, font, radius, shadow, space, text } from "../../tokens.stylex.js";
|
|
7
8
|
import { Button } from "../button/Button.js";
|
|
8
9
|
const REDUCED = "@media (prefers-reduced-motion: reduce)";
|
|
@@ -14,14 +15,12 @@ const styles = stylex.create({
|
|
|
14
15
|
backdrop: {
|
|
15
16
|
position: "fixed",
|
|
16
17
|
inset: 0,
|
|
17
|
-
zIndex: 70,
|
|
18
18
|
backgroundColor: "rgba(24, 22, 19, 0.35)",
|
|
19
19
|
backdropFilter: "blur(2px)",
|
|
20
20
|
},
|
|
21
21
|
viewport: {
|
|
22
22
|
position: "fixed",
|
|
23
23
|
inset: 0,
|
|
24
|
-
zIndex: 71,
|
|
25
24
|
display: "grid",
|
|
26
25
|
placeItems: "center",
|
|
27
26
|
padding: space.md,
|
|
@@ -69,9 +68,9 @@ export function DialogActions({ children }) {
|
|
|
69
68
|
return _jsx("div", { ...stylex.props(styles.actions), children: children });
|
|
70
69
|
}
|
|
71
70
|
export function DialogContent({ title, description, children }) {
|
|
72
|
-
return (_jsxs(BaseDialog.Portal, { children: [_jsx(BaseDialog.Backdrop, { ...stylex.props(styles.backdrop) }), _jsx(BaseDialog.Viewport, { ...stylex.props(styles.viewport), children: _jsxs(BaseDialog.Popup, { ...stylex.props(styles.popup), children: [_jsx(BaseDialog.Title, { ...stylex.props(styles.title), children: title }), description != null && (_jsx(BaseDialog.Description, { ...stylex.props(styles.description), children: description })), children] }) })] }));
|
|
71
|
+
return (_jsxs(BaseDialog.Portal, { children: [_jsx(BaseDialog.Backdrop, { ...stylex.props(layerStyles.dialogBackdrop, styles.backdrop) }), _jsx(BaseDialog.Viewport, { ...stylex.props(layerStyles.dialog, styles.viewport), children: _jsxs(BaseDialog.Popup, { ...stylex.props(styles.popup), children: [_jsx(BaseDialog.Title, { ...stylex.props(styles.title), children: title }), description != null && (_jsx(BaseDialog.Description, { ...stylex.props(styles.description), children: description })), children] }) })] }));
|
|
73
72
|
}
|
|
74
73
|
export function ConfirmDialog({ trigger, title, description, danger = false, confirmLabel = "確認", cancelLabel = "取消", onConfirm, ...props }) {
|
|
75
74
|
const cancelRef = useRef(null);
|
|
76
|
-
return (_jsxs(AlertDialog.Root, { ...props, children: [trigger != null && _jsx(AlertDialog.Trigger, { render: trigger }), _jsxs(AlertDialog.Portal, { children: [_jsx(AlertDialog.Backdrop, { ...stylex.props(styles.backdrop) }), _jsx(AlertDialog.Viewport, { ...stylex.props(styles.viewport), children: _jsxs(AlertDialog.Popup, { initialFocus: danger ? cancelRef : undefined, ...stylex.props(styles.popup), children: [_jsx(AlertDialog.Title, { ...stylex.props(styles.title), children: title }), description != null && (_jsx(AlertDialog.Description, { ...stylex.props(styles.description), children: description })), _jsxs("div", { ...stylex.props(styles.actions), children: [_jsx(AlertDialog.Close, { render: _jsx(Button, { ref: cancelRef, variant: "ghost" }), children: cancelLabel }), _jsx(AlertDialog.Close, { render: _jsx(Button, { variant: danger ? "danger" : "primary" }), onClick: onConfirm, children: confirmLabel })] })] }) })] })] }));
|
|
75
|
+
return (_jsxs(AlertDialog.Root, { ...props, children: [trigger != null && _jsx(AlertDialog.Trigger, { render: trigger }), _jsxs(AlertDialog.Portal, { children: [_jsx(AlertDialog.Backdrop, { ...stylex.props(layerStyles.dialogBackdrop, styles.backdrop) }), _jsx(AlertDialog.Viewport, { ...stylex.props(layerStyles.dialog, styles.viewport), children: _jsxs(AlertDialog.Popup, { initialFocus: danger ? cancelRef : undefined, ...stylex.props(styles.popup), children: [_jsx(AlertDialog.Title, { ...stylex.props(styles.title), children: title }), description != null && (_jsx(AlertDialog.Description, { ...stylex.props(styles.description), children: description })), _jsxs("div", { ...stylex.props(styles.actions), children: [_jsx(AlertDialog.Close, { render: _jsx(Button, { ref: cancelRef, variant: "ghost" }), children: cancelLabel }), _jsx(AlertDialog.Close, { render: _jsx(Button, { variant: danger ? "danger" : "primary" }), onClick: onConfirm, children: confirmLabel })] })] }) })] })] }));
|
|
77
76
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as stylex from "@stylexjs/stylex";
|
|
2
2
|
import type { ComponentProps, ReactNode } from "react";
|
|
3
|
+
import { type StyleArg } from "../../lib/styled.js";
|
|
3
4
|
export declare const controlStyles: Readonly<{
|
|
4
5
|
readonly base: Readonly<{
|
|
5
6
|
readonly width: stylex.StyleXClassNameFor<"width", "100%">;
|
|
@@ -44,5 +45,6 @@ export type InputProps = Omit<ComponentProps<"input">, "size"> & {
|
|
|
44
45
|
size?: "sm" | "md";
|
|
45
46
|
invalid?: boolean;
|
|
46
47
|
leadingIcon?: ReactNode;
|
|
48
|
+
sx?: StyleArg;
|
|
47
49
|
};
|
|
48
|
-
export declare function Input({ size, invalid, leadingIcon, ...props }: InputProps): import("react").JSX.Element;
|
|
50
|
+
export declare function Input({ size, invalid, leadingIcon, sx, ...props }: InputProps): import("react").JSX.Element;
|
|
@@ -54,10 +54,10 @@ const styles = stylex.create({
|
|
|
54
54
|
withIconMd: { paddingInlineStart: space.xl },
|
|
55
55
|
withIconSm: { paddingInlineStart: space.lg },
|
|
56
56
|
});
|
|
57
|
-
export function Input({ size = "md", invalid, leadingIcon, ...props }) {
|
|
57
|
+
export function Input({ size = "md", invalid, leadingIcon, sx, ...props }) {
|
|
58
58
|
const { invalid: fieldInvalid, ...field } = useFieldControl(props);
|
|
59
59
|
const isInvalid = invalid ?? fieldInvalid;
|
|
60
|
-
const input = (_jsx("input", { ...props, ...field, "aria-invalid": isInvalid || undefined, ...styled(props, controlStyles.base, controlStyles[size], isInvalid && controlStyles.invalid, Boolean(leadingIcon) && (size === "sm" ? styles.withIconSm : styles.withIconMd)) }));
|
|
60
|
+
const input = (_jsx("input", { ...props, ...field, "aria-invalid": isInvalid || undefined, ...styled(props, controlStyles.base, controlStyles[size], isInvalid && controlStyles.invalid, Boolean(leadingIcon) && (size === "sm" ? styles.withIconSm : styles.withIconMd), sx) }));
|
|
61
61
|
if (!leadingIcon)
|
|
62
62
|
return input;
|
|
63
63
|
return (_jsxs("span", { ...stylex.props(styles.affix), children: [_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.icon), children: leadingIcon }), input] }));
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ComponentProps } from "react";
|
|
2
|
+
import { type StyleArg } from "../../lib/styled.js";
|
|
2
3
|
export type LabelProps = ComponentProps<"label"> & {
|
|
3
4
|
required?: boolean;
|
|
4
5
|
optional?: boolean;
|
|
5
6
|
optionalLabel?: string;
|
|
7
|
+
sx?: StyleArg;
|
|
6
8
|
};
|
|
7
|
-
export declare function Label({ required, optional, optionalLabel, children, ...props }: LabelProps): import("react").JSX.Element;
|
|
9
|
+
export declare function Label({ required, optional, optionalLabel, children, sx, ...props }: LabelProps): import("react").JSX.Element;
|
|
@@ -16,6 +16,6 @@ const styles = stylex.create({
|
|
|
16
16
|
required: { color: color.danger },
|
|
17
17
|
optional: { fontWeight: 400, fontSize: text.xs, color: color.textFaint },
|
|
18
18
|
});
|
|
19
|
-
export function Label({ required, optional, optionalLabel = "選填", children, ...props }) {
|
|
20
|
-
return (_jsxs("label", { ...props, ...styled(props, styles.base), children: [children, required && (_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.required), children: "*" })), optional && _jsxs("span", { ...stylex.props(styles.optional), children: [" ", optionalLabel] })] }));
|
|
19
|
+
export function Label({ required, optional, optionalLabel = "選填", children, sx, ...props }) {
|
|
20
|
+
return (_jsxs("label", { ...props, ...styled(props, styles.base, sx), children: [children, required && (_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.required), children: "*" })), optional && _jsxs("span", { ...stylex.props(styles.optional), children: [" ", optionalLabel] })] }));
|
|
21
21
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { type ComponentProps, type ReactNode } from "react";
|
|
2
|
+
import { type StyleArg } from "../../lib/styled.js";
|
|
2
3
|
export type SwitchProps = Omit<ComponentProps<"input">, "type" | "role" | "children"> & {
|
|
3
4
|
label?: ReactNode;
|
|
4
5
|
description?: ReactNode;
|
|
5
6
|
onCheckedChange?: (checked: boolean) => void;
|
|
7
|
+
sx?: StyleArg;
|
|
6
8
|
};
|
|
7
|
-
export declare function Switch({ label, description, onCheckedChange, checked, defaultChecked, onChange, ...props }: SwitchProps): import("react").JSX.Element;
|
|
9
|
+
export declare function Switch({ label, description, onCheckedChange, checked, defaultChecked, onChange, sx, ...props }: SwitchProps): import("react").JSX.Element;
|
|
@@ -91,7 +91,7 @@ const styles = stylex.create({
|
|
|
91
91
|
description: { display: "block", fontSize: text.xs, color: color.textMuted },
|
|
92
92
|
});
|
|
93
93
|
const BUCKETS = [styles.y0, styles.y1, styles.y2, styles.y3, styles.y4];
|
|
94
|
-
export function Switch({ label, description, onCheckedChange, checked, defaultChecked, onChange, ...props }) {
|
|
94
|
+
export function Switch({ label, description, onCheckedChange, checked, defaultChecked, onChange, sx, ...props }) {
|
|
95
95
|
const clipId = useSvgId("ak-weave");
|
|
96
96
|
const base = useId();
|
|
97
97
|
const labelId = `${base}label`;
|
|
@@ -101,7 +101,7 @@ export function Switch({ label, description, onCheckedChange, checked, defaultCh
|
|
|
101
101
|
.filter(Boolean)
|
|
102
102
|
.join(" ");
|
|
103
103
|
const [isOn, setOn] = useControllableState(checked, defaultChecked ?? false, onCheckedChange);
|
|
104
|
-
return (_jsxs("label", { ...stylex.props(styles.root), children: [(label != null || description != null) && (_jsxs("span", { children: [label != null && (_jsx("span", { id: labelId, ...stylex.props(styles.labelText), children: label })), description != null && (_jsx("span", { id: descriptionId, ...stylex.props(styles.description), children: description }))] })), _jsxs("span", { ...stylex.props(styles.track), children: [_jsx("input", { type: "checkbox", role: "switch", ...props, ...field, "aria-invalid": invalid || undefined, "aria-labelledby": label != null ? labelId : undefined, "aria-describedby": describedBy || undefined, checked: isOn, "aria-checked": isOn, onChange: (event) => {
|
|
104
|
+
return (_jsxs("label", { ...stylex.props(styles.root, sx), children: [(label != null || description != null) && (_jsxs("span", { children: [label != null && (_jsx("span", { id: labelId, ...stylex.props(styles.labelText), children: label })), description != null && (_jsx("span", { id: descriptionId, ...stylex.props(styles.description), children: description }))] })), _jsxs("span", { ...stylex.props(styles.track), children: [_jsx("input", { type: "checkbox", role: "switch", ...props, ...field, "aria-invalid": invalid || undefined, "aria-labelledby": label != null ? labelId : undefined, "aria-describedby": describedBy || undefined, checked: isOn, "aria-checked": isOn, onChange: (event) => {
|
|
105
105
|
setOn(event.currentTarget.checked);
|
|
106
106
|
onChange?.(event);
|
|
107
107
|
}, ...styled(props, styles.input) }), _jsxs("svg", { viewBox: "0 0 44 22", "aria-hidden": "true", ...stylex.props(styles.svg), children: [_jsx("path", { d: "M11,11 H33", ...stylex.props(styles.guide) }), _jsxs("g", { ...stylex.props(styles.cloth, isOn && styles.clothOn), children: [_jsxs("defs", { children: [_jsx("clipPath", { id: `${clipId}p`, children: _jsx("rect", { x: "1", y: "1", width: "42", height: "20", rx: "10" }) }), _jsx("clipPath", { id: clipId, children: _jsx("rect", { x: "1", y: "-3", height: "28", ...stylex.props(styles.pillclip, isOn && styles.pillclipOn) }) })] }), _jsx("g", { clipPath: `url(#${clipId}p)`, children: _jsxs("g", { clipPath: `url(#${clipId})`, ...stylex.props(styles.yarns), children: [_jsx("g", { ...stylex.props(styles.un), children: CLOTH.under.map((t, i) => (_jsx("path", { d: t.d, strokeWidth: t.sw }, i))) }), _jsx("g", { ...stylex.props(styles.sh), children: CLOTH.seams.map((t, i) => (_jsx("path", { d: t.d, strokeWidth: t.sw }, i))) }), CLOTH.face.map((t, i) => (_jsx("path", { d: t.d, strokeWidth: t.sw, ...stylex.props(BUCKETS[t.bucket]) }, i))), _jsx("g", { ...stylex.props(styles.hi), children: CLOTH.hi.map((t, i) => (_jsx("path", { d: t.d, strokeWidth: t.sw }, i))) })] }) })] }), _jsx("circle", { cx: "11", cy: "11", r: "8.4", ...stylex.props(styles.thumb, isOn && styles.thumbOn) })] })] })] }));
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ComponentProps } from "react";
|
|
2
|
+
import { type StyleArg } from "../../lib/styled.js";
|
|
2
3
|
export type TextareaProps = ComponentProps<"textarea"> & {
|
|
3
4
|
autoGrow?: boolean;
|
|
4
5
|
maxRows?: number;
|
|
5
6
|
invalid?: boolean;
|
|
7
|
+
sx?: StyleArg;
|
|
6
8
|
};
|
|
7
|
-
export declare function Textarea({ autoGrow, maxRows, invalid, ...props }: TextareaProps): import("react").JSX.Element;
|
|
9
|
+
export declare function Textarea({ autoGrow, maxRows, invalid, sx, ...props }: TextareaProps): import("react").JSX.Element;
|
|
@@ -18,8 +18,8 @@ const styles = stylex.create({
|
|
|
18
18
|
},
|
|
19
19
|
maxRows: (rows) => ({ maxHeight: `calc(${rows} * 1.6em + ${space.md})` }),
|
|
20
20
|
});
|
|
21
|
-
export function Textarea({ autoGrow, maxRows, invalid, ...props }) {
|
|
21
|
+
export function Textarea({ autoGrow, maxRows, invalid, sx, ...props }) {
|
|
22
22
|
const { invalid: fieldInvalid, ...field } = useFieldControl(props);
|
|
23
23
|
const isInvalid = invalid ?? fieldInvalid;
|
|
24
|
-
return (_jsx("textarea", { ...props, ...field, "aria-invalid": isInvalid || undefined, ...styled(props, controlStyles.base, styles.base, autoGrow && styles.autoGrow, maxRows != null && styles.maxRows(maxRows), isInvalid && controlStyles.invalid) }));
|
|
24
|
+
return (_jsx("textarea", { ...props, ...field, "aria-invalid": isInvalid || undefined, ...styled(props, controlStyles.base, styles.base, autoGrow && styles.autoGrow, maxRows != null && styles.maxRows(maxRows), isInvalid && controlStyles.invalid, sx) }));
|
|
25
25
|
}
|
|
@@ -5,6 +5,7 @@ import { createContext, useContext, useState } from "react";
|
|
|
5
5
|
import { reset } from "../../lib/styled.js";
|
|
6
6
|
import { usePrefersReducedMotion } from "../../lib/motion.js";
|
|
7
7
|
import { UNWEAVE_PATH } from "../../lib/paths.js";
|
|
8
|
+
import { layerStyles } from "../../lib/popup.js";
|
|
8
9
|
import { color, font, motion, radius, shadow, space, text } from "../../tokens.stylex.js";
|
|
9
10
|
const REDUCED = "@media (prefers-reduced-motion: reduce)";
|
|
10
11
|
const DEFAULT_TIMEOUT = 5000;
|
|
@@ -19,7 +20,6 @@ const unweave = stylex.keyframes({
|
|
|
19
20
|
const styles = stylex.create({
|
|
20
21
|
viewport: {
|
|
21
22
|
position: "fixed",
|
|
22
|
-
zIndex: 80,
|
|
23
23
|
display: "flex",
|
|
24
24
|
gap: space.xs,
|
|
25
25
|
width: "min(20rem, calc(100vw - 2.5rem))",
|
|
@@ -161,7 +161,7 @@ export function Toaster({ position = "bottom-right", timeout = DEFAULT_TIMEOUT,
|
|
|
161
161
|
const [api] = useState(() => makeApi(() => own));
|
|
162
162
|
const [paused, setPaused] = useState(false);
|
|
163
163
|
const fromBottom = position.startsWith("bottom");
|
|
164
|
-
return (_jsx(ToastApiContext, { value: api, children: _jsx(BaseToast.Provider, { toastManager: own, timeout: timeout, limit: limit, children: _jsx(BaseToast.Portal, { children: _jsx(BaseToast.Viewport, { onMouseEnter: () => setPaused(true), onMouseLeave: () => setPaused(false), onFocus: () => setPaused(true), onBlur: () => setPaused(false), ...stylex.props(styles.viewport, fromBottom ? styles.fromBottom : styles.fromTop, POSITIONS[position]), children: _jsx(ToastList, { fallbackTimeout: timeout, paused: paused }) }) }) }) }));
|
|
164
|
+
return (_jsx(ToastApiContext, { value: api, children: _jsx(BaseToast.Provider, { toastManager: own, timeout: timeout, limit: limit, children: _jsx(BaseToast.Portal, { children: _jsx(BaseToast.Viewport, { onMouseEnter: () => setPaused(true), onMouseLeave: () => setPaused(false), onFocus: () => setPaused(true), onBlur: () => setPaused(false), ...stylex.props(layerStyles.toast, styles.viewport, fromBottom ? styles.fromBottom : styles.fromTop, POSITIONS[position]), children: _jsx(ToastList, { fallbackTimeout: timeout, paused: paused }) }) }) }) }));
|
|
165
165
|
}
|
|
166
166
|
function ToastList({ fallbackTimeout, paused }) {
|
|
167
167
|
const { toasts } = BaseToast.useToastManager();
|
|
@@ -3,12 +3,12 @@ import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
|
|
|
3
3
|
import * as stylex from "@stylexjs/stylex";
|
|
4
4
|
import { useId, useState } from "react";
|
|
5
5
|
import { usePrefersReducedMotion } from "../../lib/motion.js";
|
|
6
|
+
import { layerStyles } from "../../lib/popup.js";
|
|
6
7
|
import { color, font, motion, radius, space, text } from "../../tokens.stylex.js";
|
|
7
8
|
import { KbdToneContext } from "../kbd/Kbd.js";
|
|
8
9
|
const REDUCED = "@media (prefers-reduced-motion: reduce)";
|
|
9
10
|
const fade = stylex.keyframes({ from: { opacity: 0 }, to: { opacity: 1 } });
|
|
10
11
|
const styles = stylex.create({
|
|
11
|
-
positioner: { zIndex: 60 },
|
|
12
12
|
bubble: {
|
|
13
13
|
display: "inline-flex",
|
|
14
14
|
alignItems: "center",
|
|
@@ -34,5 +34,5 @@ export function Tooltip({ content, shortcut, side = "top", align = "center", del
|
|
|
34
34
|
const [open, setOpen] = useState(false);
|
|
35
35
|
if (disabled)
|
|
36
36
|
return children;
|
|
37
|
-
return (_jsxs(BaseTooltip.Root, { open: open, onOpenChange: setOpen, children: [_jsx(BaseTooltip.Trigger, { delay: reduced ? 0 : delay, "aria-describedby": open ? id : undefined, render: children }), _jsx(BaseTooltip.Portal, { children: _jsx(BaseTooltip.Positioner, { side: side, align: align, sideOffset: 6, ...stylex.props(
|
|
37
|
+
return (_jsxs(BaseTooltip.Root, { open: open, onOpenChange: setOpen, children: [_jsx(BaseTooltip.Trigger, { delay: reduced ? 0 : delay, "aria-describedby": open ? id : undefined, render: children }), _jsx(BaseTooltip.Portal, { children: _jsx(BaseTooltip.Positioner, { side: side, align: align, sideOffset: 6, ...stylex.props(layerStyles.tooltip), children: _jsx(BaseTooltip.Popup, { id: id, role: "tooltip", ...stylex.props(styles.bubble), children: _jsxs(KbdToneContext, { value: "inverted", children: [content, shortcut] }) }) }) })] }));
|
|
38
38
|
}
|
package/dist/lib/popup.d.ts
CHANGED
|
@@ -1,4 +1,39 @@
|
|
|
1
1
|
import * as stylex from "@stylexjs/stylex";
|
|
2
|
+
/**
|
|
3
|
+
* 全站疊層表。Base UI 的浮層一律 portal 到 body,跟 dialog / toast 同在一層比 z-index,
|
|
4
|
+
* 各元件各寫一個數字就會出現「dialog 裡的 select 打不開」這種洞,所以值集中在這裡。
|
|
5
|
+
*
|
|
6
|
+
* 順序的理由:popup 壓過 dialog(浮層是當下互動的最上層);tooltip 壓過 popup
|
|
7
|
+
* (popup 裡的元素也能有 tooltip);toast 永遠最上(非阻斷通知不能被 modal 蓋掉)。
|
|
8
|
+
*/
|
|
9
|
+
export declare const layer: {
|
|
10
|
+
readonly dialogBackdrop: 70;
|
|
11
|
+
readonly dialog: 71;
|
|
12
|
+
readonly popup: 75;
|
|
13
|
+
readonly tooltip: 78;
|
|
14
|
+
readonly toast: 80;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* `layer` 的 stylex 版。跨檔案 import 的值在 `stylex.create()` 裡不能靜態求值,
|
|
18
|
+
* 所以疊層要以「做好的樣式」而不是數字提供給其他元件。
|
|
19
|
+
*/
|
|
20
|
+
export declare const layerStyles: Readonly<{
|
|
21
|
+
readonly dialogBackdrop: Readonly<{
|
|
22
|
+
readonly zIndex: stylex.StyleXClassNameFor<"zIndex", 70>;
|
|
23
|
+
}>;
|
|
24
|
+
readonly dialog: Readonly<{
|
|
25
|
+
readonly zIndex: stylex.StyleXClassNameFor<"zIndex", 71>;
|
|
26
|
+
}>;
|
|
27
|
+
readonly popup: Readonly<{
|
|
28
|
+
readonly zIndex: stylex.StyleXClassNameFor<"zIndex", 75>;
|
|
29
|
+
}>;
|
|
30
|
+
readonly tooltip: Readonly<{
|
|
31
|
+
readonly zIndex: stylex.StyleXClassNameFor<"zIndex", 78>;
|
|
32
|
+
}>;
|
|
33
|
+
readonly toast: Readonly<{
|
|
34
|
+
readonly zIndex: stylex.StyleXClassNameFor<"zIndex", 80>;
|
|
35
|
+
}>;
|
|
36
|
+
}>;
|
|
2
37
|
export declare const growIn: string;
|
|
3
38
|
export declare const popupStyles: Readonly<{
|
|
4
39
|
readonly surface: Readonly<{
|
|
@@ -23,7 +58,7 @@ export declare const popupStyles: Readonly<{
|
|
|
23
58
|
readonly maxHeight: stylex.StyleXClassNameFor<"maxHeight", "var(--available-height)">;
|
|
24
59
|
}>;
|
|
25
60
|
readonly positioner: Readonly<{
|
|
26
|
-
readonly zIndex: stylex.StyleXClassNameFor<"zIndex",
|
|
61
|
+
readonly zIndex: stylex.StyleXClassNameFor<"zIndex", 75>;
|
|
27
62
|
readonly outline: stylex.StyleXClassNameFor<"outline", "none">;
|
|
28
63
|
}>;
|
|
29
64
|
}>;
|
package/dist/lib/popup.js
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
import * as stylex from "@stylexjs/stylex";
|
|
2
2
|
import { color, radius, shadow } from "../tokens.stylex.js";
|
|
3
3
|
const REDUCED = "@media (prefers-reduced-motion: reduce)";
|
|
4
|
+
/**
|
|
5
|
+
* 全站疊層表。Base UI 的浮層一律 portal 到 body,跟 dialog / toast 同在一層比 z-index,
|
|
6
|
+
* 各元件各寫一個數字就會出現「dialog 裡的 select 打不開」這種洞,所以值集中在這裡。
|
|
7
|
+
*
|
|
8
|
+
* 順序的理由:popup 壓過 dialog(浮層是當下互動的最上層);tooltip 壓過 popup
|
|
9
|
+
* (popup 裡的元素也能有 tooltip);toast 永遠最上(非阻斷通知不能被 modal 蓋掉)。
|
|
10
|
+
*/
|
|
11
|
+
export const layer = {
|
|
12
|
+
dialogBackdrop: 70,
|
|
13
|
+
dialog: 71,
|
|
14
|
+
popup: 75,
|
|
15
|
+
tooltip: 78,
|
|
16
|
+
toast: 80,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* `layer` 的 stylex 版。跨檔案 import 的值在 `stylex.create()` 裡不能靜態求值,
|
|
20
|
+
* 所以疊層要以「做好的樣式」而不是數字提供給其他元件。
|
|
21
|
+
*/
|
|
22
|
+
export const layerStyles = stylex.create({
|
|
23
|
+
dialogBackdrop: { zIndex: layer.dialogBackdrop },
|
|
24
|
+
dialog: { zIndex: layer.dialog },
|
|
25
|
+
popup: { zIndex: layer.popup },
|
|
26
|
+
tooltip: { zIndex: layer.tooltip },
|
|
27
|
+
toast: { zIndex: layer.toast },
|
|
28
|
+
});
|
|
4
29
|
export const growIn = stylex.keyframes({
|
|
5
30
|
from: { opacity: 0, scale: "1 0.97" },
|
|
6
31
|
to: { opacity: 1, scale: "1 1" },
|
|
@@ -23,5 +48,5 @@ export const popupStyles = stylex.create({
|
|
|
23
48
|
},
|
|
24
49
|
anchorWidth: { width: "var(--anchor-width)" },
|
|
25
50
|
availableHeight: { maxHeight: "var(--available-height)" },
|
|
26
|
-
positioner: { zIndex:
|
|
51
|
+
positioner: { zIndex: layer.popup, outline: "none" },
|
|
27
52
|
});
|