@stackific/md3 0.1.1 → 0.1.3
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 +2486 -191
- package/dist/internal.md +274 -0
- package/dist/md3.css +1 -1
- package/dist/md3.js +1 -1
- package/package.json +1 -3
- package/src/main.js +0 -5
- package/src/runtime/elements/dialogs.js +0 -72
- package/src/runtime/elements/fields.js +0 -181
- package/src/runtime/elements/menus.js +0 -42
- package/src/runtime/elements/pages.js +0 -7
- package/src/runtime/elements/progress.js +0 -35
- package/src/runtime/elements/sliders.js +0 -78
- package/src/runtime/elements/snackbars.js +0 -27
- package/src/runtime/helpers/ripples.js +0 -46
- package/src/runtime/md3.js +0 -141
- package/src/runtime/palette.js +0 -64
- package/src/runtime/settings/theme.js +0 -194
- package/src/runtime/utils.js +0 -165
- package/src/styles/_config.scss +0 -142
- package/src/styles/_mixins.scss +0 -80
- package/src/styles/elements/_badges.scss +0 -65
- package/src/styles/elements/_bars.scss +0 -83
- package/src/styles/elements/_buttons.scss +0 -119
- package/src/styles/elements/_cards.scss +0 -32
- package/src/styles/elements/_chips.scss +0 -46
- package/src/styles/elements/_dialogs.scss +0 -143
- package/src/styles/elements/_dividers.scss +0 -46
- package/src/styles/elements/_expansions.scss +0 -19
- package/src/styles/elements/_fields.scss +0 -458
- package/src/styles/elements/_grids.scss +0 -35
- package/src/styles/elements/_icons.scss +0 -70
- package/src/styles/elements/_layouts.scss +0 -24
- package/src/styles/elements/_lists.scss +0 -76
- package/src/styles/elements/_main-layouts.scss +0 -45
- package/src/styles/elements/_media.scss +0 -104
- package/src/styles/elements/_menus.scss +0 -289
- package/src/styles/elements/_navigations.scss +0 -450
- package/src/styles/elements/_overlays.scss +0 -34
- package/src/styles/elements/_pages.scss +0 -28
- package/src/styles/elements/_progress.scss +0 -141
- package/src/styles/elements/_selections.scss +0 -248
- package/src/styles/elements/_shapes.scss +0 -153
- package/src/styles/elements/_sliders.scss +0 -336
- package/src/styles/elements/_snackbars.scss +0 -44
- package/src/styles/elements/_tables.scss +0 -67
- package/src/styles/elements/_tabs.scss +0 -49
- package/src/styles/elements/_tooltips.scss +0 -125
- package/src/styles/fonts/material-symbols-outlined.woff2 +0 -0
- package/src/styles/fonts/material-symbols-rounded.woff2 +0 -0
- package/src/styles/fonts/material-symbols-sharp.woff2 +0 -0
- package/src/styles/fonts/material-symbols-subset.woff2 +0 -0
- package/src/styles/helpers/_alignments.scss +0 -29
- package/src/styles/helpers/_blurs.scss +0 -26
- package/src/styles/helpers/_colors.scss +0 -39
- package/src/styles/helpers/_directions.scss +0 -30
- package/src/styles/helpers/_elevates.scss +0 -20
- package/src/styles/helpers/_forms.scss +0 -76
- package/src/styles/helpers/_margins.scss +0 -39
- package/src/styles/helpers/_opacities.scss +0 -18
- package/src/styles/helpers/_paddings.scss +0 -35
- package/src/styles/helpers/_positions.scss +0 -44
- package/src/styles/helpers/_responsive.scss +0 -24
- package/src/styles/helpers/_ripples.scss +0 -40
- package/src/styles/helpers/_scrolls.scss +0 -7
- package/src/styles/helpers/_shadows.scss +0 -22
- package/src/styles/helpers/_sizes.scss +0 -34
- package/src/styles/helpers/_spaces.scss +0 -22
- package/src/styles/helpers/_typography.scss +0 -132
- package/src/styles/helpers/_waves.scss +0 -52
- package/src/styles/helpers/_zoom.scss +0 -18
- package/src/styles/md3.scss +0 -61
- package/src/styles/settings/_fonts.scss +0 -41
- package/src/styles/settings/_globals.scss +0 -104
- package/src/styles/settings/_reset.scss +0 -82
- package/src/styles/settings/_theme.scss +0 -126
- package/src/styles/settings/_themes.scss +0 -1525
- package/src/styles/shapes/arch.svg +0 -1
- package/src/styles/shapes/arrow.svg +0 -1
- package/src/styles/shapes/boom.svg +0 -1
- package/src/styles/shapes/bun.svg +0 -1
- package/src/styles/shapes/burst.svg +0 -1
- package/src/styles/shapes/circle.svg +0 -1
- package/src/styles/shapes/clamshell.svg +0 -1
- package/src/styles/shapes/diamond.svg +0 -1
- package/src/styles/shapes/fan.svg +0 -1
- package/src/styles/shapes/flower.svg +0 -1
- package/src/styles/shapes/gem.svg +0 -1
- package/src/styles/shapes/ghost-ish.svg +0 -1
- package/src/styles/shapes/heart.svg +0 -1
- package/src/styles/shapes/leaf-clover4.svg +0 -1
- package/src/styles/shapes/leaf-clover8.svg +0 -1
- package/src/styles/shapes/loading-indicator.svg +0 -1
- package/src/styles/shapes/oval.svg +0 -1
- package/src/styles/shapes/pentagon.svg +0 -1
- package/src/styles/shapes/pill.svg +0 -1
- package/src/styles/shapes/pixel-circle.svg +0 -1
- package/src/styles/shapes/pixel-triangle.svg +0 -1
- package/src/styles/shapes/puffy-diamond.svg +0 -1
- package/src/styles/shapes/puffy.svg +0 -1
- package/src/styles/shapes/semicircle.svg +0 -1
- package/src/styles/shapes/sided-cookie12.svg +0 -1
- package/src/styles/shapes/sided-cookie4.svg +0 -1
- package/src/styles/shapes/sided-cookie6.svg +0 -1
- package/src/styles/shapes/sided-cookie7.svg +0 -1
- package/src/styles/shapes/sided-cookie9.svg +0 -1
- package/src/styles/shapes/slanted.svg +0 -1
- package/src/styles/shapes/soft-boom.svg +0 -1
- package/src/styles/shapes/soft-burst.svg +0 -1
- package/src/styles/shapes/square.svg +0 -1
- package/src/styles/shapes/sunny.svg +0 -1
- package/src/styles/shapes/triangle.svg +0 -1
- package/src/styles/shapes/very-sunny.svg +0 -1
- package/src/styles/shapes/wavy-circle.svg +0 -1
- package/src/styles/shapes/wavy.svg +0 -1
package/src/runtime/md3.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { updateAllFields } from "./elements/fields.js";
|
|
2
|
-
import { updateAllSliders } from "./elements/sliders.js";
|
|
3
|
-
import {
|
|
4
|
-
attachAutoListener,
|
|
5
|
-
getThemes,
|
|
6
|
-
readStoredMode,
|
|
7
|
-
readStoredTheme,
|
|
8
|
-
updateMode,
|
|
9
|
-
updateTheme,
|
|
10
|
-
} from "./settings/theme.js";
|
|
11
|
-
import {
|
|
12
|
-
addClass, guid, hasClass, hasTag, onWeak, query, removeClass, updateAllClickable,
|
|
13
|
-
} from "./utils.js";
|
|
14
|
-
import { updateDialog } from "./elements/dialogs.js";
|
|
15
|
-
import { updateMenu } from "./elements/menus.js";
|
|
16
|
-
import { updateSnackbar } from "./elements/snackbars.js";
|
|
17
|
-
import { updatePage } from "./elements/pages.js";
|
|
18
|
-
import { updateAllRipples } from "./helpers/ripples.js";
|
|
19
|
-
import { updateAllProgress } from "./elements/progress.js";
|
|
20
|
-
|
|
21
|
-
let _timeoutMutation;
|
|
22
|
-
let _mutation = null;
|
|
23
|
-
|
|
24
|
-
function onMutation() {
|
|
25
|
-
if (_timeoutMutation) clearTimeout(_timeoutMutation);
|
|
26
|
-
_timeoutMutation = setTimeout(() => _ui(), 180);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function run(from, to, options, e) {
|
|
30
|
-
if (!to) {
|
|
31
|
-
to = query(from.getAttribute("data-ui"));
|
|
32
|
-
if (!to) {
|
|
33
|
-
from.classList.toggle("active");
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
updateAllClickable(from);
|
|
39
|
-
|
|
40
|
-
if (hasTag(to, "dialog")) {
|
|
41
|
-
requestAnimationFrame(() => updateDialog(from, to));
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (hasTag(to, "menu")) {
|
|
46
|
-
requestAnimationFrame(() => updateMenu(from, to, e));
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (hasClass(to, "snackbar")) {
|
|
51
|
-
requestAnimationFrame(() => updateSnackbar(to, options));
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (hasClass(to, "page")) {
|
|
56
|
-
requestAnimationFrame(() => updatePage(to));
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (hasClass(to, "active")) {
|
|
61
|
-
removeClass(from, "active");
|
|
62
|
-
removeClass(to, "active");
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
addClass(to, "active");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function setup() {
|
|
70
|
-
if (globalThis.ui || _mutation || !globalThis.MutationObserver) return;
|
|
71
|
-
_mutation = new MutationObserver(onMutation);
|
|
72
|
-
_mutation.observe(document.body, { childList: true, subtree: true });
|
|
73
|
-
onMutation();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function onClickDataUi(e) {
|
|
77
|
-
const from = e.target.closest("[data-ui]");
|
|
78
|
-
if (from) void run(from, null, null, e);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function onKeydownDataUi(e) {
|
|
82
|
-
const from = e.target.closest("[data-ui]");
|
|
83
|
-
if (from && hasTag(from, "a") && !from.getAttribute("href") && e.key === "Enter") {
|
|
84
|
-
void run(from, null, null, e);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function updateAllDataUis() {
|
|
89
|
-
const body = document.body;
|
|
90
|
-
if (!body) return;
|
|
91
|
-
|
|
92
|
-
onWeak(body, "click", onClickDataUi);
|
|
93
|
-
onWeak(body, "keydown", onKeydownDataUi);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function _ui(selector, options) {
|
|
97
|
-
if (selector) {
|
|
98
|
-
if (selector === "setup") { setup(); return undefined; }
|
|
99
|
-
if (selector === "guid") return guid();
|
|
100
|
-
if (selector === "mode") return updateMode(options);
|
|
101
|
-
if (selector === "theme") return updateTheme(options);
|
|
102
|
-
if (selector === "themes") return getThemes();
|
|
103
|
-
|
|
104
|
-
const to = query(selector);
|
|
105
|
-
if (!to) return undefined;
|
|
106
|
-
void run(to, to, options);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
updateAllDataUis();
|
|
110
|
-
updateAllFields();
|
|
111
|
-
updateAllRipples();
|
|
112
|
-
updateAllSliders();
|
|
113
|
-
updateAllProgress();
|
|
114
|
-
return undefined;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function start() {
|
|
118
|
-
if (globalThis.ui) return;
|
|
119
|
-
|
|
120
|
-
// Stored preference wins over the HTML default — the user's last choice
|
|
121
|
-
// outranks `<html data-mode="…">` hardcoded in markup. If neither is set,
|
|
122
|
-
// default to "auto" so the OS theme drives.
|
|
123
|
-
const root = globalThis.document?.documentElement;
|
|
124
|
-
if (root) {
|
|
125
|
-
updateMode(readStoredMode() || root.dataset.mode || "auto");
|
|
126
|
-
// Theme persistence: stored choice beats the HTML default, same as mode.
|
|
127
|
-
// If neither is set, leave data-theme alone — bare :root carries the
|
|
128
|
-
// implicit default (first theme in $themes).
|
|
129
|
-
const storedTheme = readStoredTheme();
|
|
130
|
-
if (storedTheme) updateTheme(storedTheme);
|
|
131
|
-
}
|
|
132
|
-
attachAutoListener();
|
|
133
|
-
|
|
134
|
-
setup();
|
|
135
|
-
globalThis.ui = _ui;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
start();
|
|
139
|
-
|
|
140
|
-
export const ui = globalThis.ui;
|
|
141
|
-
export default ui;
|
package/src/runtime/palette.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// Generated by scripts/build-palette.mjs from
|
|
2
|
-
// src/styles/_config.scss ($material-palette)
|
|
3
|
-
// src/styles/settings/_themes.scss ($themes)
|
|
4
|
-
// DO NOT EDIT — re-run `pnpm build` (or `node scripts/build-palette.mjs`).
|
|
5
|
-
|
|
6
|
-
export const palette = {
|
|
7
|
-
"red": "#F44336",
|
|
8
|
-
"pink": "#E91E63",
|
|
9
|
-
"purple": "#9C27B0",
|
|
10
|
-
"deep-purple": "#673AB7",
|
|
11
|
-
"blue": "#2196F3",
|
|
12
|
-
"light-blue": "#03A9F4",
|
|
13
|
-
"cyan": "#00BCD4",
|
|
14
|
-
"green": "#4CAF50",
|
|
15
|
-
"light-green": "#8BC34A",
|
|
16
|
-
"lime": "#CDDC39",
|
|
17
|
-
"yellow": "#FFEB3B",
|
|
18
|
-
"amber": "#FFC107",
|
|
19
|
-
"orange": "#FF9800",
|
|
20
|
-
"deep-orange": "#FF5722",
|
|
21
|
-
"brown": "#795548",
|
|
22
|
-
"blue-grey": "#607D8B",
|
|
23
|
-
"stackific": "#1447E6",
|
|
24
|
-
"hello-pumpkin": "#FF8F00",
|
|
25
|
-
"sea-lettuce": "#63A002",
|
|
26
|
-
"olive": "#7C7C67",
|
|
27
|
-
"nord": "#5E81AC",
|
|
28
|
-
"vega-violet": "#AD46FF",
|
|
29
|
-
"wild-strawberry": "#F6339A",
|
|
30
|
-
"heliotrope-magenta": "#E12AFB",
|
|
31
|
-
"voodoo-violet": "#804792",
|
|
32
|
-
"red-orchid": "#C0001C",
|
|
33
|
-
"green-brown": "#6E5D00",
|
|
34
|
-
"shakshuka": "#AB350F",
|
|
35
|
-
"purple-honeycreeper": "#8E51FF",
|
|
36
|
-
"maldives": "#00B8DB",
|
|
37
|
-
"verditer": "#00BBA7",
|
|
38
|
-
"fennel": "#00BC7D",
|
|
39
|
-
"gold": "#EFB100",
|
|
40
|
-
"vitamin-c": "#FD9A00",
|
|
41
|
-
"burtuqali": "#FF6900",
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const themes = [
|
|
45
|
-
"stackific",
|
|
46
|
-
"hello-pumpkin",
|
|
47
|
-
"sea-lettuce",
|
|
48
|
-
"olive",
|
|
49
|
-
"nord",
|
|
50
|
-
"vega-violet",
|
|
51
|
-
"wild-strawberry",
|
|
52
|
-
"heliotrope-magenta",
|
|
53
|
-
"voodoo-violet",
|
|
54
|
-
"red-orchid",
|
|
55
|
-
"green-brown",
|
|
56
|
-
"shakshuka",
|
|
57
|
-
"purple-honeycreeper",
|
|
58
|
-
"maldives",
|
|
59
|
-
"verditer",
|
|
60
|
-
"fennel",
|
|
61
|
-
"gold",
|
|
62
|
-
"vitamin-c",
|
|
63
|
-
"burtuqali",
|
|
64
|
-
];
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { isDark } from "../utils.js";
|
|
2
|
-
import { palette, themes } from "../palette.js";
|
|
3
|
-
|
|
4
|
-
const _lastTheme = {
|
|
5
|
-
light: "",
|
|
6
|
-
dark: "",
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const MODE_STORAGE_KEY = "md3:mode";
|
|
10
|
-
const THEME_STORAGE_KEY = "md3:theme";
|
|
11
|
-
|
|
12
|
-
export function getThemes() {
|
|
13
|
-
return themes.slice();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function readStoredTheme() {
|
|
17
|
-
try { return globalThis.localStorage?.getItem(THEME_STORAGE_KEY) || null; }
|
|
18
|
-
catch { return null; }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function writeStoredTheme(value) {
|
|
22
|
-
try { globalThis.localStorage?.setItem(THEME_STORAGE_KEY, value); }
|
|
23
|
-
catch { /* localStorage may be blocked */ }
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function getRoot() {
|
|
27
|
-
return document?.documentElement;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function readStoredMode() {
|
|
31
|
-
try { return globalThis.localStorage?.getItem(MODE_STORAGE_KEY) || null; }
|
|
32
|
-
catch { return null; }
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function writeStoredMode(value) {
|
|
36
|
-
try { globalThis.localStorage?.setItem(MODE_STORAGE_KEY, value); }
|
|
37
|
-
catch { /* localStorage may be blocked (private mode, sandboxed iframe) */ }
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// User's preference, read straight off <html data-mode>. Falls back to the
|
|
41
|
-
// stored value, then "auto" — used by callers that want to display the
|
|
42
|
-
// current preference (e.g. the demo's mode-switcher icon).
|
|
43
|
-
function getMode() {
|
|
44
|
-
const m = getRoot()?.dataset?.mode;
|
|
45
|
-
if (m === "auto" || m === "light" || m === "dark") return m;
|
|
46
|
-
return readStoredMode() || "auto";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// The concrete mode actually painted. "auto" resolves via prefers-color-scheme
|
|
50
|
-
// at read time. Used internally for inline-style overrides applied to <html>.
|
|
51
|
-
function getResolvedMode() {
|
|
52
|
-
const m = getRoot()?.dataset?.mode;
|
|
53
|
-
if (m === "light" || m === "dark") return m;
|
|
54
|
-
return isDark() ? "dark" : "light";
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function lastTheme() {
|
|
58
|
-
if (_lastTheme.light && _lastTheme.dark) return _lastTheme;
|
|
59
|
-
const root = getRoot();
|
|
60
|
-
if (!root) return _lastTheme;
|
|
61
|
-
|
|
62
|
-
// Probe by swapping data-mode to each explicit value in turn, then restore.
|
|
63
|
-
// We probe "light"/"dark" only because "auto" depends on the host OS state.
|
|
64
|
-
const prevMode = root.dataset.mode;
|
|
65
|
-
|
|
66
|
-
const probe = (mode) => {
|
|
67
|
-
root.dataset.mode = mode;
|
|
68
|
-
const style = getComputedStyle(root);
|
|
69
|
-
const variables = [
|
|
70
|
-
"--primary", "--on-primary", "--primary-container", "--on-primary-container",
|
|
71
|
-
"--secondary", "--on-secondary", "--secondary-container", "--on-secondary-container",
|
|
72
|
-
"--tertiary", "--on-tertiary", "--tertiary-container", "--on-tertiary-container",
|
|
73
|
-
"--error", "--on-error", "--error-container", "--on-error-container",
|
|
74
|
-
"--background", "--on-background", "--surface", "--on-surface",
|
|
75
|
-
"--surface-variant", "--on-surface-variant", "--outline", "--outline-variant",
|
|
76
|
-
"--shadow", "--scrim", "--inverse-surface", "--inverse-on-surface", "--inverse-primary",
|
|
77
|
-
"--surface-dim", "--surface-bright", "--surface-container-lowest", "--surface-container-low",
|
|
78
|
-
"--surface-container", "--surface-container-high", "--surface-container-highest",
|
|
79
|
-
];
|
|
80
|
-
let out = "";
|
|
81
|
-
for (let i = 0, n = variables.length; i < n; i++) {
|
|
82
|
-
out += variables[i] + ":" + style.getPropertyValue(variables[i]) + ";";
|
|
83
|
-
}
|
|
84
|
-
return out;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
_lastTheme.light = probe("light");
|
|
89
|
-
_lastTheme.dark = probe("dark");
|
|
90
|
-
} finally {
|
|
91
|
-
if (prevMode === undefined) delete root.dataset.mode;
|
|
92
|
-
else root.dataset.mode = prevMode;
|
|
93
|
-
}
|
|
94
|
-
return _lastTheme;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export async function updateTheme(source) {
|
|
98
|
-
const root = getRoot();
|
|
99
|
-
if (!source) return lastTheme();
|
|
100
|
-
|
|
101
|
-
if (source.light && source.dark) {
|
|
102
|
-
_lastTheme.light = source.light;
|
|
103
|
-
_lastTheme.dark = source.dark;
|
|
104
|
-
root.setAttribute("style", source[getResolvedMode()]);
|
|
105
|
-
return source;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Baked named theme: pure attribute swap — no MDC call, no inline style.
|
|
109
|
-
// The CSS rules in _themes.scss handle the token swap via the
|
|
110
|
-
// [data-theme] attribute selector.
|
|
111
|
-
if (typeof source === "string" && themes.includes(source)) {
|
|
112
|
-
writeStoredTheme(source);
|
|
113
|
-
root.dataset.theme = source;
|
|
114
|
-
root.removeAttribute("style");
|
|
115
|
-
_lastTheme.light = "";
|
|
116
|
-
_lastTheme.dark = "";
|
|
117
|
-
return { light: "", dark: "" };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Palette-name alias: `ui("theme", "red")` → `ui("theme", "#F44336")`.
|
|
121
|
-
// Names come from $material-palette in src/styles/_config.scss; the JS
|
|
122
|
-
// map is regenerated by scripts/build-palette.mjs on every build.
|
|
123
|
-
if (typeof source === "string" && palette[source]) source = palette[source];
|
|
124
|
-
|
|
125
|
-
// Resolve material-dynamic-colors from the host page. Consumers either
|
|
126
|
-
// `import "material-dynamic-colors"` (sets globalThis.materialDynamicColors
|
|
127
|
-
// as a side effect) or load the CDN <script> — both register the global.
|
|
128
|
-
const mdc = globalThis.materialDynamicColors;
|
|
129
|
-
if (typeof mdc !== "function") {
|
|
130
|
-
throw new Error(
|
|
131
|
-
'ui("theme", source) requires material-dynamic-colors. Install it and `import "material-dynamic-colors"` once at app entry, or include the CDN script.',
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return mdc(source).then((theme) => {
|
|
136
|
-
const toCss = (data) => {
|
|
137
|
-
let style = "";
|
|
138
|
-
for (const key of Object.keys(data)) {
|
|
139
|
-
const value = data[key];
|
|
140
|
-
const kebabCase = key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
|
|
141
|
-
style += "--" + kebabCase + ":" + value + ";";
|
|
142
|
-
}
|
|
143
|
-
return style;
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
_lastTheme.light = toCss(theme.light);
|
|
147
|
-
_lastTheme.dark = toCss(theme.dark);
|
|
148
|
-
root.setAttribute("style", _lastTheme[getResolvedMode()]);
|
|
149
|
-
return _lastTheme;
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export function updateMode(value) {
|
|
154
|
-
const root = getRoot();
|
|
155
|
-
|
|
156
|
-
if (!root) return value;
|
|
157
|
-
if (!value) return getMode();
|
|
158
|
-
|
|
159
|
-
// Normalize: invalid values fall through to "auto".
|
|
160
|
-
if (value !== "auto" && value !== "light" && value !== "dark") value = "auto";
|
|
161
|
-
|
|
162
|
-
writeStoredMode(value);
|
|
163
|
-
root.dataset.mode = value;
|
|
164
|
-
|
|
165
|
-
// If an MDC-generated inline style is active, swap it to match the
|
|
166
|
-
// currently resolved mode. The CSS-side tokens handle themselves via
|
|
167
|
-
// the data-mode attribute selectors and @media (prefers-color-scheme).
|
|
168
|
-
if (_lastTheme.light && _lastTheme.dark) {
|
|
169
|
-
root.setAttribute("style", _lastTheme[getResolvedMode()]);
|
|
170
|
-
}
|
|
171
|
-
return getMode();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// `prefers-color-scheme` listener — only needed to keep an MDC-generated
|
|
175
|
-
// inline style override in sync when the OS theme flips while data-mode is
|
|
176
|
-
// "auto". Regular CSS tokens are already handled by the @media rules in
|
|
177
|
-
// _themes.scss, so no work is needed for them here.
|
|
178
|
-
let _autoListenerAttached = false;
|
|
179
|
-
export function attachAutoListener() {
|
|
180
|
-
if (_autoListenerAttached) return;
|
|
181
|
-
if (typeof globalThis.matchMedia !== "function") return;
|
|
182
|
-
|
|
183
|
-
const mql = globalThis.matchMedia("(prefers-color-scheme: dark)");
|
|
184
|
-
const handler = () => {
|
|
185
|
-
const root = getRoot();
|
|
186
|
-
if (!root || root.dataset.mode !== "auto") return;
|
|
187
|
-
if (!_lastTheme.light || !_lastTheme.dark) return;
|
|
188
|
-
root.setAttribute("style", _lastTheme[mql.matches ? "dark" : "light"]);
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
if (mql.addEventListener) mql.addEventListener("change", handler);
|
|
192
|
-
else if (mql.addListener) mql.addListener(handler);
|
|
193
|
-
_autoListenerAttached = true;
|
|
194
|
-
}
|
package/src/runtime/utils.js
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
const _emptyNodeList = [];
|
|
2
|
-
const _weakMap = new WeakMap();
|
|
3
|
-
|
|
4
|
-
export const isChrome = navigator.userAgent.includes("Chrome");
|
|
5
|
-
export const isFirefox = navigator.userAgent.includes("Firefox") && !isChrome;
|
|
6
|
-
export const isSafari = navigator.userAgent.includes("Safari") && !isChrome;
|
|
7
|
-
export const isWindows = navigator.userAgent.includes("Windows");
|
|
8
|
-
export const isMac = navigator.userAgent.includes("Macintosh");
|
|
9
|
-
export const isLinux = navigator.userAgent.includes("Linux");
|
|
10
|
-
export const isAndroid = navigator.userAgent.includes("Android");
|
|
11
|
-
export const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
12
|
-
|
|
13
|
-
let _isTouchable;
|
|
14
|
-
export function isTouchable() {
|
|
15
|
-
if (_isTouchable !== undefined) return _isTouchable;
|
|
16
|
-
_isTouchable = window?.matchMedia?.("(pointer: coarse)")?.matches ?? false;
|
|
17
|
-
return _isTouchable;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function isDark() {
|
|
21
|
-
return window?.matchMedia?.("(prefers-color-scheme: dark)")?.matches ?? false;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function wait(milliseconds) {
|
|
25
|
-
await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function guid() {
|
|
29
|
-
return "fxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
30
|
-
const r = (Math.random() * 16) | 0;
|
|
31
|
-
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
32
|
-
return v.toString(16);
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function query(selector, element) {
|
|
37
|
-
try {
|
|
38
|
-
return typeof selector === "string"
|
|
39
|
-
? (element ?? document).querySelector(selector)
|
|
40
|
-
: selector;
|
|
41
|
-
} catch {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function queryAll(selector, element) {
|
|
47
|
-
try {
|
|
48
|
-
return typeof selector === "string"
|
|
49
|
-
? (element ?? document).querySelectorAll(selector)
|
|
50
|
-
: selector ?? _emptyNodeList;
|
|
51
|
-
} catch {
|
|
52
|
-
return _emptyNodeList;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function hasClass(element, name) {
|
|
57
|
-
return element?.classList.contains(name) ?? false;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function hasTag(element, name) {
|
|
61
|
-
return element?.tagName?.toLowerCase() === name;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function hasType(element, name) {
|
|
65
|
-
return element?.type?.toLowerCase() === name;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function addClass(element, name) {
|
|
69
|
-
if (element instanceof NodeList) for (let i = 0; i < element.length; i++) element[i].classList.add(name);
|
|
70
|
-
else element?.classList.add(name);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function removeClass(element, name) {
|
|
74
|
-
if (element instanceof NodeList) for (let i = 0; i < element.length; i++) element[i].classList.remove(name);
|
|
75
|
-
else element?.classList.remove(name);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function on(element, name, callback, useCapture = true) {
|
|
79
|
-
if (element?.addEventListener) element.addEventListener(name, callback, useCapture);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function onWeak(element, name, callback, useCapture = true) {
|
|
83
|
-
if (!element) return;
|
|
84
|
-
|
|
85
|
-
let events = _weakMap.get(element);
|
|
86
|
-
if (!events) {
|
|
87
|
-
events = new Map();
|
|
88
|
-
_weakMap.set(element, events);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const key = name + (useCapture ? "1" : "0");
|
|
92
|
-
let callbacks = events.get(key);
|
|
93
|
-
if (!callbacks) {
|
|
94
|
-
callbacks = new Set();
|
|
95
|
-
events.set(key, callbacks);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (callbacks.has(callback)) return;
|
|
99
|
-
|
|
100
|
-
callbacks.add(callback);
|
|
101
|
-
on(element, name, callback, useCapture);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function off(element, name, callback, useCapture = true) {
|
|
105
|
-
if (element?.removeEventListener) element.removeEventListener(name, callback, useCapture);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function insertBefore(newElement, element) {
|
|
109
|
-
element?.parentNode?.insertBefore(newElement, element);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function prev(element) {
|
|
113
|
-
return element?.previousElementSibling;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function next(element) {
|
|
117
|
-
return element?.nextElementSibling;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function parent(element) {
|
|
121
|
-
return element?.parentElement;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function create(htmlAttributesAsJson) {
|
|
125
|
-
const element = document.createElement("div");
|
|
126
|
-
for (const key of Object.keys(htmlAttributesAsJson)) {
|
|
127
|
-
element.setAttribute(key, htmlAttributesAsJson[key]);
|
|
128
|
-
}
|
|
129
|
-
return element;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function blurActiveElement() {
|
|
133
|
-
document.activeElement?.blur?.();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function queryAllDataUi(id) {
|
|
137
|
-
return queryAll(`[data-ui="#${id}"]`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function queryDataUi(id) {
|
|
141
|
-
return query(`[data-ui="#${id}"]`);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export function updateAllClickable(element) {
|
|
145
|
-
if (element.id && hasClass(element, "page")) element = queryDataUi(element.id) ?? element;
|
|
146
|
-
|
|
147
|
-
const container = parent(element);
|
|
148
|
-
if (!hasClass(container, "tabs") && !hasClass(container, "tabbed") && !hasTag(container, "nav")) return;
|
|
149
|
-
|
|
150
|
-
const as = queryAll("a", container);
|
|
151
|
-
for (let i = 0; i < as.length; i++) removeClass(as[i], "active");
|
|
152
|
-
if (!hasTag(element, "button") && !hasClass(element, "button") && !hasClass(element, "chip")) addClass(element, "active");
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function addWeakElement(element) {
|
|
156
|
-
if (_weakMap.has(element)) return;
|
|
157
|
-
_weakMap.set(element, new Map());
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export function rootSizeInPixels() {
|
|
161
|
-
const size = getComputedStyle(document.documentElement).getPropertyValue("--size") || "16px";
|
|
162
|
-
if (size.includes("%")) return (parseInt(size) * 16) / 100;
|
|
163
|
-
if (size.includes("em")) return parseInt(size) * 16;
|
|
164
|
-
return parseInt(size);
|
|
165
|
-
}
|