@anyknown/ui 0.7.0 → 0.8.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/README.md +7 -8
- package/dist/brand.css +101 -214
- 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/dialog/Dialog.js +1 -1
- 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/input/Input.d.ts +3 -1
- package/dist/components/input/Input.js +3 -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/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 +11 -0
- package/dist/index.js +11 -0
- package/dist/themes.stylex.d.ts +33 -496
- package/dist/themes.stylex.js +25 -253
- package/dist/tokens.css +53 -126
- package/dist/tokens.stylex.d.ts +36 -54
- package/dist/tokens.stylex.js +62 -90
- package/package.json +1 -1
- 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
|
@@ -2,16 +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 {
|
|
6
|
-
import { buildWeave, weaveRand } from "../../lib/weave.js";
|
|
7
|
-
import { color, font, motion, radius, space, text, yarn } from "../../tokens.stylex.js";
|
|
5
|
+
import { color, font, motion, radius, space, text } from "../../tokens.stylex.js";
|
|
8
6
|
import { useFieldControl } from "../label/fieldContext.js";
|
|
9
7
|
import { useRadioGroup } from "./RadioGroup.js";
|
|
10
8
|
const REDUCED = "@media (prefers-reduced-motion: reduce)";
|
|
11
|
-
// 鏡頭 dot:布像背景一樣在後面延伸(與 checkbox 同源幾何,module scope 織一次),
|
|
12
|
-
// 圓形只是取景框 — 選中 = 孔徑(circle r)從 0 打開,布本身完全不動。
|
|
13
|
-
// 孔徑只開到 r 6.8:維持 radio 的標準構成(外環 + surface 空隙 + 內實心圓)。
|
|
14
|
-
const CLOTH = buildWeave({ w: 14.8, h: 14.8, s: 24 / 14.8 }, weaveRand());
|
|
15
9
|
const styles = stylex.create({
|
|
16
10
|
root: {
|
|
17
11
|
display: "flex",
|
|
@@ -35,44 +29,39 @@ const styles = stylex.create({
|
|
|
35
29
|
input: { position: "absolute", opacity: 0, width: "1.05rem", height: "1.05rem", margin: 0 },
|
|
36
30
|
dot: {
|
|
37
31
|
flex: "none",
|
|
32
|
+
boxSizing: "border-box",
|
|
33
|
+
display: "grid",
|
|
34
|
+
placeItems: "center",
|
|
38
35
|
width: "1.05rem",
|
|
39
36
|
height: "1.05rem",
|
|
40
37
|
marginTop: "0.16rem",
|
|
41
|
-
borderWidth: 1,
|
|
38
|
+
borderWidth: 1.5,
|
|
42
39
|
borderStyle: "solid",
|
|
43
40
|
borderColor: color.borderStrong,
|
|
44
41
|
borderRadius: radius.full,
|
|
45
|
-
backgroundColor: color.
|
|
42
|
+
backgroundColor: color.bg,
|
|
46
43
|
transitionProperty: "border-color",
|
|
47
44
|
transitionDuration: { default: motion.fast, [REDUCED]: "0s" },
|
|
48
45
|
outline: { default: "none", ":has(:focus-visible)": `2px solid ${color.focusRing}` },
|
|
49
46
|
outlineOffset: 2,
|
|
50
47
|
},
|
|
51
48
|
dotOn: { borderColor: color.accent },
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
fill: {
|
|
50
|
+
width: "0.55rem",
|
|
51
|
+
height: "0.55rem",
|
|
52
|
+
borderRadius: radius.full,
|
|
53
|
+
backgroundColor: color.accent,
|
|
54
|
+
scale: "0",
|
|
55
|
+
transitionProperty: "scale",
|
|
56
|
+
transitionDuration: { default: "160ms", [REDUCED]: "0s" },
|
|
57
|
+
transitionTimingFunction: "ease-out",
|
|
58
58
|
},
|
|
59
|
-
|
|
60
|
-
yarns: { fill: "none", strokeLinecap: "round" },
|
|
61
|
-
un: { stroke: yarn.un },
|
|
62
|
-
sh: { stroke: yarn.sh, opacity: 0.5 },
|
|
63
|
-
y0: { stroke: yarn.y0 },
|
|
64
|
-
y1: { stroke: yarn.y1 },
|
|
65
|
-
y2: { stroke: yarn.y2 },
|
|
66
|
-
y3: { stroke: yarn.y3 },
|
|
67
|
-
y4: { stroke: yarn.y4 },
|
|
68
|
-
hi: { stroke: yarn.hi, opacity: 0.45 },
|
|
59
|
+
fillOn: { scale: "1" },
|
|
69
60
|
labelText: { display: "block", fontWeight: 500, fontSize: text.sm, color: color.text },
|
|
70
61
|
description: { display: "block", fontSize: text.xs, color: color.textMuted },
|
|
71
62
|
});
|
|
72
|
-
const BUCKETS = [styles.y0, styles.y1, styles.y2, styles.y3, styles.y4];
|
|
73
63
|
export function Radio({ value, label, description, onChange, disabled, ...props }) {
|
|
74
64
|
const group = useRadioGroup();
|
|
75
|
-
const clipId = useSvgId("ak-lens");
|
|
76
65
|
const base = useId();
|
|
77
66
|
const labelId = `${base}label`;
|
|
78
67
|
const descriptionId = `${base}description`;
|
|
@@ -85,5 +74,5 @@ export function Radio({ value, label, description, onChange, disabled, ...props
|
|
|
85
74
|
if (event.currentTarget.checked)
|
|
86
75
|
group.select(value);
|
|
87
76
|
onChange?.(event);
|
|
88
|
-
}, ...styled(props, styles.input) }),
|
|
77
|
+
}, ...styled(props, styles.input) }), _jsx("span", { "aria-hidden": "true", ...stylex.props(styles.fill, checked && styles.fillOn) })] }), (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 }))] }))] }));
|
|
89
78
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as stylex from "@stylexjs/stylex";
|
|
2
|
+
export type SegmentedProps<T extends string> = {
|
|
3
|
+
value: T;
|
|
4
|
+
options: {
|
|
5
|
+
value: T;
|
|
6
|
+
label: string;
|
|
7
|
+
}[];
|
|
8
|
+
onChange: (value: T) => void;
|
|
9
|
+
label: string;
|
|
10
|
+
sx?: stylex.StyleXStyles;
|
|
11
|
+
};
|
|
12
|
+
export declare function Segmented<T extends string>({ value, options, onChange, label, sx }: SegmentedProps<T>): import("react").JSX.Element;
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
+
/** `.seg`: a few words in one outline; the chosen one sits on a layer. */
|
|
5
|
+
const REDUCED = "@media (prefers-reduced-motion: reduce)";
|
|
6
|
+
const PHONE = "@media (max-width: 45rem)";
|
|
7
|
+
const styles = stylex.create({
|
|
8
|
+
root: {
|
|
9
|
+
alignSelf: "flex-start",
|
|
10
|
+
borderRadius: corner.md,
|
|
11
|
+
boxShadow: `inset 0 0 0 1px ${color.border}`,
|
|
12
|
+
display: "inline-flex",
|
|
13
|
+
gap: 2,
|
|
14
|
+
maxWidth: "100%",
|
|
15
|
+
overflowX: { default: "visible", [PHONE]: "auto" },
|
|
16
|
+
padding: 2,
|
|
17
|
+
scrollbarWidth: "none",
|
|
18
|
+
},
|
|
19
|
+
item: {
|
|
20
|
+
backgroundColor: { default: "transparent", ":hover": "transparent" },
|
|
21
|
+
borderRadius: corner.sm,
|
|
22
|
+
borderStyle: "none",
|
|
23
|
+
borderWidth: 0,
|
|
24
|
+
color: { default: color.textMuted, ":hover": color.text },
|
|
25
|
+
cursor: "pointer",
|
|
26
|
+
fontFamily: font.body,
|
|
27
|
+
fontSize: type.t2,
|
|
28
|
+
height: { default: 28, [PHONE]: 40 },
|
|
29
|
+
lineHeight: type.body,
|
|
30
|
+
margin: 0,
|
|
31
|
+
outline: { default: "none", ":focus-visible": `2px solid ${color.accent}` },
|
|
32
|
+
outlineOffset: -2,
|
|
33
|
+
paddingBlock: 0,
|
|
34
|
+
paddingInline: space.sm,
|
|
35
|
+
transitionDuration: { default: motion.fast, [REDUCED]: "0s" },
|
|
36
|
+
transitionProperty: "background-color, color",
|
|
37
|
+
whiteSpace: "nowrap",
|
|
38
|
+
},
|
|
39
|
+
on: { backgroundColor: color.layer4, color: color.text },
|
|
40
|
+
});
|
|
41
|
+
export function Segmented({ value, options, onChange, label, sx }) {
|
|
42
|
+
return (_jsx("div", { "aria-label": label, ...stylex.props(styles.root, sx), children: options.map((one) => (_jsx("button", { type: "button", "aria-pressed": one.value === value, onClick: () => onChange(one.value), ...stylex.props(styles.item, one.value === value && styles.on), children: one.label }, one.value))) }));
|
|
43
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as stylex from "@stylexjs/stylex";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
type Sx = {
|
|
4
|
+
sx?: stylex.StyleXStyles;
|
|
5
|
+
};
|
|
6
|
+
export declare function SettingsRows({ children, sx }: {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
} & Sx): import("react").JSX.Element;
|
|
9
|
+
export type SettingsRowProps = {
|
|
10
|
+
label: ReactNode;
|
|
11
|
+
help?: ReactNode;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
sx?: stylex.StyleXStyles;
|
|
14
|
+
};
|
|
15
|
+
export declare function SettingsRow({ label, help, children, sx }: SettingsRowProps): import("react").JSX.Element;
|
|
16
|
+
/** `.help` inline: a muted reading on a row's label line. */
|
|
17
|
+
export declare function Help({ children, sx }: {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
} & Sx): import("react").JSX.Element;
|
|
20
|
+
/** `.val`: a mono reading, like `•••• 9b7c`. */
|
|
21
|
+
export declare function Value({ children, sx }: {
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
} & Sx): import("react").JSX.Element;
|
|
24
|
+
export declare function Dot({ sx }: Sx): import("react").JSX.Element;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as stylex from "@stylexjs/stylex";
|
|
3
|
+
import { color, corner, font, space, type } from "../../tokens.stylex.js";
|
|
4
|
+
/**
|
|
5
|
+
* `.srows` / `.srow`: a setting per line, 44px — its name and one line of help on the left, the
|
|
6
|
+
* control on the right. The rows sit on one surface with hairlines between them.
|
|
7
|
+
*/
|
|
8
|
+
const styles = stylex.create({
|
|
9
|
+
rows: {
|
|
10
|
+
backgroundColor: color.surface,
|
|
11
|
+
borderRadius: corner.card,
|
|
12
|
+
boxShadow: `inset 0 0 0 1px ${color.border}`,
|
|
13
|
+
color: color.text,
|
|
14
|
+
fontSize: type.t2,
|
|
15
|
+
lineHeight: type.body,
|
|
16
|
+
},
|
|
17
|
+
row: {
|
|
18
|
+
alignItems: "center",
|
|
19
|
+
borderRadius: {
|
|
20
|
+
default: 0,
|
|
21
|
+
":first-child": `${corner.card} ${corner.card} 0 0`,
|
|
22
|
+
":last-child": `0 0 ${corner.card} ${corner.card}`,
|
|
23
|
+
},
|
|
24
|
+
boxShadow: { default: "none", ":not(:first-child)": `inset 0 1px 0 ${color.border}` },
|
|
25
|
+
columnGap: space.sm,
|
|
26
|
+
display: "grid",
|
|
27
|
+
gridTemplateColumns: "minmax(0, 1fr) auto",
|
|
28
|
+
minHeight: 44,
|
|
29
|
+
paddingBlock: space.xs,
|
|
30
|
+
paddingInline: space.sm,
|
|
31
|
+
},
|
|
32
|
+
key: { minWidth: 0 },
|
|
33
|
+
label: {
|
|
34
|
+
alignItems: "center",
|
|
35
|
+
display: "flex",
|
|
36
|
+
flexWrap: "wrap",
|
|
37
|
+
fontSize: type.t2,
|
|
38
|
+
fontWeight: 500,
|
|
39
|
+
gap: space.xs,
|
|
40
|
+
minWidth: 0,
|
|
41
|
+
},
|
|
42
|
+
help: { color: color.textMuted, fontSize: type.t2 },
|
|
43
|
+
value: { color: color.textMuted, fontFamily: font.mono, fontSize: type.t2, whiteSpace: "nowrap" },
|
|
44
|
+
ctl: { alignItems: "center", display: "flex", flex: "none", gap: space.xs },
|
|
45
|
+
dot: { backgroundColor: color.accent, borderRadius: "50%", flex: "none", height: 6, width: 6 },
|
|
46
|
+
});
|
|
47
|
+
export function SettingsRows({ children, sx }) {
|
|
48
|
+
return _jsx("div", { ...stylex.props(styles.rows, sx), children: children });
|
|
49
|
+
}
|
|
50
|
+
export function SettingsRow({ label, help, children, sx }) {
|
|
51
|
+
return (_jsxs("div", { ...stylex.props(styles.row, sx), children: [_jsxs("div", { ...stylex.props(styles.key), children: [_jsx("div", { ...stylex.props(styles.label), children: label }), help !== undefined && _jsx("div", { ...stylex.props(styles.help), children: help })] }), children !== undefined && _jsx("div", { ...stylex.props(styles.ctl), children: children })] }));
|
|
52
|
+
}
|
|
53
|
+
/** `.help` inline: a muted reading on a row's label line. */
|
|
54
|
+
export function Help({ children, sx }) {
|
|
55
|
+
return _jsx("span", { ...stylex.props(styles.help, sx), children: children });
|
|
56
|
+
}
|
|
57
|
+
/** `.val`: a mono reading, like `•••• 9b7c`. */
|
|
58
|
+
export function Value({ children, sx }) {
|
|
59
|
+
return _jsx("span", { ...stylex.props(styles.value, sx), children: children });
|
|
60
|
+
}
|
|
61
|
+
export function Dot({ sx }) {
|
|
62
|
+
return _jsx("span", { "aria-hidden": "true", ...stylex.props(styles.dot, sx) });
|
|
63
|
+
}
|
|
@@ -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
|
+
}
|