@anyknown/ui 0.6.1 → 0.8.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/README.md +6 -7
- package/dist/brand.css +111 -124
- package/dist/components/badge/Badge.d.ts +11 -3
- package/dist/components/badge/Badge.js +21 -3
- package/dist/components/button/Button.d.ts +3 -2
- package/dist/components/button/Button.js +32 -48
- package/dist/components/checkbox/Checkbox.js +24 -48
- package/dist/components/data-table/DataTable.d.ts +7 -1
- package/dist/components/data-table/DataTable.js +34 -34
- package/dist/components/dialog/Dialog.d.ts +6 -1
- package/dist/components/dialog/Dialog.js +11 -3
- package/dist/components/empty-state/EmptyState.js +1 -1
- package/dist/components/ghost/Ghost.d.ts +16 -0
- package/dist/components/ghost/Ghost.js +50 -0
- package/dist/components/group/Group.d.ts +66 -0
- package/dist/components/group/Group.js +166 -0
- package/dist/components/handoff-receipt/HandoffReceipt.js +12 -42
- package/dist/components/icon/Chevron.d.ts +9 -0
- package/dist/components/icon/Chevron.js +6 -0
- package/dist/components/icon/icon.d.ts +35 -0
- package/dist/components/icon/icon.js +10 -0
- package/dist/components/icon-button/IconButton.d.ts +17 -0
- package/dist/components/icon-button/IconButton.js +66 -0
- package/dist/components/live-dot/LiveDot.d.ts +7 -0
- package/dist/components/live-dot/LiveDot.js +35 -0
- package/dist/components/message/Message.d.ts +3 -1
- package/dist/components/message/Message.js +2 -2
- package/dist/components/page/Page.d.ts +64 -0
- package/dist/components/page/Page.js +163 -0
- package/dist/components/popover/Popover.js +1 -1
- package/dist/components/progress/Progress.js +49 -104
- package/dist/components/radio/Radio.js +17 -28
- package/dist/components/segmented/Segmented.d.ts +12 -0
- package/dist/components/segmented/Segmented.js +43 -0
- package/dist/components/settings-rows/SettingsRows.d.ts +25 -0
- package/dist/components/settings-rows/SettingsRows.js +63 -0
- package/dist/components/slider/Slider.d.ts +19 -0
- package/dist/components/slider/Slider.js +103 -0
- package/dist/components/spin/Spin.d.ts +5 -0
- package/dist/components/spin/Spin.js +25 -0
- package/dist/components/status-chip/StatusChip.d.ts +18 -0
- package/dist/components/status-chip/StatusChip.js +68 -0
- package/dist/components/switch/Switch.js +20 -63
- package/dist/components/table/Table.d.ts +39 -0
- package/dist/components/table/Table.js +125 -0
- package/dist/components/table/TableCells.d.ts +52 -0
- package/dist/components/table/TableCells.js +103 -0
- package/dist/components/tabs/Tabs.js +16 -48
- package/dist/components/text/Text.js +2 -2
- package/dist/components/toast/Toast.js +7 -8
- package/dist/index.d.ts +14 -0
- package/dist/index.js +14 -0
- package/dist/lib/layers.d.ts +7 -0
- package/dist/lib/layers.js +12 -0
- package/dist/themes.stylex.d.ts +54 -206
- package/dist/themes.stylex.js +55 -157
- package/dist/tokens.css +63 -46
- package/dist/tokens.stylex.d.ts +41 -54
- package/dist/tokens.stylex.js +64 -85
- package/package.json +2 -2
- package/dist/lib/paths.d.ts +0 -3
- package/dist/lib/paths.js +0 -11
- package/dist/lib/progress.d.ts +0 -2
- package/dist/lib/progress.js +0 -28
- package/dist/lib/silk.d.ts +0 -66
- package/dist/lib/silk.js +0 -337
- package/dist/lib/svgId.d.ts +0 -1
- package/dist/lib/svgId.js +0 -4
- package/dist/lib/weave.d.ts +0 -28
- package/dist/lib/weave.js +0 -83
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as stylex from "@stylexjs/stylex";
|
|
3
|
+
import { useId, useRef, useState } from "react";
|
|
4
|
+
import { color, font, motion, radius, shadow, space, text } from "../../tokens.stylex.js";
|
|
5
|
+
const REDUCED = "@media (prefers-reduced-motion: reduce)";
|
|
6
|
+
const ARROW_FRACTION = 0.05;
|
|
7
|
+
const styles = stylex.create({
|
|
8
|
+
root: { display: "flex", flexDirection: "column", gap: space.xs, fontFamily: font.body },
|
|
9
|
+
label: { fontSize: text.sm, fontWeight: 500, color: color.text },
|
|
10
|
+
control: {
|
|
11
|
+
position: "relative",
|
|
12
|
+
height: "1.5rem",
|
|
13
|
+
borderRadius: radius.full,
|
|
14
|
+
backgroundColor: color.layer4,
|
|
15
|
+
cursor: "pointer",
|
|
16
|
+
touchAction: "none",
|
|
17
|
+
outline: { default: "none", ":focus-visible": `2px solid ${color.focusRing}` },
|
|
18
|
+
outlineOffset: 2,
|
|
19
|
+
},
|
|
20
|
+
disabled: { cursor: "not-allowed", opacity: 0.5 },
|
|
21
|
+
fill: {
|
|
22
|
+
position: "absolute",
|
|
23
|
+
insetInlineStart: 0,
|
|
24
|
+
insetBlock: 0,
|
|
25
|
+
borderRadius: radius.full,
|
|
26
|
+
backgroundColor: color.borderStrong,
|
|
27
|
+
},
|
|
28
|
+
thumb: {
|
|
29
|
+
position: "absolute",
|
|
30
|
+
insetBlock: "0.2rem",
|
|
31
|
+
width: "1.6rem",
|
|
32
|
+
borderRadius: radius.md,
|
|
33
|
+
backgroundColor: color.surfaceRaised,
|
|
34
|
+
boxShadow: shadow.raised,
|
|
35
|
+
transitionProperty: "inset-inline-start",
|
|
36
|
+
transitionDuration: { default: motion.normal, [REDUCED]: "0s" },
|
|
37
|
+
transitionTimingFunction: motion.easeOut,
|
|
38
|
+
},
|
|
39
|
+
still: { transitionDuration: { default: "0s", [REDUCED]: "0s" } },
|
|
40
|
+
grown: (ratio) => ({ width: `calc(1.6rem + (100% - 1.6rem) * ${ratio})` }),
|
|
41
|
+
slid: (ratio) => ({ insetInlineStart: `calc((100% - 1.6rem) * ${ratio})` }),
|
|
42
|
+
});
|
|
43
|
+
function snap(raw, min, max, step) {
|
|
44
|
+
const clamped = Math.min(max, Math.max(min, raw));
|
|
45
|
+
if (step <= 0)
|
|
46
|
+
return clamped;
|
|
47
|
+
const decimals = (String(step).split(".")[1] ?? "").length;
|
|
48
|
+
const stepped = min + Math.round((clamped - min) / step) * step;
|
|
49
|
+
return Number(Math.min(max, Math.max(min, stepped)).toFixed(decimals));
|
|
50
|
+
}
|
|
51
|
+
export function Slider({ value, onChange, min = 0, max = 1, step = 0.01, label, valueText, disabled = false, sx, "aria-label": ariaLabel, }) {
|
|
52
|
+
const labelId = useId();
|
|
53
|
+
const control = useRef(null);
|
|
54
|
+
const thumb = useRef(null);
|
|
55
|
+
const [dragging, setDragging] = useState(false);
|
|
56
|
+
const current = snap(value, min, max, step);
|
|
57
|
+
const ratio = max === min ? 0 : (current - min) / (max - min);
|
|
58
|
+
function emit(raw) {
|
|
59
|
+
const next = snap(raw, min, max, step);
|
|
60
|
+
if (next !== current)
|
|
61
|
+
onChange(next);
|
|
62
|
+
}
|
|
63
|
+
function ratioAt(clientX) {
|
|
64
|
+
const track = control.current;
|
|
65
|
+
const knob = thumb.current;
|
|
66
|
+
if (track == null || knob == null)
|
|
67
|
+
return ratio;
|
|
68
|
+
const rect = track.getBoundingClientRect();
|
|
69
|
+
const span = rect.width - knob.offsetWidth;
|
|
70
|
+
if (span <= 0)
|
|
71
|
+
return ratio;
|
|
72
|
+
return (clientX - rect.left - knob.offsetWidth / 2) / span;
|
|
73
|
+
}
|
|
74
|
+
function drag(event) {
|
|
75
|
+
emit(min + ratioAt(event.clientX) * (max - min));
|
|
76
|
+
}
|
|
77
|
+
return (_jsxs("div", { ...stylex.props(styles.root, sx), children: [label != null && (_jsx("span", { id: labelId, ...stylex.props(styles.label), children: label })), _jsxs("div", { ref: control, role: "slider", tabIndex: disabled ? -1 : 0, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": current, "aria-valuetext": valueText?.(current), "aria-orientation": "horizontal", "aria-disabled": disabled || undefined, "aria-labelledby": label != null ? labelId : undefined, "aria-label": ariaLabel, onPointerDown: (event) => {
|
|
78
|
+
if (disabled)
|
|
79
|
+
return;
|
|
80
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
81
|
+
event.currentTarget.focus();
|
|
82
|
+
setDragging(true);
|
|
83
|
+
drag(event);
|
|
84
|
+
}, onPointerMove: (event) => {
|
|
85
|
+
if (dragging)
|
|
86
|
+
drag(event);
|
|
87
|
+
}, onPointerUp: () => setDragging(false), onPointerCancel: () => setDragging(false), onKeyDown: (event) => {
|
|
88
|
+
if (disabled)
|
|
89
|
+
return;
|
|
90
|
+
const nudge = (max - min) * ARROW_FRACTION;
|
|
91
|
+
if (event.key === "ArrowRight" || event.key === "ArrowUp")
|
|
92
|
+
emit(current + nudge);
|
|
93
|
+
else if (event.key === "ArrowLeft" || event.key === "ArrowDown")
|
|
94
|
+
emit(current - nudge);
|
|
95
|
+
else if (event.key === "Home")
|
|
96
|
+
emit(min);
|
|
97
|
+
else if (event.key === "End")
|
|
98
|
+
emit(max);
|
|
99
|
+
else
|
|
100
|
+
return;
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
}, ...stylex.props(styles.control, disabled && styles.disabled), children: [_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.fill, styles.grown(ratio)) }), _jsx("span", { ref: thumb, "aria-hidden": "true", ...stylex.props(styles.thumb, dragging && styles.still, styles.slid(ratio)) })] })] }));
|
|
103
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as stylex from "@stylexjs/stylex";
|
|
3
|
+
/** `.spin`: 12px ring, the one thing on a button that moves while it waits. */
|
|
4
|
+
const turn = stylex.keyframes({ to: { transform: "rotate(360deg)" } });
|
|
5
|
+
const styles = stylex.create({
|
|
6
|
+
root: {
|
|
7
|
+
animationDuration: "0.7s",
|
|
8
|
+
animationIterationCount: "infinite",
|
|
9
|
+
animationName: { default: turn, "@media (prefers-reduced-motion: reduce)": "none" },
|
|
10
|
+
animationTimingFunction: "linear",
|
|
11
|
+
borderColor: "color-mix(in srgb, currentColor 28%, transparent)",
|
|
12
|
+
borderRadius: "50%",
|
|
13
|
+
borderStyle: "solid",
|
|
14
|
+
borderTopColor: "currentColor",
|
|
15
|
+
borderWidth: 2,
|
|
16
|
+
boxSizing: "border-box",
|
|
17
|
+
flex: "none",
|
|
18
|
+
height: 12,
|
|
19
|
+
width: 12,
|
|
20
|
+
},
|
|
21
|
+
small: { borderWidth: 1.5, height: 9, width: 9 },
|
|
22
|
+
});
|
|
23
|
+
export function Spin({ small = false, sx }) {
|
|
24
|
+
return _jsx("span", { "aria-hidden": "true", ...stylex.props(styles.root, small && styles.small, sx) });
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as stylex from "@stylexjs/stylex";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
export type StatusChipProps = {
|
|
4
|
+
variant: "r" | "w" | "d" | "n" | "a" | "f" | "plain";
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
sx?: stylex.StyleXStyles;
|
|
7
|
+
};
|
|
8
|
+
export declare function StatusChip({ variant, children, sx }: StatusChipProps): import("react").JSX.Element;
|
|
9
|
+
export type PillProps = {
|
|
10
|
+
/** A dot in front, coloured by what the thing is doing. */
|
|
11
|
+
status?: "live" | "paused" | "done";
|
|
12
|
+
/** The sub thread's name: body face, text colour, truncates. */
|
|
13
|
+
title?: boolean;
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
sx?: stylex.StyleXStyles;
|
|
16
|
+
};
|
|
17
|
+
/** `.pill-s`: the 22px mono pills a fold's first line is made of. */
|
|
18
|
+
export declare function Pill({ status, title, children, sx }: PillProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as stylex from "@stylexjs/stylex";
|
|
3
|
+
import { color, font, space, tone, type } from "../../tokens.stylex.js";
|
|
4
|
+
import { Spin } from "../spin/Spin.js";
|
|
5
|
+
/**
|
|
6
|
+
* `.tchip` / `.achip`: a mono word in a 16px pill. `r` read-only (outline), `w` writes (layer),
|
|
7
|
+
* `d` destructive (warning fill), `n` unmarked (faint outline), `a` active (accent, spinning),
|
|
8
|
+
* `f` failed (warning outline + dot), `plain` the catalogue's auth chip.
|
|
9
|
+
*/
|
|
10
|
+
const styles = stylex.create({
|
|
11
|
+
root: {
|
|
12
|
+
alignItems: "center",
|
|
13
|
+
borderRadius: "1rem",
|
|
14
|
+
display: "inline-flex",
|
|
15
|
+
flex: "none",
|
|
16
|
+
fontFamily: font.mono,
|
|
17
|
+
fontSize: type.t1,
|
|
18
|
+
gap: space.xxs,
|
|
19
|
+
lineHeight: "16px",
|
|
20
|
+
paddingInline: 6,
|
|
21
|
+
whiteSpace: "nowrap",
|
|
22
|
+
},
|
|
23
|
+
r: { boxShadow: `inset 0 0 0 1px ${color.border}`, color: color.textMuted },
|
|
24
|
+
w: { backgroundColor: color.layer4, color: color.text },
|
|
25
|
+
d: { backgroundColor: color.warning, color: color.bg },
|
|
26
|
+
n: { boxShadow: `inset 0 0 0 1px ${color.border}`, color: tone.faint },
|
|
27
|
+
a: { backgroundColor: color.accentSubtle, color: color.text },
|
|
28
|
+
f: {
|
|
29
|
+
boxShadow: `inset 0 0 0 1px color-mix(in srgb, ${color.warning} 55%, transparent)`,
|
|
30
|
+
color: color.warning,
|
|
31
|
+
},
|
|
32
|
+
plain: { backgroundColor: color.layer3, color: color.textMuted, textAlign: "center" },
|
|
33
|
+
dot: { backgroundColor: color.warning, borderRadius: "50%", flex: "none", height: 6, width: 6 },
|
|
34
|
+
pill: {
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
backgroundColor: color.layer3,
|
|
37
|
+
borderRadius: 11,
|
|
38
|
+
color: color.textMuted,
|
|
39
|
+
display: "inline-flex",
|
|
40
|
+
fontFamily: font.mono,
|
|
41
|
+
fontSize: type.t1,
|
|
42
|
+
gap: space.xxs,
|
|
43
|
+
height: 22,
|
|
44
|
+
paddingInline: space.xs,
|
|
45
|
+
whiteSpace: "nowrap",
|
|
46
|
+
},
|
|
47
|
+
status: { paddingInlineStart: 6 },
|
|
48
|
+
live: { backgroundColor: color.accent, borderRadius: "50%", flex: "none", height: 6, width: 6 },
|
|
49
|
+
paused: { backgroundColor: color.warning },
|
|
50
|
+
done: { backgroundColor: tone.faint },
|
|
51
|
+
title: {
|
|
52
|
+
color: color.text,
|
|
53
|
+
display: "inline-block",
|
|
54
|
+
fontFamily: font.body,
|
|
55
|
+
fontSize: type.t2,
|
|
56
|
+
lineHeight: "20px",
|
|
57
|
+
minWidth: 0,
|
|
58
|
+
overflow: "hidden",
|
|
59
|
+
textOverflow: "ellipsis",
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
export function StatusChip({ variant, children, sx }) {
|
|
63
|
+
return (_jsxs("span", { ...stylex.props(styles.root, styles[variant], sx), children: [variant === "a" && _jsx(Spin, { small: true }), variant === "f" && _jsx("i", { ...stylex.props(styles.dot), "aria-hidden": "true" }), children] }));
|
|
64
|
+
}
|
|
65
|
+
/** `.pill-s`: the 22px mono pills a fold's first line is made of. */
|
|
66
|
+
export function Pill({ status, title = false, children, sx }) {
|
|
67
|
+
return (_jsxs("span", { ...stylex.props(styles.pill, status !== undefined && styles.status, title && styles.title, sx), children: [status !== undefined && (_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.live, status === "paused" && styles.paused, status === "done" && styles.done) })), children] }));
|
|
68
|
+
}
|
|
@@ -2,15 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import * as stylex from "@stylexjs/stylex";
|
|
3
3
|
import { useId } from "react";
|
|
4
4
|
import { styled } from "../../lib/styled.js";
|
|
5
|
-
import { useSvgId } from "../../lib/svgId.js";
|
|
6
5
|
import { useControllableState } from "../../lib/useControllableState.js";
|
|
7
|
-
import {
|
|
8
|
-
import { color, font, motion, radius, space, text, yarn } from "../../tokens.stylex.js";
|
|
6
|
+
import { color, font, motion, radius, space, text } from "../../tokens.stylex.js";
|
|
9
7
|
import { useFieldControl } from "../label/fieldContext.js";
|
|
10
8
|
const REDUCED = "@media (prefers-reduced-motion: reduce)";
|
|
11
|
-
const DARK = "@media (prefers-color-scheme: dark)";
|
|
12
|
-
// 藥丸 42×20(1:1 CSS px),module scope 織一次(固定種子 → 恆定;純幾何,SSR 安全)
|
|
13
|
-
const CLOTH = buildWeave({ w: 42, h: 20, ox: 1, oy: 1 }, weaveRand());
|
|
14
9
|
const styles = stylex.create({
|
|
15
10
|
root: {
|
|
16
11
|
display: "flex",
|
|
@@ -24,75 +19,37 @@ const styles = stylex.create({
|
|
|
24
19
|
input: { position: "absolute", opacity: 0, width: "2.75rem", height: "1.4rem", margin: 0 },
|
|
25
20
|
track: {
|
|
26
21
|
flex: "none",
|
|
22
|
+
position: "relative",
|
|
23
|
+
boxSizing: "border-box",
|
|
27
24
|
width: "2.75rem",
|
|
28
25
|
height: "1.4rem",
|
|
29
26
|
marginTop: "0.1rem",
|
|
30
27
|
borderRadius: radius.full,
|
|
28
|
+
backgroundColor: color.borderStrong,
|
|
29
|
+
transitionProperty: "background-color",
|
|
30
|
+
transitionDuration: { default: motion.fast, [REDUCED]: "0s" },
|
|
31
31
|
outline: { default: "none", ":has(:focus-visible)": `2px solid ${color.focusRing}` },
|
|
32
32
|
outlineOffset: 3,
|
|
33
33
|
},
|
|
34
|
-
|
|
35
|
-
guide: { stroke: color.borderStrong, strokeWidth: 1.5, strokeLinecap: "round", fill: "none" },
|
|
36
|
-
// 開:布從左織進來(wipe clip 的 width 推進,紗本身不動 — 同一塊布被逐漸織出);
|
|
37
|
-
// 關:整塊布 scale 到 0 收掉,width/opacity 等 scale 跑完才歸零。
|
|
38
|
-
// 藥丸形狀是另一支固定 clip:左圓角從第一幀就完整,前緣是織布機的直線 fell。
|
|
39
|
-
cloth: {
|
|
40
|
-
opacity: 0,
|
|
41
|
-
scale: "0",
|
|
42
|
-
transformBox: "fill-box",
|
|
43
|
-
transformOrigin: "center",
|
|
44
|
-
transitionProperty: "scale, opacity",
|
|
45
|
-
transitionDuration: { default: "200ms, 0s", [REDUCED]: "0s" },
|
|
46
|
-
transitionTimingFunction: "ease-in",
|
|
47
|
-
transitionDelay: { default: "0s, 200ms", [REDUCED]: "0s" },
|
|
48
|
-
filter: {
|
|
49
|
-
default: "drop-shadow(0 1px 1.5px rgba(18, 60, 49, 0.30))",
|
|
50
|
-
[DARK]: "drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45))",
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
clothOn: {
|
|
54
|
-
opacity: 1,
|
|
55
|
-
scale: "1",
|
|
56
|
-
transitionDuration: { default: "0s, 0s", [REDUCED]: "0s" },
|
|
57
|
-
transitionDelay: "0s",
|
|
58
|
-
},
|
|
59
|
-
pillclip: {
|
|
60
|
-
width: 0,
|
|
61
|
-
transitionProperty: "width",
|
|
62
|
-
transitionDuration: { default: "0s", [REDUCED]: "0s" },
|
|
63
|
-
transitionDelay: { default: "200ms", [REDUCED]: "0s" },
|
|
64
|
-
},
|
|
65
|
-
pillclipOn: {
|
|
66
|
-
width: 42,
|
|
67
|
-
transitionDuration: { default: "240ms", [REDUCED]: "0s" },
|
|
68
|
-
transitionTimingFunction: "cubic-bezier(0.32, 0.85, 0.45, 1)",
|
|
69
|
-
transitionDelay: "0s",
|
|
70
|
-
},
|
|
71
|
-
yarns: { fill: "none", strokeLinecap: "round" },
|
|
72
|
-
un: { stroke: yarn.un },
|
|
73
|
-
sh: { stroke: yarn.sh, opacity: 0.5 },
|
|
74
|
-
y0: { stroke: yarn.y0 },
|
|
75
|
-
y1: { stroke: yarn.y1 },
|
|
76
|
-
y2: { stroke: yarn.y2 },
|
|
77
|
-
y3: { stroke: yarn.y3 },
|
|
78
|
-
y4: { stroke: yarn.y4 },
|
|
79
|
-
hi: { stroke: yarn.hi, opacity: 0.45 },
|
|
34
|
+
trackOn: { backgroundColor: color.accent },
|
|
80
35
|
thumb: {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
36
|
+
position: "absolute",
|
|
37
|
+
insetBlockStart: 2,
|
|
38
|
+
insetInlineStart: 2,
|
|
39
|
+
width: "calc(1.4rem - 4px)",
|
|
40
|
+
height: "calc(1.4rem - 4px)",
|
|
41
|
+
borderRadius: radius.full,
|
|
42
|
+
backgroundColor: "#FFFFFF",
|
|
84
43
|
translate: "0 0",
|
|
85
|
-
transitionProperty: "translate,
|
|
86
|
-
transitionDuration: { default:
|
|
87
|
-
transitionTimingFunction: "
|
|
44
|
+
transitionProperty: "translate, background-color",
|
|
45
|
+
transitionDuration: { default: "180ms", [REDUCED]: "0s" },
|
|
46
|
+
transitionTimingFunction: "ease-out",
|
|
88
47
|
},
|
|
89
|
-
thumbOn: { translate: "
|
|
48
|
+
thumbOn: { translate: "1.35rem 0", backgroundColor: color.accentText },
|
|
90
49
|
labelText: { display: "block", fontWeight: 500, fontSize: text.sm, color: color.text },
|
|
91
50
|
description: { display: "block", fontSize: text.xs, color: color.textMuted },
|
|
92
51
|
});
|
|
93
|
-
const BUCKETS = [styles.y0, styles.y1, styles.y2, styles.y3, styles.y4];
|
|
94
52
|
export function Switch({ label, description, onCheckedChange, checked, defaultChecked, onChange, sx, ...props }) {
|
|
95
|
-
const clipId = useSvgId("ak-weave");
|
|
96
53
|
const base = useId();
|
|
97
54
|
const labelId = `${base}label`;
|
|
98
55
|
const descriptionId = `${base}description`;
|
|
@@ -101,8 +58,8 @@ export function Switch({ label, description, onCheckedChange, checked, defaultCh
|
|
|
101
58
|
.filter(Boolean)
|
|
102
59
|
.join(" ");
|
|
103
60
|
const [isOn, setOn] = useControllableState(checked, defaultChecked ?? false, onCheckedChange);
|
|
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) => {
|
|
61
|
+
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, isOn && styles.trackOn), 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
62
|
setOn(event.currentTarget.checked);
|
|
106
63
|
onChange?.(event);
|
|
107
|
-
}, ...styled(props, styles.input) }),
|
|
64
|
+
}, ...styled(props, styles.input) }), _jsx("span", { "aria-hidden": "true", ...stylex.props(styles.thumb, isOn && styles.thumbOn) })] })] }));
|
|
108
65
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as stylex from "@stylexjs/stylex";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
type Sx = {
|
|
4
|
+
sx?: stylex.StyleXStyles;
|
|
5
|
+
};
|
|
6
|
+
export type TableProps = {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
} & Sx;
|
|
9
|
+
export declare function Table({ children, sx }: TableProps): import("react").JSX.Element;
|
|
10
|
+
export type HeadProps = {
|
|
11
|
+
columns: string;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
sticky?: boolean;
|
|
14
|
+
} & Sx;
|
|
15
|
+
/** The one mono line above the rows; `columns` is the grid template every row shares. */
|
|
16
|
+
export declare function Head({ columns, children, sticky, sx }: HeadProps): import("react").JSX.Element;
|
|
17
|
+
export type TrProps = {
|
|
18
|
+
columns: string;
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
hover?: boolean;
|
|
21
|
+
} & Sx;
|
|
22
|
+
export declare function Tr({ columns, children, hover, sx }: TrProps): import("react").JSX.Element;
|
|
23
|
+
export declare function Detail({ id, children, sx }: {
|
|
24
|
+
id?: string;
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
} & Sx): import("react").JSX.Element;
|
|
27
|
+
/** `.moreRow`: the last line of a ledger that has more, 40px, centred. */
|
|
28
|
+
export declare function MoreRow({ children, onPress, sx }: {
|
|
29
|
+
children: ReactNode;
|
|
30
|
+
onPress: () => void;
|
|
31
|
+
} & Sx): import("react").JSX.Element;
|
|
32
|
+
/**
|
|
33
|
+
* `.listscroll`: a ledger that scrolls on its own to the bottom of the window, the head stuck to
|
|
34
|
+
* its top.
|
|
35
|
+
*/
|
|
36
|
+
export declare function ListScroll({ children, sx }: {
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
} & Sx): import("react").JSX.Element;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as stylex from "@stylexjs/stylex";
|
|
3
|
+
import { color, corner, font, motion, space, type } from "../../tokens.stylex.js";
|
|
4
|
+
/**
|
|
5
|
+
* `.tbl`: a ledger. The head is one mono line, every row is 34px, identifiers and numbers are
|
|
6
|
+
* mono and numbers sit on the right. On a phone the head goes and each row wraps to two lines,
|
|
7
|
+
* in the order the caller gives each cell.
|
|
8
|
+
*/
|
|
9
|
+
const REDUCED = "@media (prefers-reduced-motion: reduce)";
|
|
10
|
+
const PHONE = "@media (max-width: 45rem)";
|
|
11
|
+
const styles = stylex.create({
|
|
12
|
+
table: {
|
|
13
|
+
backgroundColor: color.surface,
|
|
14
|
+
borderRadius: corner.card,
|
|
15
|
+
boxShadow: `inset 0 0 0 1px ${color.border}`,
|
|
16
|
+
color: color.text,
|
|
17
|
+
fontSize: type.t2,
|
|
18
|
+
lineHeight: type.body,
|
|
19
|
+
minWidth: 0,
|
|
20
|
+
},
|
|
21
|
+
cols: (columns) => ({ gridTemplateColumns: columns }),
|
|
22
|
+
head: {
|
|
23
|
+
alignItems: "center",
|
|
24
|
+
borderRadius: `${corner.card} ${corner.card} 0 0`,
|
|
25
|
+
color: color.textMuted,
|
|
26
|
+
display: { default: "grid", [PHONE]: "none" },
|
|
27
|
+
fontFamily: font.mono,
|
|
28
|
+
fontSize: type.t1,
|
|
29
|
+
gap: space.sm,
|
|
30
|
+
height: 28,
|
|
31
|
+
paddingInline: space.sm,
|
|
32
|
+
},
|
|
33
|
+
sticky: { backgroundColor: color.surface, position: "sticky", top: 0, zIndex: 1 },
|
|
34
|
+
row: {
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
borderRadius: { default: 0, ":last-child": `0 0 ${corner.card} ${corner.card}` },
|
|
37
|
+
boxShadow: `inset 0 1px 0 ${color.border}`,
|
|
38
|
+
columnGap: { default: space.sm, [PHONE]: space.xs },
|
|
39
|
+
display: { default: "grid", [PHONE]: "flex" },
|
|
40
|
+
flexWrap: "wrap",
|
|
41
|
+
fontSize: type.t2,
|
|
42
|
+
height: { default: 34, [PHONE]: "auto" },
|
|
43
|
+
lineHeight: { default: type.body, [PHONE]: "1.4" },
|
|
44
|
+
minHeight: { default: 34, [PHONE]: 52 },
|
|
45
|
+
paddingBlock: { default: 0, [PHONE]: space.xs },
|
|
46
|
+
paddingInline: space.sm,
|
|
47
|
+
rowGap: 0,
|
|
48
|
+
},
|
|
49
|
+
hover: { backgroundColor: { default: "transparent", ":hover": color.layer3 } },
|
|
50
|
+
detail: {
|
|
51
|
+
boxShadow: `inset 0 1px 0 ${color.border}`,
|
|
52
|
+
paddingBlock: `0 ${space.xs}`,
|
|
53
|
+
paddingInline: space.sm,
|
|
54
|
+
},
|
|
55
|
+
more: {
|
|
56
|
+
alignItems: "center",
|
|
57
|
+
backgroundColor: { default: "transparent", ":hover": color.layer3 },
|
|
58
|
+
borderRadius: `0 0 ${corner.card} ${corner.card}`,
|
|
59
|
+
borderStyle: "none",
|
|
60
|
+
borderWidth: 0,
|
|
61
|
+
boxShadow: `inset 0 1px 0 ${color.border}`,
|
|
62
|
+
color: { default: color.textMuted, ":hover": color.text },
|
|
63
|
+
cursor: "pointer",
|
|
64
|
+
display: "flex",
|
|
65
|
+
fontFamily: "inherit",
|
|
66
|
+
fontSize: type.t2,
|
|
67
|
+
height: 40,
|
|
68
|
+
justifyContent: "center",
|
|
69
|
+
lineHeight: type.body,
|
|
70
|
+
margin: 0,
|
|
71
|
+
outline: { default: "none", ":focus-visible": `2px solid ${color.accent}` },
|
|
72
|
+
outlineOffset: -2,
|
|
73
|
+
padding: 0,
|
|
74
|
+
transitionDuration: { default: motion.fast, [REDUCED]: "0s" },
|
|
75
|
+
transitionProperty: "background-color, color",
|
|
76
|
+
width: "100%",
|
|
77
|
+
},
|
|
78
|
+
scroll: {
|
|
79
|
+
borderRadius: corner.card,
|
|
80
|
+
maxHeight: "calc(100dvh - var(--akn-off, 22rem))",
|
|
81
|
+
minHeight: "12rem",
|
|
82
|
+
overflow: "auto",
|
|
83
|
+
overscrollBehavior: "contain",
|
|
84
|
+
scrollbarColor: {
|
|
85
|
+
default: "transparent transparent",
|
|
86
|
+
":hover": `color-mix(in srgb, ${color.text} 24%, transparent) transparent`,
|
|
87
|
+
},
|
|
88
|
+
scrollbarWidth: "thin",
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
export function Table({ children, sx }) {
|
|
92
|
+
return _jsx("div", { ...stylex.props(styles.table, sx), children: children });
|
|
93
|
+
}
|
|
94
|
+
/** The one mono line above the rows; `columns` is the grid template every row shares. */
|
|
95
|
+
export function Head({ columns, children, sticky = false, sx }) {
|
|
96
|
+
return (_jsx("div", { ...stylex.props(styles.head, styles.cols(columns), sticky && styles.sticky, sx), children: children }));
|
|
97
|
+
}
|
|
98
|
+
export function Tr({ columns, children, hover = false, sx }) {
|
|
99
|
+
return _jsx("div", { ...stylex.props(styles.row, styles.cols(columns), hover && styles.hover, sx), children: children });
|
|
100
|
+
}
|
|
101
|
+
export function Detail({ id, children, sx }) {
|
|
102
|
+
return (_jsx("div", { ...(id ? { id } : {}), ...stylex.props(styles.detail, sx), children: children }));
|
|
103
|
+
}
|
|
104
|
+
/** `.moreRow`: the last line of a ledger that has more, 40px, centred. */
|
|
105
|
+
export function MoreRow({ children, onPress, sx }) {
|
|
106
|
+
return (_jsx("button", { type: "button", onClick: onPress, ...stylex.props(styles.more, sx), children: children }));
|
|
107
|
+
}
|
|
108
|
+
/** Reads where the list starts and leaves 24px under it, again whenever the window changes. */
|
|
109
|
+
function fit(node) {
|
|
110
|
+
if (node === null)
|
|
111
|
+
return;
|
|
112
|
+
const measure = () => {
|
|
113
|
+
node.style.setProperty("--akn-off", `${Math.round(node.getBoundingClientRect().top + 24)}px`);
|
|
114
|
+
};
|
|
115
|
+
measure();
|
|
116
|
+
window.addEventListener("resize", measure);
|
|
117
|
+
return () => window.removeEventListener("resize", measure);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* `.listscroll`: a ledger that scrolls on its own to the bottom of the window, the head stuck to
|
|
121
|
+
* its top.
|
|
122
|
+
*/
|
|
123
|
+
export function ListScroll({ children, sx }) {
|
|
124
|
+
return (_jsx("div", { ref: fit, ...stylex.props(styles.scroll, sx), children: children }));
|
|
125
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as stylex from "@stylexjs/stylex";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
type Sx = {
|
|
4
|
+
sx?: stylex.StyleXStyles;
|
|
5
|
+
};
|
|
6
|
+
export type CellProps = {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
mono?: boolean;
|
|
9
|
+
num?: boolean;
|
|
10
|
+
faint?: boolean;
|
|
11
|
+
/** Where the cell lands once the row wraps on a phone. */
|
|
12
|
+
order?: number;
|
|
13
|
+
/** On a phone the cell opens with `· `, the way the prototype joins the second line. */
|
|
14
|
+
prefixed?: boolean;
|
|
15
|
+
/** On a phone the cell goes to the end of its line. */
|
|
16
|
+
pushed?: boolean;
|
|
17
|
+
grow?: boolean;
|
|
18
|
+
/** Not drawn on a phone. */
|
|
19
|
+
hidden?: boolean;
|
|
20
|
+
} & Sx;
|
|
21
|
+
export declare function Cell({ children, mono, num, faint, order, prefixed, pushed, grow, hidden, sx }: CellProps): import("react").JSX.Element;
|
|
22
|
+
export type StatusCellProps = {
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
warn?: boolean;
|
|
25
|
+
order?: number;
|
|
26
|
+
pushed?: boolean;
|
|
27
|
+
} & Sx;
|
|
28
|
+
/** The state column: nothing when fine, a warning dot and a mono code when not. */
|
|
29
|
+
export declare function StatusCell({ children, warn, order, pushed, sx }: StatusCellProps): import("react").JSX.Element;
|
|
30
|
+
/** The line break a phone row wraps at; nothing on a desk. */
|
|
31
|
+
export declare function Break({ order }: {
|
|
32
|
+
order?: number;
|
|
33
|
+
}): import("react").JSX.Element;
|
|
34
|
+
export type ToggleProps = {
|
|
35
|
+
open: boolean;
|
|
36
|
+
onPress: () => void;
|
|
37
|
+
label: string;
|
|
38
|
+
controls?: string;
|
|
39
|
+
order?: number;
|
|
40
|
+
} & Sx;
|
|
41
|
+
/** `.rowtog`: the chevron at the end of a row that has a detail under it. */
|
|
42
|
+
export declare function Toggle({ open, onPress, label, controls, order, sx }: ToggleProps): import("react").JSX.Element;
|
|
43
|
+
export type SubjectProps = {
|
|
44
|
+
children: ReactNode;
|
|
45
|
+
onPress: () => void;
|
|
46
|
+
title?: string;
|
|
47
|
+
order?: number;
|
|
48
|
+
grow?: boolean;
|
|
49
|
+
} & Sx;
|
|
50
|
+
/** `.subj`: a mono identifier that is also the way to filter by it. */
|
|
51
|
+
export declare function Subject({ children, onPress, title, order, grow, sx }: SubjectProps): import("react").JSX.Element;
|
|
52
|
+
export {};
|