@maple-kit/ui 0.9.0 → 0.10.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 +5 -2
- package/dist/cx.js +6 -0
- package/dist/icons/chevron.d.ts +4 -0
- package/dist/icons/chevron.js +8 -0
- package/dist/icons/code.d.ts +4 -0
- package/dist/icons/code.js +5 -0
- package/dist/icons/index.d.ts +4 -1
- package/dist/icons/index.js +4 -1
- package/dist/icons/link.d.ts +4 -0
- package/dist/icons/link.js +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/island/account.js +2 -1
- package/dist/island/approve.js +2 -1
- package/dist/island/content.js +2 -1
- package/dist/island/filters.js +2 -1
- package/dist/island/header.js +2 -1
- package/dist/island/island.js +2 -1
- package/dist/island/item.js +2 -1
- package/dist/island/list.js +2 -1
- package/dist/island/new-comment.js +2 -1
- package/dist/island/settings.js +2 -1
- package/dist/island/trigger.js +2 -1
- package/dist/island/unsent.js +2 -1
- package/dist/island/wordmark.js +2 -1
- package/dist/maple.d.ts +2 -1
- package/dist/maple.js +2 -1
- package/dist/mock/css.js +427 -0
- package/dist/mock/index.d.ts +4 -0
- package/dist/mock/index.js +4 -0
- package/dist/mock/language.d.ts +39 -0
- package/dist/mock/language.js +66 -0
- package/dist/mock/layers.js +168 -0
- package/dist/mock/menu.js +85 -0
- package/dist/mock/mock.d.ts +18 -0
- package/dist/mock/mock.js +200 -0
- package/dist/mock/sheet.d.ts +8 -0
- package/dist/mock/sheet.js +9 -0
- package/dist/notice/notice.js +2 -1
- package/dist/part.js +1 -4
- package/dist/root.js +2 -1
- package/dist/sheet-base.d.ts +11 -0
- package/dist/sheet-base.js +173 -0
- package/dist/stylesheet.d.ts +3 -12
- package/dist/stylesheet.js +5 -167
- package/dist/tip.js +1 -1
- package/dist/tokens.js +6 -2
- package/package.json +6 -4
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ChevronIcon } from "../icons/chevron.js";
|
|
2
|
+
import { Fragment, createElement, useRef } from "react";
|
|
3
|
+
//#region src/mock/menu.ts
|
|
4
|
+
const EDGE_PX = 8;
|
|
5
|
+
function Menu(props) {
|
|
6
|
+
const { label, onPick, options, value } = props;
|
|
7
|
+
const trigger = useRef(null);
|
|
8
|
+
const menu = useRef(null);
|
|
9
|
+
const chosen = options.find((option) => option.value === value) ?? options[0];
|
|
10
|
+
const toggle = () => {
|
|
11
|
+
const node = menu.current;
|
|
12
|
+
const from = trigger.current;
|
|
13
|
+
if (!node || !from) return;
|
|
14
|
+
node.togglePopover();
|
|
15
|
+
if (!node.matches(":popover-open")) return;
|
|
16
|
+
place(node, from.getBoundingClientRect());
|
|
17
|
+
node.querySelector("[aria-checked=\"true\"]")?.focus();
|
|
18
|
+
from.getRootNode().addEventListener("scroll", () => close(node), {
|
|
19
|
+
capture: true,
|
|
20
|
+
once: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
const pick = (next) => {
|
|
24
|
+
close(menu.current);
|
|
25
|
+
trigger.current?.focus();
|
|
26
|
+
onPick(next);
|
|
27
|
+
};
|
|
28
|
+
return createElement(Fragment, null, createElement("button", {
|
|
29
|
+
type: "button",
|
|
30
|
+
className: "mk-mock-pick mk-press",
|
|
31
|
+
"aria-haspopup": "menu",
|
|
32
|
+
"aria-label": `${label}: ${chosen?.label ?? ""}`,
|
|
33
|
+
"data-mk-real": String(chosen?.real === true),
|
|
34
|
+
ref: trigger,
|
|
35
|
+
onClick: toggle
|
|
36
|
+
}, chosen && optionText(chosen), createElement(ChevronIcon, {
|
|
37
|
+
key: "chevron",
|
|
38
|
+
className: "mk-mock-chevron",
|
|
39
|
+
size: 11
|
|
40
|
+
})), createElement("div", {
|
|
41
|
+
className: "mk-mock-menu",
|
|
42
|
+
popover: "auto",
|
|
43
|
+
role: "menu",
|
|
44
|
+
"aria-label": label,
|
|
45
|
+
ref: menu,
|
|
46
|
+
onKeyDown: move
|
|
47
|
+
}, options.map((option) => createElement("button", {
|
|
48
|
+
key: option.label,
|
|
49
|
+
type: "button",
|
|
50
|
+
role: "menuitemradio",
|
|
51
|
+
className: "mk-mock-item",
|
|
52
|
+
"aria-checked": option.value === value,
|
|
53
|
+
onClick: () => pick(option.value)
|
|
54
|
+
}, optionText(option)))));
|
|
55
|
+
}
|
|
56
|
+
function optionText(option) {
|
|
57
|
+
return [...option.real === true ? [createElement("span", {
|
|
58
|
+
key: "dot",
|
|
59
|
+
className: "mk-mock-dot",
|
|
60
|
+
"aria-hidden": true
|
|
61
|
+
})] : [], createElement("span", { key: "text" }, option.label)];
|
|
62
|
+
}
|
|
63
|
+
function move(event) {
|
|
64
|
+
const step = {
|
|
65
|
+
ArrowDown: 1,
|
|
66
|
+
ArrowUp: -1
|
|
67
|
+
}[event.key];
|
|
68
|
+
if (step === void 0) return;
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
const items = [...event.currentTarget.querySelectorAll("[role=\"menuitemradio\"]")];
|
|
71
|
+
items[(items.indexOf(event.target) + step + items.length) % items.length]?.focus();
|
|
72
|
+
}
|
|
73
|
+
function close(node) {
|
|
74
|
+
if (node?.matches(":popover-open") === true) node.hidePopover();
|
|
75
|
+
}
|
|
76
|
+
function place(node, anchor) {
|
|
77
|
+
const box = node.getBoundingClientRect();
|
|
78
|
+
const below = anchor.bottom + 4;
|
|
79
|
+
const y = below + box.height <= window.innerHeight - EDGE_PX ? below : anchor.top - 4 - box.height;
|
|
80
|
+
const x = Math.max(EDGE_PX, anchor.right - box.width);
|
|
81
|
+
node.style.setProperty("--mk-x", `${String(Math.round(x))}px`);
|
|
82
|
+
node.style.setProperty("--mk-y", `${String(Math.round(Math.max(EDGE_PX, y)))}px`);
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
export { Menu };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { MockClient } from "@maple-kit/mock/client";
|
|
2
|
+
//#region src/mock/mock.d.ts
|
|
3
|
+
/** How the box is mounted. */
|
|
4
|
+
export interface MapleMockProps {
|
|
5
|
+
/** A controller the caller built and owns, started and destroyed by them. */
|
|
6
|
+
readonly client?: MockClient;
|
|
7
|
+
/** Start with the box open. `m` opens and closes it either way. */
|
|
8
|
+
readonly defaultOpen?: boolean;
|
|
9
|
+
/** Added to the box. */
|
|
10
|
+
readonly className?: string;
|
|
11
|
+
/** For a host that mounts Maple with a script tag rather than a bundle. */
|
|
12
|
+
readonly nonce?: string;
|
|
13
|
+
/** Where its own host is appended. Defaults to `document.body`. */
|
|
14
|
+
readonly parent?: Element;
|
|
15
|
+
}
|
|
16
|
+
/** The box, the banner, and a shadow host of their own when nothing gives one. */
|
|
17
|
+
export declare const MapleMock: import("react").ForwardRefExoticComponent<MapleMockProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { MapleUiContext } from "../context.js";
|
|
2
|
+
import { SCHEME_ATTRIBUTE } from "../sheet-base.js";
|
|
3
|
+
import { cx } from "../cx.js";
|
|
4
|
+
import { MOCK_COPY, SHAPE_LABELS, STATE_LABELS, bannerSentence, callName, codecOf } from "./language.js";
|
|
5
|
+
import { CodeIcon } from "../icons/code.js";
|
|
6
|
+
import { LinkIcon } from "../icons/link.js";
|
|
7
|
+
import { Menu } from "./menu.js";
|
|
8
|
+
import { MOCK_CSS } from "./sheet.js";
|
|
9
|
+
import { createElement, forwardRef, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
10
|
+
import { createOverlayHost } from "@maple-kit/core/overlay";
|
|
11
|
+
import { createPortal } from "react-dom";
|
|
12
|
+
import { MOCK_STATES } from "@maple-kit/core/mock";
|
|
13
|
+
import { useMock } from "@maple-kit/react/mock";
|
|
14
|
+
//#region src/mock/mock.ts
|
|
15
|
+
const MapleMock = forwardRef(function MapleMock(props, ref) {
|
|
16
|
+
const { className, client, defaultOpen, nonce, parent } = props;
|
|
17
|
+
const binding = useMock({
|
|
18
|
+
...client === void 0 ? {} : { client },
|
|
19
|
+
...defaultOpen === void 0 ? {} : { defaultOpen }
|
|
20
|
+
});
|
|
21
|
+
const inside = useContext(MapleUiContext);
|
|
22
|
+
if (!binding.state.installed) return null;
|
|
23
|
+
const surface = createElement(MockSurface, {
|
|
24
|
+
...binding,
|
|
25
|
+
className,
|
|
26
|
+
forwarded: ref
|
|
27
|
+
});
|
|
28
|
+
if (inside !== null) return surface;
|
|
29
|
+
return createElement(OwnHost, {
|
|
30
|
+
scheme: binding.state.scheme,
|
|
31
|
+
nonce,
|
|
32
|
+
parent
|
|
33
|
+
}, surface);
|
|
34
|
+
});
|
|
35
|
+
function OwnHost(props) {
|
|
36
|
+
const { nonce, parent, scheme } = props;
|
|
37
|
+
const [host, setHost] = useState();
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const mounted = createOverlayHost({
|
|
40
|
+
...nonce === void 0 ? {} : { nonce },
|
|
41
|
+
...parent === void 0 ? {} : { parent }
|
|
42
|
+
});
|
|
43
|
+
mounted.addStyles(MOCK_CSS);
|
|
44
|
+
setHost(mounted);
|
|
45
|
+
return () => mounted.destroy();
|
|
46
|
+
}, [nonce, parent]);
|
|
47
|
+
useLayoutEffect(() => {
|
|
48
|
+
host?.container.setAttribute(SCHEME_ATTRIBUTE, scheme);
|
|
49
|
+
}, [host, scheme]);
|
|
50
|
+
if (host === void 0) return null;
|
|
51
|
+
return createPortal(createElement("div", { className: "mk-layer" }, props.children), host.root);
|
|
52
|
+
}
|
|
53
|
+
function MockSurface(props) {
|
|
54
|
+
const { client, state } = props;
|
|
55
|
+
const layers = useLayers(state);
|
|
56
|
+
return createElement("div", { className: "mk-mock-surface" }, state.active === void 0 ? null : createElement(Banner, {
|
|
57
|
+
key: "banner",
|
|
58
|
+
client,
|
|
59
|
+
state,
|
|
60
|
+
layers
|
|
61
|
+
}), state.open ? createElement(Box, {
|
|
62
|
+
key: "box",
|
|
63
|
+
...props,
|
|
64
|
+
layers
|
|
65
|
+
}) : null);
|
|
66
|
+
}
|
|
67
|
+
function useLayers(state) {
|
|
68
|
+
const [chunk, setChunk] = useState();
|
|
69
|
+
const { active } = state;
|
|
70
|
+
const needed = !!(state.identity ?? state.flags[0] ?? active?.as ?? active?.flags);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (needed) import("./layers.js").then(setChunk, () => void 0);
|
|
73
|
+
}, [needed]);
|
|
74
|
+
return chunk;
|
|
75
|
+
}
|
|
76
|
+
function Banner(props) {
|
|
77
|
+
const { client, layers, state } = props;
|
|
78
|
+
return createElement("div", {
|
|
79
|
+
className: "mk-mock-banner mk-live",
|
|
80
|
+
role: "status"
|
|
81
|
+
}, createElement("span", { className: "mk-mock-banner-said" }, bannerSentence(state.active.calls)), layers && createElement(layers.LayerBanner, { state }), state.open ? null : button(MOCK_COPY.edit, () => client.setOpen(true)), button(MOCK_COPY.turnOff, () => client.turnOff()));
|
|
82
|
+
}
|
|
83
|
+
function Box(props) {
|
|
84
|
+
const { className, client, forwarded, layers, state } = props;
|
|
85
|
+
const field = useRef(null);
|
|
86
|
+
useEffect(() => field.current?.focus(), []);
|
|
87
|
+
return createElement("div", {
|
|
88
|
+
className: cx("mk-mock mk-surface mk-live", className),
|
|
89
|
+
role: "dialog",
|
|
90
|
+
"aria-label": MOCK_COPY.label,
|
|
91
|
+
ref: forwarded
|
|
92
|
+
}, createElement("div", {
|
|
93
|
+
className: "mk-mock-head",
|
|
94
|
+
"data-mk-thinking": String(state.thinking),
|
|
95
|
+
"aria-busy": state.thinking
|
|
96
|
+
}, createElement("input", {
|
|
97
|
+
className: "mk-mock-field",
|
|
98
|
+
type: "text",
|
|
99
|
+
placeholder: state.planning ? MOCK_COPY.sentence : MOCK_COPY.field,
|
|
100
|
+
"aria-label": state.planning ? MOCK_COPY.sentence : MOCK_COPY.field,
|
|
101
|
+
value: state.query,
|
|
102
|
+
ref: field,
|
|
103
|
+
onChange: (event) => client.setQuery(event.currentTarget.value)
|
|
104
|
+
}), createElement("kbd", { className: "mk-mock-key-hint" }, MOCK_COPY.escape)), state.unnamed ? createElement("p", { className: "mk-mock-unnamed" }, MOCK_COPY.unnamed) : null, createElement("div", { className: "mk-mock-body" }, createElement("p", { className: "mk-mock-route" }, `${MOCK_COPY.routePrefix} `, createElement("span", { className: "mk-mono" }, state.route)), calls(state, client), layers && createElement(layers.Layers, {
|
|
105
|
+
state,
|
|
106
|
+
client
|
|
107
|
+
})), createElement(Foot, {
|
|
108
|
+
client,
|
|
109
|
+
state
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
function calls(state, client) {
|
|
113
|
+
if (state.calls.length === 0) {
|
|
114
|
+
const said = state.query === "" ? MOCK_COPY.nothingRecorded : MOCK_COPY.nothingMatches;
|
|
115
|
+
return createElement("p", { className: "mk-mock-empty" }, said);
|
|
116
|
+
}
|
|
117
|
+
return createElement("ul", { className: "mk-mock-calls" }, state.calls.map((row) => createElement(CallRow, {
|
|
118
|
+
key: row.key,
|
|
119
|
+
row,
|
|
120
|
+
client
|
|
121
|
+
})));
|
|
122
|
+
}
|
|
123
|
+
function CallRow(props) {
|
|
124
|
+
const { client, row } = props;
|
|
125
|
+
return createElement("li", {
|
|
126
|
+
className: "mk-mock-call",
|
|
127
|
+
"data-mk-mocked": String(row.state !== void 0),
|
|
128
|
+
"data-mk-seen": String(row.seen),
|
|
129
|
+
title: row.seen ? row.key : `${row.key}: ${MOCK_COPY.notSeen}`
|
|
130
|
+
}, createElement("span", { className: "mk-mock-name mk-mono" }, createElement("span", { className: "mk-mock-codec" }, codecOf(row.key)), callName(row.key)), row.source === void 0 ? null : createElement("span", {
|
|
131
|
+
className: "mk-mock-rung",
|
|
132
|
+
title: `${MOCK_COPY.shapeFrom} ${SHAPE_LABELS[row.source]}`
|
|
133
|
+
}, SHAPE_LABELS[row.source]), createElement(Menu, {
|
|
134
|
+
label: callName(row.key),
|
|
135
|
+
options: STATE_OPTIONS,
|
|
136
|
+
value: row.state,
|
|
137
|
+
onPick: (state) => client.choose(row.key, state)
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
const STATE_OPTIONS = [{
|
|
141
|
+
value: void 0,
|
|
142
|
+
label: MOCK_COPY.real,
|
|
143
|
+
real: true
|
|
144
|
+
}, ...MOCK_STATES.map((state) => ({
|
|
145
|
+
value: state,
|
|
146
|
+
label: STATE_LABELS[state]
|
|
147
|
+
}))];
|
|
148
|
+
function Foot(props) {
|
|
149
|
+
const { client, state } = props;
|
|
150
|
+
const [copied, setCopied] = useState();
|
|
151
|
+
const empty = client.recipe() === void 0;
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (copied === void 0) return;
|
|
154
|
+
const timer = setTimeout(() => setCopied(void 0), 1600);
|
|
155
|
+
return () => clearTimeout(timer);
|
|
156
|
+
}, [copied]);
|
|
157
|
+
const copy = (what) => () => {
|
|
158
|
+
(what === "link" ? client.copyLink() : client.copyRecipe()).then(() => setCopied({
|
|
159
|
+
what,
|
|
160
|
+
ok: true
|
|
161
|
+
}), () => setCopied({
|
|
162
|
+
what,
|
|
163
|
+
ok: false
|
|
164
|
+
}));
|
|
165
|
+
};
|
|
166
|
+
return createElement("div", { className: "mk-mock-foot" }, button(label(copied, "link", MOCK_COPY.copyLink), copy("link"), {
|
|
167
|
+
key: "link",
|
|
168
|
+
disabled: empty,
|
|
169
|
+
icon: LinkIcon
|
|
170
|
+
}), button(label(copied, "recipe", MOCK_COPY.copyRecipe), copy("recipe"), {
|
|
171
|
+
key: "recipe",
|
|
172
|
+
disabled: empty,
|
|
173
|
+
icon: CodeIcon,
|
|
174
|
+
quiet: true
|
|
175
|
+
}), createElement("span", {
|
|
176
|
+
key: "spacer",
|
|
177
|
+
className: "mk-mock-spacer"
|
|
178
|
+
}), button(MOCK_COPY.apply, () => client.apply(), {
|
|
179
|
+
key: "apply",
|
|
180
|
+
disabled: !state.changed,
|
|
181
|
+
primary: true
|
|
182
|
+
}));
|
|
183
|
+
}
|
|
184
|
+
function label(copied, what, idle) {
|
|
185
|
+
if (copied?.what !== what) return idle;
|
|
186
|
+
return copied.ok ? MOCK_COPY.copied : MOCK_COPY.copyFailed;
|
|
187
|
+
}
|
|
188
|
+
function button(text, onClick, flags = {}) {
|
|
189
|
+
return createElement("button", {
|
|
190
|
+
key: flags.key ?? text,
|
|
191
|
+
type: "button",
|
|
192
|
+
className: "mk-mock-button mk-press",
|
|
193
|
+
disabled: flags.disabled === true,
|
|
194
|
+
"data-mk-primary": flags.primary === true ? "true" : void 0,
|
|
195
|
+
"data-mk-quiet": flags.quiet === true ? "true" : void 0,
|
|
196
|
+
onClick
|
|
197
|
+
}, flags.icon && createElement(flags.icon, { key: "icon" }), text);
|
|
198
|
+
}
|
|
199
|
+
//#endregion
|
|
200
|
+
export { MapleMock };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/mock/sheet.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The sheet `MapleMock` adopts when it mounts on its own: the tokens, the base
|
|
4
|
+
* rules and the box's rules, and none of the island's, composer's or marks'.
|
|
5
|
+
*/
|
|
6
|
+
/** The box's own styles, for a page with no `<Maple />`. */
|
|
7
|
+
export declare const MOCK_CSS: string;
|
|
8
|
+
//#endregion
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { mockCss } from "./css.js";
|
|
2
|
+
import { baseCss, tokenCss } from "../sheet-base.js";
|
|
3
|
+
//#region src/mock/sheet.ts
|
|
4
|
+
function buildMockCss() {
|
|
5
|
+
return `${tokenCss()}\n\n${baseCss()}\n\n${mockCss()}\n`;
|
|
6
|
+
}
|
|
7
|
+
const MOCK_CSS = buildMockCss();
|
|
8
|
+
//#endregion
|
|
9
|
+
export { MOCK_CSS };
|
package/dist/notice/notice.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { cx
|
|
1
|
+
import { cx } from "../cx.js";
|
|
2
|
+
import { renderPart } from "../part.js";
|
|
2
3
|
import { NOTICE_COPY, offersSignIn } from "./language.js";
|
|
3
4
|
import { createElement, forwardRef } from "react";
|
|
4
5
|
import { useMaple, useMapleClient } from "@maple-kit/react";
|
package/dist/part.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import { Slot } from "./slot.js";
|
|
2
2
|
import { createElement } from "react";
|
|
3
3
|
//#region src/part.ts
|
|
4
|
-
function cx(...names) {
|
|
5
|
-
return names.filter(Boolean).join(" ");
|
|
6
|
-
}
|
|
7
4
|
function renderPart(tag, asChild, props, children) {
|
|
8
5
|
return createElement(asChild ? Slot : tag, props, children);
|
|
9
6
|
}
|
|
10
7
|
//#endregion
|
|
11
|
-
export {
|
|
8
|
+
export { renderPart };
|
package/dist/root.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MapleUiContext } from "./context.js";
|
|
2
2
|
import { ShotContext, createShotStore } from "./shots.js";
|
|
3
|
-
import {
|
|
3
|
+
import { SCHEME_ATTRIBUTE } from "./sheet-base.js";
|
|
4
|
+
import { OVERLAY_CSS } from "./stylesheet.js";
|
|
4
5
|
import { useOverlayScheme } from "./theme.js";
|
|
5
6
|
import { createElement, forwardRef, useEffect, useLayoutEffect, useMemo, useState } from "react";
|
|
6
7
|
import { readMapleConfig } from "@maple-kit/core/client";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/sheet-base.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The tokens and the base rules: what every sheet in this package starts from.
|
|
4
|
+
*
|
|
5
|
+
* `Maple.Root` adopts them with every part's rules, and `MapleMock` on its own
|
|
6
|
+
* adopts them with the box's alone, so a page that only mocks never carries the
|
|
7
|
+
* island's or the composer's styles. Building a string reaches nothing.
|
|
8
|
+
*/
|
|
9
|
+
/** The attribute the root writes the overlay's resolved scheme to. */
|
|
10
|
+
export declare const SCHEME_ATTRIBUTE = "data-mk-scheme";
|
|
11
|
+
//#endregion
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { COLOR_TOKENS, MOTION_TOKENS, RADIUS_TOKENS, REDUCED_MOTION_TOKENS, SHADOW_TOKENS, SIZE_TOKENS, TYPE_TOKENS } from "./tokens.js";
|
|
2
|
+
//#region src/sheet-base.ts
|
|
3
|
+
const SCHEME_ATTRIBUTE = "data-mk-scheme";
|
|
4
|
+
const DARK_HOST = `:host([${SCHEME_ATTRIBUTE}="dark"])`;
|
|
5
|
+
function declare(tokens) {
|
|
6
|
+
return Object.entries(tokens).map(([name, value]) => ` ${name}: ${value};`).join("\n");
|
|
7
|
+
}
|
|
8
|
+
function declareThemed(tokens, scheme) {
|
|
9
|
+
return Object.entries(tokens).map(([name, value]) => ` ${name}: ${value[scheme]};`).join("\n");
|
|
10
|
+
}
|
|
11
|
+
function tokenCss() {
|
|
12
|
+
return [
|
|
13
|
+
`:host {`,
|
|
14
|
+
declareThemed(COLOR_TOKENS, "light"),
|
|
15
|
+
declareThemed(SHADOW_TOKENS, "light"),
|
|
16
|
+
declare(RADIUS_TOKENS),
|
|
17
|
+
declare(TYPE_TOKENS),
|
|
18
|
+
declare(SIZE_TOKENS),
|
|
19
|
+
declare(MOTION_TOKENS),
|
|
20
|
+
` color-scheme: light;`,
|
|
21
|
+
`}`,
|
|
22
|
+
``,
|
|
23
|
+
`${DARK_HOST} {`,
|
|
24
|
+
declareThemed(COLOR_TOKENS, "dark"),
|
|
25
|
+
declareThemed(SHADOW_TOKENS, "dark"),
|
|
26
|
+
` color-scheme: dark;`,
|
|
27
|
+
`}`,
|
|
28
|
+
``,
|
|
29
|
+
`@media (prefers-reduced-motion: reduce) {`,
|
|
30
|
+
` :host {`,
|
|
31
|
+
declare(REDUCED_MOTION_TOKENS).split("\n").map((line) => ` ${line}`).join("\n"),
|
|
32
|
+
` }`,
|
|
33
|
+
`}`
|
|
34
|
+
].join("\n");
|
|
35
|
+
}
|
|
36
|
+
function baseCss() {
|
|
37
|
+
return `
|
|
38
|
+
:host {
|
|
39
|
+
display: block;
|
|
40
|
+
font-family: var(--mk-font);
|
|
41
|
+
font-size: 13px;
|
|
42
|
+
font-weight: 400;
|
|
43
|
+
font-style: normal;
|
|
44
|
+
font-variant: normal;
|
|
45
|
+
letter-spacing: normal;
|
|
46
|
+
line-height: 1.45;
|
|
47
|
+
text-align: left;
|
|
48
|
+
color: var(--mk-fg);
|
|
49
|
+
-webkit-font-smoothing: antialiased;
|
|
50
|
+
-moz-osx-font-smoothing: grayscale;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
*,
|
|
54
|
+
*::before,
|
|
55
|
+
*::after {
|
|
56
|
+
box-sizing: border-box;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.mk-layer {
|
|
60
|
+
position: absolute;
|
|
61
|
+
inset: 0;
|
|
62
|
+
pointer-events: none;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.mk-live {
|
|
66
|
+
pointer-events: auto;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.mk-surface {
|
|
70
|
+
background: var(--mk-bg);
|
|
71
|
+
border: 1px solid var(--mk-line-firm);
|
|
72
|
+
border-radius: var(--mk-r);
|
|
73
|
+
box-shadow: var(--mk-sh2);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
${DARK_HOST} .mk-surface {
|
|
77
|
+
box-shadow: var(--mk-sh2), inset 0 1px 0 oklch(1 0 0 / 0.045);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.mk-num {
|
|
81
|
+
font-variant-numeric: tabular-nums;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.mk-mono {
|
|
85
|
+
font-family: var(--mk-mono);
|
|
86
|
+
font-variant-numeric: tabular-nums;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.mk-body {
|
|
90
|
+
text-wrap: pretty;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.mk-title,
|
|
94
|
+
h1,
|
|
95
|
+
h2,
|
|
96
|
+
h3 {
|
|
97
|
+
text-wrap: balance;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.mk-shot {
|
|
101
|
+
outline: 1px solid var(--mk-shot-edge);
|
|
102
|
+
outline-offset: -1px;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* No radius here: an outline already follows the control's own corners, and
|
|
106
|
+
forcing one squared off every pill in the overlay the moment it took focus.
|
|
107
|
+
The two controls that carry no radius of their own are given one below. */
|
|
108
|
+
:where(a, button, input, textarea, [role="button"], [tabindex]):focus-visible {
|
|
109
|
+
outline: 2px solid var(--mk-accent);
|
|
110
|
+
outline-offset: 2px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.mk-press {
|
|
114
|
+
transition: transform var(--mk-dur-fade) var(--mk-ease-surface);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.mk-press:active {
|
|
118
|
+
transform: scale(var(--mk-press));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.mk-hit {
|
|
122
|
+
position: relative;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.mk-hit::after {
|
|
126
|
+
content: "";
|
|
127
|
+
position: absolute;
|
|
128
|
+
top: 50%;
|
|
129
|
+
left: 50%;
|
|
130
|
+
width: max(100%, var(--mk-hit));
|
|
131
|
+
height: max(100%, var(--mk-hit));
|
|
132
|
+
transform: translate(-50%, -50%);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.mk-track {
|
|
136
|
+
transition: opacity var(--mk-dur-fade) var(--mk-ease-surface);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.mk-icon-swap {
|
|
140
|
+
display: inline-grid;
|
|
141
|
+
place-items: center;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.mk-icon-swap > * {
|
|
145
|
+
grid-area: 1 / 1;
|
|
146
|
+
transition:
|
|
147
|
+
opacity var(--mk-dur-swap) var(--mk-ease-swap),
|
|
148
|
+
transform var(--mk-dur-swap) var(--mk-ease-swap),
|
|
149
|
+
filter var(--mk-dur-swap) var(--mk-ease-swap);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.mk-icon-swap > [data-mk-icon="out"] {
|
|
153
|
+
opacity: 0;
|
|
154
|
+
transform: scale(var(--mk-icon-scale));
|
|
155
|
+
filter: blur(var(--mk-icon-blur));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.mk-icon-swap > [data-mk-icon="in"] {
|
|
159
|
+
opacity: 1;
|
|
160
|
+
transform: scale(1);
|
|
161
|
+
filter: blur(0);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@media (max-width: 639px) {
|
|
165
|
+
:host {
|
|
166
|
+
--mk-composer-w: 100%;
|
|
167
|
+
--mk-composer-r: var(--mk-r) var(--mk-r) 0 0;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
`.trim();
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
export { SCHEME_ATTRIBUTE, baseCss, tokenCss };
|
package/dist/stylesheet.d.ts
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
|
+
import { SCHEME_ATTRIBUTE } from "./sheet-base.js";
|
|
1
2
|
//#region src/stylesheet.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* The overlay's stylesheet: one string, built from the token table.
|
|
4
|
-
*
|
|
5
|
-
* It is a constant rather than a CSS file behind a loader, so it needs no
|
|
6
|
-
* bundler plugin, stays tree-shakeable, and leaves the CSP claim in
|
|
7
|
-
* docs/overlay-csp.md checkable by reading `buildOverlayCss` and
|
|
8
|
-
* `createOverlayStyleSheet`. Nothing here constructs a `CSSStyleSheet`, reaches
|
|
9
|
-
* `document` or reads storage; building a string does none of those.
|
|
10
|
-
*/
|
|
11
|
-
/** The attribute the root writes the overlay's resolved scheme to. */
|
|
12
|
-
export declare const SCHEME_ATTRIBUTE = "data-mk-scheme";
|
|
13
3
|
/** The overlay's styles. The only thing `Maple.Root` adopts. */
|
|
14
4
|
export declare const OVERLAY_CSS: string;
|
|
15
|
-
//#endregion
|
|
5
|
+
//#endregion
|
|
6
|
+
export { SCHEME_ATTRIBUTE };
|