@raylang/elements 0.0.0-stage → 0.4.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/LICENSE +202 -0
- package/NOTICE +4 -0
- package/README.md +12 -2
- package/base.css +111 -0
- package/components/accordion/accordion.js +197 -0
- package/components/alert/alert.js +112 -0
- package/components/app-bar/app-bar.js +168 -0
- package/components/app-shell/app-shell.js +198 -0
- package/components/aspect-ratio/aspect-ratio.js +59 -0
- package/components/attachment/attachment.js +333 -0
- package/components/avatar/avatar.js +96 -0
- package/components/badge/badge.js +63 -0
- package/components/blockquote/blockquote.js +128 -0
- package/components/bottom-nav/bottom-nav.js +309 -0
- package/components/breadcrumbs/breadcrumbs.js +175 -0
- package/components/button/button.js +283 -0
- package/components/button-group/button-group.js +72 -0
- package/components/card/card.js +73 -0
- package/components/carousel/carousel.js +435 -0
- package/components/center/center.js +26 -0
- package/components/checkbox/checkbox.js +152 -0
- package/components/checkbox-group/checkbox-group.js +152 -0
- package/components/code/code.js +574 -0
- package/components/color-picker/color-picker.js +775 -0
- package/components/combobox/combobox.js +563 -0
- package/components/command-palette/command-palette.js +510 -0
- package/components/container/container.js +41 -0
- package/components/date-picker/date-picker.js +594 -0
- package/components/dialog/dialog.js +329 -0
- package/components/drawer/drawer.js +139 -0
- package/components/empty-state/empty-state.js +66 -0
- package/components/file-upload/file-upload.js +589 -0
- package/components/grid/grid.js +96 -0
- package/components/group/group.js +40 -0
- package/components/icon/icon.js +58 -0
- package/components/icon-button/icon-button.js +30 -0
- package/components/indicator/indicator.js +112 -0
- package/components/input/input.js +85 -0
- package/components/kbd/kbd.js +60 -0
- package/components/menu/menu.js +296 -0
- package/components/nav-link/nav-link.js +159 -0
- package/components/notification/notification.js +591 -0
- package/components/number-input/number-input.js +241 -0
- package/components/pagination/pagination.js +194 -0
- package/components/password-input/password-input.js +85 -0
- package/components/path-input/path-input.js +137 -0
- package/components/popover/popover.js +85 -0
- package/components/progress/progress.js +109 -0
- package/components/radio/radio.js +253 -0
- package/components/scroll-area/scroll-area.js +158 -0
- package/components/search/search.js +157 -0
- package/components/segmented-control/segmented-control.js +190 -0
- package/components/select/select.js +506 -0
- package/components/separator/separator.js +58 -0
- package/components/sidebar/sidebar.js +252 -0
- package/components/skeleton/skeleton.js +90 -0
- package/components/slider/slider.js +155 -0
- package/components/spinner/spinner.js +39 -0
- package/components/split/split.js +221 -0
- package/components/stack/stack.js +46 -0
- package/components/stat/stat.js +79 -0
- package/components/statusbar/statusbar.js +110 -0
- package/components/stepper/stepper.js +239 -0
- package/components/switch/switch.js +45 -0
- package/components/table/table.js +328 -0
- package/components/tabs/tabs.js +224 -0
- package/components/textarea/textarea.js +105 -0
- package/components/theme-toggle/theme-toggle.js +78 -0
- package/components/timeline/timeline.js +150 -0
- package/components/toggle/toggle.js +130 -0
- package/components/toggle-group/toggle-group.js +216 -0
- package/components/tooltip/tooltip.js +101 -0
- package/core/charts.js +107 -0
- package/core/color.js +110 -0
- package/core/core.js +556 -0
- package/core/dismiss.js +69 -0
- package/core/floating.js +195 -0
- package/core/focus.js +70 -0
- package/core/form.js +235 -0
- package/core/host.js +200 -0
- package/core/hotkey.js +40 -0
- package/core/icons.js +104 -0
- package/core/motion.js +73 -0
- package/core/position.js +91 -0
- package/core/raylang.js +167 -0
- package/core/scroll.js +58 -0
- package/core/styles.js +211 -0
- package/core.js +16 -0
- package/custom-elements.json +18545 -0
- package/index.js +74 -0
- package/package.json +312 -4
- package/ray-elements.d.ts +2570 -0
- package/tokens.css +796 -0
- package/tokens.json +2083 -0
- package/vscode.html-custom-data.json +5499 -0
package/core/raylang.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// The page's half of the ray-elements native bridge for std/ui windows (raylang);
|
|
2
|
+
// the program's half is the raylang module elements/bridge.
|
|
3
|
+
//
|
|
4
|
+
// import { enableRaylang } from "ray-elements/core/raylang.js";
|
|
5
|
+
// await enableRaylang(); // the host, or null in a browser
|
|
6
|
+
//
|
|
7
|
+
// It detects window.ray, asks the program what it offers ("hello") and
|
|
8
|
+
// installs a host (core/host.js), so the components that use one get the
|
|
9
|
+
// system dialogs. Requests travel through window.ray.request as JSON objects
|
|
10
|
+
// tagged "ray-elements", which bridge.handle answers and the app's own protocol
|
|
11
|
+
// never sees. In a browser, or when the program does not answer (its loop
|
|
12
|
+
// does not call bridge.handle), it resolves to null and nothing changes.
|
|
13
|
+
|
|
14
|
+
import { setHost, HostFile } from "./host.js";
|
|
15
|
+
import { chartTheme, onChartThemeChange } from "./charts.js";
|
|
16
|
+
import { getTheme } from "./core.js";
|
|
17
|
+
import { parseColor, toHex } from "./color.js";
|
|
18
|
+
|
|
19
|
+
/** The version of the protocol this page speaks. */
|
|
20
|
+
export const PROTOCOL = 1;
|
|
21
|
+
|
|
22
|
+
let enabling = null;
|
|
23
|
+
|
|
24
|
+
// The width macOS keeps for the window buttons at the start of the title bar.
|
|
25
|
+
const MAC_BUTTONS = 78;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Installs the raylang host once the program answers. `timeout` (ms) is how
|
|
29
|
+
* long to wait for that answer; `ray` replaces window.ray (tests).
|
|
30
|
+
* `windowColors` (default true) keeps the window's background in the
|
|
31
|
+
* theme's background color, so a resize or a reopen never shows the other
|
|
32
|
+
* theme. The title bar is tinted too only when the window has its own bar
|
|
33
|
+
* (not full_content) and the theme is light or dark: with "system" it stays
|
|
34
|
+
* the system's, so the page keeps following the system.
|
|
35
|
+
*/
|
|
36
|
+
export function enableRaylang({ timeout = 2000, ray = globalThis.ray, windowColors = true } = {}) {
|
|
37
|
+
if (ray !== globalThis.ray) return connect(ray, timeout, windowColors);
|
|
38
|
+
enabling ??= connect(ray, timeout, windowColors);
|
|
39
|
+
return enabling;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function connect(ray, timeout, windowColors) {
|
|
43
|
+
if (typeof ray?.request !== "function") return null;
|
|
44
|
+
const call = (op, args = {}) => request(ray, op, args);
|
|
45
|
+
let hello;
|
|
46
|
+
try {
|
|
47
|
+
hello = await within(call("hello"), timeout);
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const ops = new Set(hello?.ops ?? []);
|
|
52
|
+
// Context menus: the choice comes back as a "ray-elements:menu" event pushed by
|
|
53
|
+
// the program ({ id, index }); a dismissed menu sends nothing, so opening
|
|
54
|
+
// the next one settles the previous with null.
|
|
55
|
+
let popups = 0;
|
|
56
|
+
let pending = null;
|
|
57
|
+
document.addEventListener("ray-elements:menu", (e) => {
|
|
58
|
+
if (pending && e.detail?.id === pending.id) {
|
|
59
|
+
pending.resolve(e.detail.index);
|
|
60
|
+
pending = null;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const host = {
|
|
64
|
+
name: "raylang",
|
|
65
|
+
platform: hello.platform ?? "",
|
|
66
|
+
version: hello.version ?? "",
|
|
67
|
+
can: (op) => ops.has(op),
|
|
68
|
+
async pickFiles({ title = "", multiple = false, directory = "", filters = [] } = {}) {
|
|
69
|
+
const picked = await call("pick_files", { title, multiple, directory, filters });
|
|
70
|
+
return (picked ?? []).map((f) => new HostFile(f));
|
|
71
|
+
},
|
|
72
|
+
async pickPath({ mode = "open", title = "", directory = "", suggested = "", filters = [] } = {}) {
|
|
73
|
+
return (await call("pick_path", { mode, title, directory, suggested, filters })) ?? null;
|
|
74
|
+
},
|
|
75
|
+
menuItems() {
|
|
76
|
+
return call("menu_items");
|
|
77
|
+
},
|
|
78
|
+
runMenu(tag) {
|
|
79
|
+
return call("run_menu", { tag });
|
|
80
|
+
},
|
|
81
|
+
async popupMenu(items) {
|
|
82
|
+
pending?.resolve(null);
|
|
83
|
+
const id = ++popups;
|
|
84
|
+
const chosen = new Promise((resolve) => { pending = { id, resolve }; });
|
|
85
|
+
try {
|
|
86
|
+
await call("popup_menu", { id, items });
|
|
87
|
+
} catch (e) {
|
|
88
|
+
if (pending?.id === id) pending = null;
|
|
89
|
+
throw e;
|
|
90
|
+
}
|
|
91
|
+
return chosen;
|
|
92
|
+
},
|
|
93
|
+
setEdited(edited) {
|
|
94
|
+
return call("set_edited", { edited: Boolean(edited) });
|
|
95
|
+
},
|
|
96
|
+
setWindowColors({ background = "", titlebar } = {}) {
|
|
97
|
+
return call("window_colors", titlebar === undefined ? { background } : { background, titlebar });
|
|
98
|
+
},
|
|
99
|
+
async confirm({ title = "Are you sure?", message = "", confirmLabel = "Confirm", cancelLabel = "Cancel", style = "" } = {}) {
|
|
100
|
+
return Boolean(await call("confirm", { title, message, confirmLabel, cancelLabel, style }));
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
// Under a transparent title bar (a full_content window): what to reserve.
|
|
104
|
+
const height = Number(ray.titlebar_height) || 0;
|
|
105
|
+
host.titlebar = height > 0 ? { height, inset: host.platform === "macos" ? MAC_BUTTONS : 0 } : null;
|
|
106
|
+
const root = document.documentElement;
|
|
107
|
+
if (host.titlebar) {
|
|
108
|
+
root.style.setProperty("--ray-titlebar-height", `${height}px`);
|
|
109
|
+
root.style.setProperty("--ray-titlebar-inset", `${host.titlebar.inset}px`);
|
|
110
|
+
root.setAttribute("data-ray-titlebar", "");
|
|
111
|
+
}
|
|
112
|
+
setHost(host);
|
|
113
|
+
root.setAttribute("data-ray-host", "raylang");
|
|
114
|
+
if (windowColors && ops.has("window_colors")) {
|
|
115
|
+
// A title bar color also sets the window's appearance (macOS picks light
|
|
116
|
+
// or dark by its luminance), which the page's prefers-color-scheme
|
|
117
|
+
// follows, and in a full_content window it brings back the opaque bar.
|
|
118
|
+
// So the bar is tinted only in a window with its own bar and a chosen
|
|
119
|
+
// theme (light or dark), and given back to the system once after that.
|
|
120
|
+
let tinted = false;
|
|
121
|
+
const paint = (theme) => {
|
|
122
|
+
const background = hex(theme.background);
|
|
123
|
+
if (!background) return;
|
|
124
|
+
const colors = { background };
|
|
125
|
+
if (!host.titlebar) {
|
|
126
|
+
if (getTheme() !== "system") {
|
|
127
|
+
colors.titlebar = background;
|
|
128
|
+
tinted = true;
|
|
129
|
+
} else if (tinted) {
|
|
130
|
+
colors.titlebar = "";
|
|
131
|
+
tinted = false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
host.setWindowColors(colors).catch(() => {});
|
|
135
|
+
};
|
|
136
|
+
paint(chartTheme());
|
|
137
|
+
onChartThemeChange(paint);
|
|
138
|
+
}
|
|
139
|
+
return host;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// "#rrggbb" of a CSS color, "" when it cannot be read.
|
|
143
|
+
function hex(color) {
|
|
144
|
+
if (/^#[0-9a-f]{6}$/i.test(color ?? "")) return color.toLowerCase();
|
|
145
|
+
try {
|
|
146
|
+
const rgb = parseColor(String(color ?? ""));
|
|
147
|
+
return rgb ? toHex(rgb).slice(0, 7).toLowerCase() : "";
|
|
148
|
+
} catch {
|
|
149
|
+
return "";
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function request(ray, op, args) {
|
|
154
|
+
const answer = await ray.request({ "ray-elements": PROTOCOL, op, ...args });
|
|
155
|
+
if (!answer || typeof answer !== "object" || !("ok" in answer)) {
|
|
156
|
+
throw new Error(`ray-elements bridge: unexpected answer to '${op}'`);
|
|
157
|
+
}
|
|
158
|
+
if (!answer.ok) throw new Error(`ray-elements bridge: ${answer.error}`);
|
|
159
|
+
return answer.value;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function within(promise, ms) {
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
const t = setTimeout(() => reject(new Error("ray-elements bridge: no answer")), ms);
|
|
165
|
+
promise.then((v) => { clearTimeout(t); resolve(v); }, (e) => { clearTimeout(t); reject(e); });
|
|
166
|
+
});
|
|
167
|
+
}
|
package/core/scroll.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Which element scrolls the page an element sits on, and the direction of
|
|
2
|
+
// its scrolling: for the bars that hide while scrolling down and come back
|
|
3
|
+
// on the way up (ray-app-bar, ray-bottom-nav).
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The scroller of `el`: `target` (an element or a selector) when given,
|
|
7
|
+
* else the content of the ray-app-shell or ray-scroll-area around it, else
|
|
8
|
+
* the window.
|
|
9
|
+
* @param {Element} el
|
|
10
|
+
* @param {Element | string | null | undefined} target
|
|
11
|
+
* @returns {Element | Window}
|
|
12
|
+
*/
|
|
13
|
+
export function scrollerOf(el, target) {
|
|
14
|
+
if (target instanceof Element) return target;
|
|
15
|
+
if (typeof target === "string" && target) {
|
|
16
|
+
const found = document.querySelector(target);
|
|
17
|
+
if (found) return found.viewport ?? found.scroller ?? found;
|
|
18
|
+
}
|
|
19
|
+
for (let n = el; n; n = n.parentElement ?? n.getRootNode()?.host) {
|
|
20
|
+
if (n.localName === "ray-app-shell" && n.scroller) return n.scroller;
|
|
21
|
+
if (n.localName === "ray-scroll-area" && n !== el && n.viewport) return n.viewport;
|
|
22
|
+
}
|
|
23
|
+
return window;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Calls `cb({ y, direction })` as `scroller` scrolls, once per frame;
|
|
28
|
+
* direction is "down" or "up" past `tolerance` px, else unchanged.
|
|
29
|
+
* Returns a function that stops listening.
|
|
30
|
+
* @param {Element | Window} scroller
|
|
31
|
+
* @param {(state: { y: number, direction: "up" | "down" }) => void} cb
|
|
32
|
+
*/
|
|
33
|
+
export function watchScroll(scroller, cb, { tolerance = 8 } = {}) {
|
|
34
|
+
const top = () => (scroller === window ? window.scrollY : /** @type {Element} */ (scroller).scrollTop);
|
|
35
|
+
let last = top();
|
|
36
|
+
let direction = "up";
|
|
37
|
+
let frame = 0;
|
|
38
|
+
const run = () => {
|
|
39
|
+
frame = 0;
|
|
40
|
+
const y = Math.max(0, top());
|
|
41
|
+
if (Math.abs(y - last) >= tolerance) {
|
|
42
|
+
direction = y > last ? "down" : "up";
|
|
43
|
+
last = y;
|
|
44
|
+
}
|
|
45
|
+
if (y <= 0) { direction = "up"; last = 0; }
|
|
46
|
+
cb({ y, direction });
|
|
47
|
+
};
|
|
48
|
+
const onScroll = () => {
|
|
49
|
+
// A hidden page runs no frames: no need to wait for one.
|
|
50
|
+
if (document.visibilityState === "hidden") return run();
|
|
51
|
+
if (!frame) frame = requestAnimationFrame(run);
|
|
52
|
+
};
|
|
53
|
+
scroller.addEventListener("scroll", onScroll, { passive: true });
|
|
54
|
+
return () => {
|
|
55
|
+
scroller.removeEventListener("scroll", onScroll);
|
|
56
|
+
cancelAnimationFrame(frame);
|
|
57
|
+
};
|
|
58
|
+
}
|
package/core/styles.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// Shared component styles: sizes, radius, color variants and the loader.
|
|
2
|
+
// Components add the sheets they need to their `static styles`.
|
|
3
|
+
|
|
4
|
+
import { css } from "./core.js";
|
|
5
|
+
|
|
6
|
+
/** Palette colors of tokens.toml; anything else given as `color` is used as a raw CSS color. */
|
|
7
|
+
export const COLORS = ["dark", "gray", "red", "pink", "violet", "indigo", "blue", "cyan", "teal", "green", "yellow", "orange", "custom"];
|
|
8
|
+
|
|
9
|
+
/** Named steps of the space scale (--ray-space-*). */
|
|
10
|
+
const SPACES = ["xs", "sm", "md", "lg", "xl"];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A spacing value as CSS: a named step ("md") as its token, a bare number
|
|
14
|
+
* as px (0 included), anything else as a CSS length ("1.5rem", "5%").
|
|
15
|
+
* @param {string | number | undefined} value
|
|
16
|
+
* @returns {string | null} null when empty
|
|
17
|
+
*/
|
|
18
|
+
export function spaceValue(value) {
|
|
19
|
+
const s = String(value ?? "").trim();
|
|
20
|
+
if (!s) return null;
|
|
21
|
+
if (SPACES.includes(s)) return `var(--ray-space-${s})`;
|
|
22
|
+
return /^-?\d+(\.\d+)?$/.test(s) ? `${s}px` : s;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Variant tokens generated per color (tokens.toml [variants.*]). */
|
|
26
|
+
export const VARIANT_TOKENS = ["filled", "filled-hover", "light", "light-hover", "light-color", "outline", "outline-hover", "contrast"];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Points the private --_<variant> custom properties of `el` at a color:
|
|
30
|
+
* a palette name, a raw CSS color, or the primary color when empty.
|
|
31
|
+
* @param {HTMLElement} el
|
|
32
|
+
* @param {string | undefined} color
|
|
33
|
+
*/
|
|
34
|
+
export function applyColor(el, color) {
|
|
35
|
+
if (!color || COLORS.includes(color) || color === "primary") {
|
|
36
|
+
const base = !color || color === "primary" ? "--ray-primary" : `--ray-${color}`;
|
|
37
|
+
for (const v of VARIANT_TOKENS) el.style.setProperty(`--_${v}`, `var(${base}-${v})`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// A raw CSS color: derive the variants the way the tokens do.
|
|
41
|
+
const mix = (pct, other = "transparent") => `color-mix(in srgb, ${color} ${pct}, ${other})`;
|
|
42
|
+
const values = {
|
|
43
|
+
"filled": color,
|
|
44
|
+
"filled-hover": mix("85%", "black"),
|
|
45
|
+
"light": mix("12%"),
|
|
46
|
+
"light-hover": mix("18%"),
|
|
47
|
+
"light-color": color,
|
|
48
|
+
"outline": color,
|
|
49
|
+
"outline-hover": mix("6%"),
|
|
50
|
+
"contrast": "white",
|
|
51
|
+
};
|
|
52
|
+
for (const v of VARIANT_TOKENS) el.style.setProperty(`--_${v}`, values[v]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The gradient of variant="gradient" on `el`, from a "from to [deg]" spec:
|
|
57
|
+
* palette colors (their filled shade) or any CSS colors ("teal blue 90",
|
|
58
|
+
* "#7c3aed #db2777"). Empty: the --ray-gradient-* tokens.
|
|
59
|
+
* @param {HTMLElement} el
|
|
60
|
+
* @param {string | undefined} spec
|
|
61
|
+
*/
|
|
62
|
+
export function applyGradient(el, spec) {
|
|
63
|
+
const parts = String(spec ?? "").trim().split(/\s+/).filter(Boolean);
|
|
64
|
+
const color = (c) => (COLORS.includes(c) ? `var(--ray-${c}-filled)` : c);
|
|
65
|
+
if (parts[0]) el.style.setProperty("--_gradient-from", color(parts[0]));
|
|
66
|
+
else el.style.removeProperty("--_gradient-from");
|
|
67
|
+
if (parts[1]) el.style.setProperty("--_gradient-to", color(parts[1]));
|
|
68
|
+
else el.style.removeProperty("--_gradient-to");
|
|
69
|
+
if (parts[2]) el.style.setProperty("--_gradient-deg", /^-?\d+(\.\d+)?$/.test(parts[2]) ? `${parts[2]}deg` : parts[2]);
|
|
70
|
+
else el.style.removeProperty("--_gradient-deg");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Size scale on the host: --_h (control height), --_fs (font size),
|
|
75
|
+
* --_px (horizontal padding), --_gap. Default `sm`, like Mantine.
|
|
76
|
+
*/
|
|
77
|
+
export const sizeStyles = css`
|
|
78
|
+
:host {
|
|
79
|
+
--_h: var(--ray-control-height-sm);
|
|
80
|
+
--_fs: var(--ray-font-size-sm);
|
|
81
|
+
--_px: 1.125rem;
|
|
82
|
+
--_gap: var(--ray-space-2);
|
|
83
|
+
}
|
|
84
|
+
:host([size="xs"]) { --_h: var(--ray-control-height-xs); --_fs: var(--ray-font-size-xs); --_px: 0.875rem; --_gap: var(--ray-space-1); }
|
|
85
|
+
:host([size="md"]) { --_h: var(--ray-control-height-md); --_fs: var(--ray-font-size-md); --_px: 1.375rem; }
|
|
86
|
+
:host([size="lg"]) { --_h: var(--ray-control-height-lg); --_fs: var(--ray-font-size-lg); --_px: 1.625rem; --_gap: var(--ray-space-3); }
|
|
87
|
+
:host([size="xl"]) { --_h: var(--ray-control-height-xl); --_fs: var(--ray-font-size-xl); --_px: 2rem; --_gap: var(--ray-space-3); }
|
|
88
|
+
`;
|
|
89
|
+
|
|
90
|
+
/** Radius on the host: --_r. Default: the system-wide --ray-radius-default. */
|
|
91
|
+
export const radiusStyles = css`
|
|
92
|
+
:host { --_r: var(--ray-radius-default); }
|
|
93
|
+
:host([radius="xs"]) { --_r: var(--ray-radius-xs); }
|
|
94
|
+
:host([radius="sm"]) { --_r: var(--ray-radius-sm); }
|
|
95
|
+
:host([radius="md"]) { --_r: var(--ray-radius-md); }
|
|
96
|
+
:host([radius="lg"]) { --_r: var(--ray-radius-lg); }
|
|
97
|
+
:host([radius="xl"]) { --_r: var(--ray-radius-xl); }
|
|
98
|
+
:host([radius="full"]) { --_r: var(--ray-radius-full); }
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Color variants for an element carrying data-variant and the --_<variant>
|
|
103
|
+
* properties of applyColor(): filled, light, outline, subtle, default,
|
|
104
|
+
* transparent, and gradient (applyGradient / --ray-gradient-*).
|
|
105
|
+
*/
|
|
106
|
+
export const variantStyles = css`
|
|
107
|
+
[data-variant] {
|
|
108
|
+
border: 1px solid transparent;
|
|
109
|
+
transition:
|
|
110
|
+
background-color var(--ray-duration-fast) var(--ray-easing-standard),
|
|
111
|
+
border-color var(--ray-duration-fast) var(--ray-easing-standard),
|
|
112
|
+
color var(--ray-duration-fast) var(--ray-easing-standard);
|
|
113
|
+
}
|
|
114
|
+
[data-variant="filled"] { background: var(--_filled); color: var(--_contrast); }
|
|
115
|
+
[data-variant="light"] { background: var(--_light); color: var(--_light-color); }
|
|
116
|
+
[data-variant="outline"] { background: transparent; color: var(--_outline); border-color: var(--_outline); }
|
|
117
|
+
[data-variant="subtle"] { background: transparent; color: var(--_light-color); }
|
|
118
|
+
[data-variant="transparent"] { background: transparent; color: var(--_light-color); }
|
|
119
|
+
[data-variant="default"] { background: var(--ray-default); color: var(--ray-foreground); border-color: var(--ray-border); }
|
|
120
|
+
[data-variant="gradient"] {
|
|
121
|
+
background: linear-gradient(
|
|
122
|
+
var(--_gradient-deg, var(--ray-gradient-deg)),
|
|
123
|
+
var(--_gradient-from, var(--ray-gradient-from)),
|
|
124
|
+
var(--_gradient-to, var(--ray-gradient-to))
|
|
125
|
+
);
|
|
126
|
+
color: var(--ray-white);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
[data-interactive]:not([data-disabled])[data-variant="filled"]:hover { background: var(--_filled-hover); }
|
|
130
|
+
[data-interactive]:not([data-disabled])[data-variant="light"]:hover { background: var(--_light-hover); }
|
|
131
|
+
[data-interactive]:not([data-disabled])[data-variant="outline"]:hover { background: var(--_outline-hover); }
|
|
132
|
+
[data-interactive]:not([data-disabled])[data-variant="subtle"]:hover { background: var(--_light); }
|
|
133
|
+
[data-interactive]:not([data-disabled])[data-variant="default"]:hover { background: var(--ray-default-hover); }
|
|
134
|
+
[data-interactive]:not([data-disabled])[data-variant="gradient"]:hover { filter: brightness(0.92); }
|
|
135
|
+
|
|
136
|
+
[data-interactive][data-disabled] {
|
|
137
|
+
background: var(--ray-muted);
|
|
138
|
+
color: var(--ray-muted-foreground);
|
|
139
|
+
border-color: var(--ray-border);
|
|
140
|
+
cursor: not-allowed;
|
|
141
|
+
}
|
|
142
|
+
[data-interactive][data-disabled][data-variant="subtle"],
|
|
143
|
+
[data-interactive][data-disabled][data-variant="transparent"] {
|
|
144
|
+
background: transparent;
|
|
145
|
+
border-color: transparent;
|
|
146
|
+
}
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
/** A ring spinner: <span class="loader"></span>, sized by --_loader (default 1em). */
|
|
150
|
+
export const loaderStyles = css`
|
|
151
|
+
.loader {
|
|
152
|
+
display: inline-block;
|
|
153
|
+
flex: none;
|
|
154
|
+
width: var(--_loader, 1em);
|
|
155
|
+
height: var(--_loader, 1em);
|
|
156
|
+
border: max(2px, calc(var(--_loader, 1em) / 8)) solid currentColor;
|
|
157
|
+
border-right-color: transparent;
|
|
158
|
+
border-radius: 50%;
|
|
159
|
+
animation: ray-spin 0.75s linear infinite;
|
|
160
|
+
}
|
|
161
|
+
@keyframes ray-spin { to { transform: rotate(360deg); } }
|
|
162
|
+
@media (prefers-reduced-motion: reduce) {
|
|
163
|
+
.loader { animation-duration: 1.5s !important; }
|
|
164
|
+
}
|
|
165
|
+
`;
|
|
166
|
+
|
|
167
|
+
/** Visually hidden but available to assistive technology. */
|
|
168
|
+
export const srOnlyStyles = css`
|
|
169
|
+
.sr-only {
|
|
170
|
+
position: absolute;
|
|
171
|
+
width: 1px;
|
|
172
|
+
height: 1px;
|
|
173
|
+
padding: 0;
|
|
174
|
+
margin: -1px;
|
|
175
|
+
overflow: hidden;
|
|
176
|
+
clip: rect(0 0 0 0);
|
|
177
|
+
white-space: nowrap;
|
|
178
|
+
border: 0;
|
|
179
|
+
}
|
|
180
|
+
`;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* The backdrop of modal overlays (dialog, drawer, command palette): the
|
|
184
|
+
* --ray-overlay color and, when --ray-overlay-blur is set (tokens default:
|
|
185
|
+
* [overlay] blur), the page behind blurred. ::backdrop inherits from its
|
|
186
|
+
* dialog, so both follow the element, its subtree or :root.
|
|
187
|
+
*/
|
|
188
|
+
export const overlayStyles = css`
|
|
189
|
+
dialog::backdrop {
|
|
190
|
+
background: var(--ray-overlay);
|
|
191
|
+
-webkit-backdrop-filter: blur(var(--ray-overlay-blur, 0px));
|
|
192
|
+
backdrop-filter: blur(var(--ray-overlay-blur, 0px));
|
|
193
|
+
}
|
|
194
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
195
|
+
dialog::backdrop { -webkit-backdrop-filter: none; backdrop-filter: none; }
|
|
196
|
+
}
|
|
197
|
+
`;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The overlay-blur attribute of an overlay: a number (px), a CSS length, or
|
|
201
|
+
* "none"/"0" to turn the blur off. Unset: the inherited --ray-overlay-blur.
|
|
202
|
+
*/
|
|
203
|
+
export function applyOverlayBlur(el, value) {
|
|
204
|
+
if (value === undefined || value === null || value === "") {
|
|
205
|
+
el.style.removeProperty("--ray-overlay-blur");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const v = String(value).trim();
|
|
209
|
+
const css = v === "none" ? "0px" : /^\d+(\.\d+)?$/.test(v) ? `${v}px` : v;
|
|
210
|
+
el.style.setProperty("--ray-overlay-blur", css);
|
|
211
|
+
}
|
package/core.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Generated by ray-elements tools. Do not edit.
|
|
2
|
+
// The API of @raylang/elements without the components: importing it registers no element.
|
|
3
|
+
|
|
4
|
+
export * from "./core/core.js";
|
|
5
|
+
export { FormControl, FieldControl, fieldTemplate, fieldStyles, boxStyles } from "./core/form.js";
|
|
6
|
+
export { Floating, floatingStyles } from "./core/floating.js";
|
|
7
|
+
export { COLORS, VARIANT_TOKENS, applyColor, spaceValue, sizeStyles, radiusStyles, variantStyles, loaderStyles, srOnlyStyles, overlayStyles, applyOverlayBlur } from "./core/styles.js";
|
|
8
|
+
export { place, pointRect, autoUpdate } from "./core/position.js";
|
|
9
|
+
export { scrollerOf, watchScroll } from "./core/scroll.js";
|
|
10
|
+
export { tabbables, focusFirst } from "./core/focus.js";
|
|
11
|
+
export { duration, motionAllowed, play, playAll, collapseOut, POP_OUT } from "./core/motion.js";
|
|
12
|
+
export { dismissable } from "./core/dismiss.js";
|
|
13
|
+
export { matchesHotkey, formatHotkey } from "./core/hotkey.js";
|
|
14
|
+
export { CHART_SERIES, chartTheme, onChartThemeChange, withAlpha } from "./core/charts.js";
|
|
15
|
+
export { setHost, getHost, hostCan, onHostChange, HostFile, typeOfName, extensionsOfType, acceptFilters, titlebar, dragRegion, trackEdits } from "./core/host.js";
|
|
16
|
+
export { enableRaylang, PROTOCOL } from "./core/raylang.js";
|