beercss 3.6.13 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/cdn/beer.css +29 -32
- package/dist/cdn/beer.js +420 -317
- package/dist/cdn/beer.min.css +1 -1
- package/dist/cdn/beer.min.js +1 -1
- package/index.d.ts +5 -2
- package/package.json +2 -2
- package/src/cdn/beer.ts +32 -490
- package/src/cdn/elements/dialogs.css +1 -0
- package/src/cdn/elements/dialogs.ts +68 -0
- package/src/cdn/elements/fields.css +2 -1
- package/src/cdn/elements/fields.ts +142 -0
- package/src/cdn/elements/icons.css +3 -1
- package/src/cdn/elements/menus.css +1 -1
- package/src/cdn/elements/menus.ts +40 -0
- package/src/cdn/elements/navigations.css +2 -0
- package/src/cdn/elements/pages.ts +7 -0
- package/src/cdn/elements/selections.css +14 -23
- package/src/cdn/elements/sliders.css +2 -1
- package/src/cdn/elements/sliders.ts +86 -0
- package/src/cdn/elements/snackbars.ts +27 -0
- package/src/cdn/helpers/theme.ts +84 -0
- package/src/cdn/helpers/waves.css +2 -2
- package/src/cdn/settings/fonts.css +3 -3
- package/src/cdn/utils.ts +162 -0
package/src/cdn/beer.ts
CHANGED
|
@@ -1,518 +1,60 @@
|
|
|
1
|
+
import { updateAllFields } from "./elements/fields";
|
|
2
|
+
import { updateAllSliders } from "./elements/sliders";
|
|
3
|
+
import { updateMode, updateTheme } from "./helpers/theme";
|
|
1
4
|
import { type IBeerCssTheme } from "./interfaces";
|
|
5
|
+
import { guid, on, query, queryAll, run } from "./utils";
|
|
2
6
|
|
|
3
|
-
let _timeoutSnackbar: ReturnType<typeof setTimeout>;
|
|
4
7
|
let _timeoutMutation: ReturnType<typeof setTimeout>;
|
|
5
|
-
let _timeoutMenu: ReturnType<typeof setTimeout>;
|
|
6
8
|
let _mutation: MutationObserver | null;
|
|
7
|
-
const _lastTheme: IBeerCssTheme = {
|
|
8
|
-
light: "",
|
|
9
|
-
dark: "",
|
|
10
|
-
};
|
|
11
|
-
const _emptyNodeList = [] as unknown as NodeListOf<Element>;
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function guid (): string {
|
|
18
|
-
return "fxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c: string) => {
|
|
19
|
-
const r = (Math.random() * 16) | 0;
|
|
20
|
-
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
21
|
-
return v.toString(16);
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function query (selector: string | Element | null, element?: Element | null): Element | null {
|
|
26
|
-
try {
|
|
27
|
-
return (typeof selector === "string")
|
|
28
|
-
? (element ?? document).querySelector(selector)
|
|
29
|
-
: selector;
|
|
30
|
-
} catch {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function queryAll (selector: string | NodeListOf<Element> | null, element?: Element | null): NodeListOf<Element> {
|
|
36
|
-
try {
|
|
37
|
-
return (typeof selector === "string")
|
|
38
|
-
? (element ?? document).querySelectorAll(selector)
|
|
39
|
-
: selector ?? _emptyNodeList;
|
|
40
|
-
} catch {
|
|
41
|
-
return _emptyNodeList;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function hasClass (element: Element | null, name: string): boolean {
|
|
46
|
-
return element?.classList?.contains(name) ?? false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function hasTag (element: Element | null, name: string): boolean {
|
|
50
|
-
return element?.tagName?.toLowerCase() === name;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function hasType (element: HTMLInputElement | null, name: string): boolean {
|
|
54
|
-
return element?.type?.toLowerCase() === name;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function addClass (element: Element | null, name: string): void {
|
|
58
|
-
element?.classList?.add(name);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function removeClass (element: Element | null, name: string): void {
|
|
62
|
-
element?.classList?.remove(name);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function on (element: any, name: string, callback: any, useCapture: boolean = true): void {
|
|
66
|
-
element?.addEventListener(name, callback, useCapture);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function off (element: any, name: string, callback: any, useCapture: boolean = true): void {
|
|
70
|
-
element?.removeEventListener(name, callback, useCapture);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function insertBefore (newElement: Element, element: Element | null): void {
|
|
74
|
-
element?.parentNode?.insertBefore(newElement, element);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function prev (element: Element): Element | null {
|
|
78
|
-
return element?.previousElementSibling;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function next (element: Element): Element | null {
|
|
82
|
-
return element?.nextElementSibling;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function parent (element: Element): Element | null {
|
|
86
|
-
return element?.parentElement;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function create (htmlAttributesAsJson: any): HTMLElement {
|
|
90
|
-
const element = document.createElement("div");
|
|
91
|
-
for (let i = 0, keys = Object.keys(htmlAttributesAsJson), n = keys.length; i < n; i++) {
|
|
92
|
-
const key = keys[i];
|
|
93
|
-
const value = htmlAttributesAsJson[key] as string;
|
|
94
|
-
element.setAttribute(key, value);
|
|
95
|
-
}
|
|
96
|
-
return element;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function updateInput (target: Element): void {
|
|
100
|
-
const input = target as HTMLInputElement;
|
|
101
|
-
if (hasType(input, "number") && !input.value) input.value = "";
|
|
102
|
-
if (!input.placeholder) input.placeholder = " ";
|
|
103
|
-
if (target.getAttribute("data-ui")) void open(target, null);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function onClickElement (e: Event): void {
|
|
107
|
-
void open(e.currentTarget as HTMLElement, null, null, e);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function onClickLabel (e: Event): void {
|
|
111
|
-
const target = e.currentTarget as Element;
|
|
112
|
-
const parentTarget = parent(target);
|
|
113
|
-
const input = query("input:not([type=file], [type=checkbox], [type=radio]), select, textarea", parentTarget) as HTMLElement;
|
|
114
|
-
if (input) input.focus();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function onFocusInput (e: Event): void {
|
|
118
|
-
const target = e.currentTarget as Element;
|
|
119
|
-
updateInput(target);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function onBlurInput (e: Event): void {
|
|
123
|
-
const target = e.currentTarget as Element;
|
|
124
|
-
updateInput(target);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function onClickDocument (e: Event): void {
|
|
128
|
-
off(document.body, "click", onClickDocument);
|
|
129
|
-
const target = e.target as Element;
|
|
130
|
-
const menus = queryAll("menu.active");
|
|
131
|
-
for (let i = 0, n = menus.length; i < n; i++) menu(target, menus[i], e);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function onClickSnackbar (e: Event): void {
|
|
135
|
-
const target = e.currentTarget as Element;
|
|
136
|
-
removeClass(target, "active");
|
|
137
|
-
|
|
138
|
-
if (_timeoutSnackbar) clearTimeout(_timeoutSnackbar);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function onChangeFile (e: Event): void {
|
|
142
|
-
const target = e.currentTarget as HTMLInputElement;
|
|
143
|
-
updateFile(target);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function onChangeColor (e: Event): void {
|
|
147
|
-
const target = e.currentTarget as HTMLInputElement;
|
|
148
|
-
updateColor(target);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function onKeydownFile (e: KeyboardEvent): void {
|
|
152
|
-
const target = e.currentTarget as HTMLInputElement;
|
|
153
|
-
updateFile(target, e);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function onKeydownColor (e: KeyboardEvent): void {
|
|
157
|
-
const target = e.currentTarget as HTMLInputElement;
|
|
158
|
-
updateColor(target, e);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function onInputTextarea (e: Event): void {
|
|
162
|
-
const target = e.currentTarget as Element;
|
|
163
|
-
updateTextarea(target);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function onMutation (): void {
|
|
10
|
+
function onMutation() {
|
|
167
11
|
if (_timeoutMutation) clearTimeout(_timeoutMutation);
|
|
168
|
-
_timeoutMutation = setTimeout(() =>
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function updateFile (target: Element, e?: KeyboardEvent): void {
|
|
172
|
-
if (e && e.key === "Enter") {
|
|
173
|
-
const previousTarget = prev(target) as HTMLInputElement;
|
|
174
|
-
if (!hasType(previousTarget, "file")) return;
|
|
175
|
-
previousTarget.click(); return;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const currentTarget = target as HTMLInputElement;
|
|
179
|
-
const nextTarget = next(target) as HTMLInputElement;
|
|
180
|
-
if (!hasType(nextTarget, "text")) return;
|
|
181
|
-
nextTarget.value = currentTarget.files ? Array.from(currentTarget.files).map((x) => x.name).join(", ") : "";
|
|
182
|
-
nextTarget.readOnly = true;
|
|
183
|
-
on(nextTarget, "keydown", onKeydownFile, false);
|
|
184
|
-
updateInput(nextTarget);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function updateColor (target: Element, e?: KeyboardEvent): void {
|
|
188
|
-
if (e && e.key === "Enter") {
|
|
189
|
-
const previousTarget = prev(target) as HTMLInputElement;
|
|
190
|
-
if (!hasType(previousTarget, "color")) return;
|
|
191
|
-
previousTarget.click(); return;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const currentTarget = target as HTMLInputElement;
|
|
195
|
-
const nextTarget = next(target) as HTMLInputElement;
|
|
196
|
-
if (!hasType(nextTarget, "text")) return;
|
|
197
|
-
nextTarget.readOnly = true;
|
|
198
|
-
nextTarget.value = currentTarget.value;
|
|
199
|
-
on(nextTarget, "keydown", onKeydownColor, false);
|
|
200
|
-
updateInput(nextTarget);
|
|
12
|
+
_timeoutMutation = setTimeout(async () => await ui(), 180);
|
|
201
13
|
}
|
|
202
14
|
|
|
203
|
-
function
|
|
204
|
-
|
|
205
|
-
const currentTarget = parent(target) as HTMLElement;
|
|
206
|
-
parentTarget.removeAttribute("style");
|
|
207
|
-
if (hasClass(parentTarget, "min")) parentTarget.style.setProperty("---size", `${Math.max(target.scrollHeight, currentTarget.offsetHeight)}px`);
|
|
15
|
+
function onClickElement(e: Event) {
|
|
16
|
+
run(e.currentTarget as HTMLElement, null, null, e);
|
|
208
17
|
}
|
|
209
18
|
|
|
210
|
-
function
|
|
211
|
-
const parentTarget = parent(target) as HTMLElement;
|
|
212
|
-
const bar = query("span", parentTarget) as HTMLElement;
|
|
213
|
-
const inputs = queryAll("input", parentTarget) as NodeListOf<HTMLInputElement>;
|
|
214
|
-
if (!inputs.length || !bar) return;
|
|
215
|
-
|
|
216
|
-
const rootSize = parseInt(getComputedStyle(document.documentElement).getPropertyValue("--size")) || 16;
|
|
217
|
-
const thumb = hasClass(parentTarget, "max") ? 0 : 0.25 * rootSize * 100 / inputs[0].offsetWidth;
|
|
218
|
-
const percents: Array<number> = [];
|
|
219
|
-
const values: Array<number> = [];
|
|
220
|
-
for (let i = 0, n = inputs.length; i < n; i++) {
|
|
221
|
-
const min = parseFloat(inputs[i].min) || 0;
|
|
222
|
-
const max = parseFloat(inputs[i].max) || 100;
|
|
223
|
-
const value = parseFloat(inputs[i].value) || 0;
|
|
224
|
-
const percent = (value - min) * 100 / (max - min);
|
|
225
|
-
const fix = thumb / 2 - thumb * percent / 100;
|
|
226
|
-
percents.push(percent + fix);
|
|
227
|
-
values.push(value);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
let percent = percents[0];
|
|
231
|
-
let start = 0;
|
|
232
|
-
let end = 100 - start - percent;
|
|
233
|
-
let value1 = values[0];
|
|
234
|
-
let value2 = values[1] || 0;
|
|
235
|
-
if (inputs.length > 1) {
|
|
236
|
-
percent = Math.abs(percents[1] - percents[0]);
|
|
237
|
-
start = percents[1] > percents[0] ? percents[0] : percents[1];
|
|
238
|
-
end = 100 - start - percent;
|
|
239
|
-
|
|
240
|
-
if (value2 > value1) {
|
|
241
|
-
value1 = values[1] || 0;
|
|
242
|
-
value2 = values[0];
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
parentTarget.style.setProperty("---start", `${start}%`);
|
|
247
|
-
parentTarget.style.setProperty("---end", `${end}%`);
|
|
248
|
-
parentTarget.style.setProperty("---value1", `'${value1}'`);
|
|
249
|
-
parentTarget.style.setProperty("---value2", `'${value2}'`);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function updateAllRanges (e?: Event) {
|
|
253
|
-
if (e) {
|
|
254
|
-
const input = e.target as HTMLInputElement;
|
|
255
|
-
if (input.type === "range") { updateRange(input); return; }
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const ranges = queryAll(".slider > input[type=range]") as NodeListOf<HTMLInputElement>;
|
|
259
|
-
if (!ranges.length) off(globalThis, "input", updateAllRanges, false);
|
|
260
|
-
else on(globalThis, "input", updateAllRanges, false);
|
|
261
|
-
for (let i = 0, n = ranges.length; i < n; i++) updateRange(ranges[i]);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
async function open (from: Element, to: Element | null, options?: any, e?: Event): Promise<void> {
|
|
265
|
-
if (!to) {
|
|
266
|
-
to = query(from.getAttribute("data-ui"));
|
|
267
|
-
if (!to) return;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (hasTag(to, "dialog")) { await dialog(from, to); return; }
|
|
271
|
-
if (hasTag(to, "menu")) { menu(from, to, e); return; }
|
|
272
|
-
if (hasClass(to, "snackbar")) { snackbar(from, to, options as number); return; }
|
|
273
|
-
if (hasClass(to, "page")) { page(from, to); return; }
|
|
274
|
-
|
|
275
|
-
tab(from);
|
|
276
|
-
|
|
277
|
-
if (hasClass(to, "active")) { removeClass(to, "active"); return; }
|
|
278
|
-
|
|
279
|
-
addClass(to, "active");
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function tab (from: Element): void {
|
|
283
|
-
if (from.id && hasClass(from, "page")) from = query(`[data-ui="#${from.id}"]`) ?? from;
|
|
284
|
-
|
|
285
|
-
const container = parent(from);
|
|
286
|
-
if (!hasClass(container, "tabs")) return;
|
|
287
|
-
const tabs = queryAll("a", container);
|
|
288
|
-
for (let i = 0, n = tabs.length; i < n; i++) removeClass(tabs[i], "active");
|
|
289
|
-
addClass(from, "active");
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function page (from: Element, to: Element): void {
|
|
293
|
-
tab(from);
|
|
294
|
-
const container = parent(to);
|
|
295
|
-
if (container) {
|
|
296
|
-
for (let i = 0, n = container.children.length; i < n; i++) {
|
|
297
|
-
if (hasClass(container.children[i], "page")) removeClass(container.children[i], "active");
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
addClass(to, "active");
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function menu (from: Element, to: Element, e?: Event) {
|
|
304
|
-
if (_timeoutMenu) clearTimeout(_timeoutMenu);
|
|
305
|
-
|
|
306
|
-
_timeoutMenu = setTimeout(() => {
|
|
307
|
-
on(document.body, "click", onClickDocument);
|
|
308
|
-
const activeElement = document.activeElement as HTMLElement;
|
|
309
|
-
if (!hasTag(activeElement, "input")) activeElement?.blur();
|
|
310
|
-
tab(from);
|
|
311
|
-
|
|
312
|
-
const isActive = hasClass(to, "active");
|
|
313
|
-
const isEvent = !!(e?.target === from);
|
|
314
|
-
const isChild = !!from.closest("menu");
|
|
315
|
-
|
|
316
|
-
if ((!isActive && isChild) || (isActive && isEvent)) {
|
|
317
|
-
removeClass(to, "active");
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
const menus = queryAll("menu.active");
|
|
322
|
-
for (let i = 0, n = menus.length; i < n; i++) removeClass(menus[i], "active");
|
|
323
|
-
addClass(to, "active");
|
|
324
|
-
}, 90);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
async function dialog (from: Element, to: Element): Promise<void> {
|
|
328
|
-
(document.activeElement as HTMLElement)?.blur();
|
|
329
|
-
tab(from);
|
|
330
|
-
|
|
331
|
-
let overlay = prev(to) as HTMLElement;
|
|
332
|
-
const target = to as HTMLDialogElement;
|
|
333
|
-
const isActive = hasClass(to, "active") || target.open;
|
|
334
|
-
const isModal = hasClass(to, "modal");
|
|
335
|
-
const container = parent(to);
|
|
336
|
-
const isNav = hasTag(container, "nav");
|
|
337
|
-
|
|
338
|
-
if (!hasClass(overlay, "overlay")) {
|
|
339
|
-
overlay = create({ class: "overlay" });
|
|
340
|
-
insertBefore(overlay, to);
|
|
341
|
-
await wait(90);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
overlay.onclick = () => {
|
|
345
|
-
if (isModal) return;
|
|
346
|
-
|
|
347
|
-
removeClass(from, "active");
|
|
348
|
-
removeClass(to, "active");
|
|
349
|
-
removeClass(overlay, "active");
|
|
350
|
-
target.close();
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
if (isNav) {
|
|
354
|
-
const elements = queryAll("dialog, a, .overlay", container);
|
|
355
|
-
for (let i = 0, n = elements.length; i < n; i++) {
|
|
356
|
-
const element = elements[i] as any;
|
|
357
|
-
removeClass(element, "active");
|
|
358
|
-
if (element.open) element.close();
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (isActive) {
|
|
363
|
-
removeClass(from, "active");
|
|
364
|
-
removeClass(overlay, "active");
|
|
365
|
-
removeClass(to, "active");
|
|
366
|
-
target.close();
|
|
367
|
-
} else {
|
|
368
|
-
if (!hasTag(from, "button") && !hasClass(from, "button") && !hasClass(from, "chip")) addClass(from, "active");
|
|
369
|
-
addClass(overlay, "active");
|
|
370
|
-
addClass(to, "active");
|
|
371
|
-
|
|
372
|
-
if (isModal) target.showModal();
|
|
373
|
-
else target.show();
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function snackbar (from: Element, to: Element, milliseconds?: number): void {
|
|
378
|
-
(document.activeElement as HTMLElement)?.blur();
|
|
379
|
-
tab(from);
|
|
380
|
-
|
|
381
|
-
const elements = queryAll(".snackbar.active");
|
|
382
|
-
for (let i = 0, n = elements.length; i < n; i++) removeClass(elements[i], "active");
|
|
383
|
-
addClass(to, "active");
|
|
384
|
-
on(to, "click", onClickSnackbar);
|
|
385
|
-
|
|
386
|
-
if (_timeoutSnackbar) clearTimeout(_timeoutSnackbar);
|
|
387
|
-
|
|
388
|
-
if (milliseconds === -1) return;
|
|
389
|
-
|
|
390
|
-
_timeoutSnackbar = setTimeout(() => {
|
|
391
|
-
removeClass(to, "active");
|
|
392
|
-
}, milliseconds ?? 6000);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
function lastTheme (): IBeerCssTheme {
|
|
396
|
-
if (_lastTheme.light && _lastTheme.dark) return _lastTheme;
|
|
397
|
-
|
|
398
|
-
const light = document.createElement("body");
|
|
399
|
-
light.className = "light";
|
|
400
|
-
document.body.appendChild(light);
|
|
401
|
-
|
|
402
|
-
const dark = document.createElement("body");
|
|
403
|
-
dark.className = "dark";
|
|
404
|
-
document.body.appendChild(dark);
|
|
405
|
-
|
|
406
|
-
const fromLight = getComputedStyle(light);
|
|
407
|
-
const fromDark = getComputedStyle(dark);
|
|
408
|
-
const variables = ["--primary", "--on-primary", "--primary-container", "--on-primary-container", "--secondary", "--on-secondary", "--secondary-container", "--on-secondary-container", "--tertiary", "--on-tertiary", "--tertiary-container", "--on-tertiary-container", "--error", "--on-error", "--error-container", "--on-error-container", "--background", "--on-background", "--surface", "--on-surface", "--surface-variant", "--on-surface-variant", "--outline", "--outline-variant", "--shadow", "--scrim", "--inverse-surface", "--inverse-on-surface", "--inverse-primary", "--surface-dim", "--surface-bright", "--surface-container-lowest", "--surface-container-low", "--surface-container", "--surface-container-high", "--surface-container-highest"];
|
|
409
|
-
for (let i = 0, n = variables.length; i < n; i++) {
|
|
410
|
-
_lastTheme.light += variables[i] + ":" + fromLight.getPropertyValue(variables[i]) + ";";
|
|
411
|
-
_lastTheme.dark += variables[i] + ":" + fromDark.getPropertyValue(variables[i]) + ";";
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
document.body.removeChild(light);
|
|
415
|
-
document.body.removeChild(dark);
|
|
416
|
-
return _lastTheme;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
function theme (source?: IBeerCssTheme | any): IBeerCssTheme | Promise<IBeerCssTheme> {
|
|
420
|
-
if (!source || !(globalThis as any).materialDynamicColors) return lastTheme();
|
|
421
|
-
|
|
422
|
-
const mode = /dark/i.test(document.body.className) ? "dark" : "light";
|
|
423
|
-
if (source.light && source.dark) {
|
|
424
|
-
_lastTheme.light = source.light;
|
|
425
|
-
_lastTheme.dark = source.dark;
|
|
426
|
-
document.body.setAttribute("style", source[mode]);
|
|
427
|
-
return source;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
return (globalThis as any).materialDynamicColors(source).then((theme: IBeerCssTheme) => {
|
|
431
|
-
const toCss = (data: any) => {
|
|
432
|
-
let style = "";
|
|
433
|
-
for (let i = 0, keys = Object.keys(data), n = keys.length; i < n; i++) {
|
|
434
|
-
const key = keys[i];
|
|
435
|
-
const value = data[key] as string;
|
|
436
|
-
const kebabCase = key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
|
|
437
|
-
style += "--" + kebabCase + ":" + value + ";";
|
|
438
|
-
}
|
|
439
|
-
return style;
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
_lastTheme.light = toCss(theme.light);
|
|
443
|
-
_lastTheme.dark = toCss(theme.dark);
|
|
444
|
-
document.body.setAttribute("style", _lastTheme[mode]);
|
|
445
|
-
return _lastTheme;
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
function mode (value: string): string {
|
|
450
|
-
if (!value) return /dark/i.test(document.body.className) ? "dark" : "light";
|
|
451
|
-
document.body.classList.remove("light", "dark");
|
|
452
|
-
document.body.classList.add(value);
|
|
453
|
-
const lastThemeStyle = value === "light" ? _lastTheme.light : _lastTheme.dark;
|
|
454
|
-
if ((globalThis as any).materialDynamicColors) document.body.setAttribute("style", lastThemeStyle);
|
|
455
|
-
return value;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
function setup () {
|
|
19
|
+
function setup() {
|
|
459
20
|
if (_mutation) return;
|
|
460
21
|
_mutation = new MutationObserver(onMutation);
|
|
461
22
|
_mutation.observe(document.body, { childList: true, subtree: true });
|
|
462
23
|
onMutation();
|
|
463
24
|
}
|
|
464
25
|
|
|
465
|
-
function
|
|
26
|
+
function updateAllDataUis() {
|
|
27
|
+
const elements = queryAll("[data-ui]");
|
|
28
|
+
for (let i = 0, n = elements.length; i < n; i++) on(elements[i], "click", onClickElement);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ui(selector?: string | Element, options?: string | number | IBeerCssTheme): string | IBeerCssTheme | Promise<IBeerCssTheme> | undefined {
|
|
466
32
|
if (selector) {
|
|
467
33
|
if (selector === "setup") { setup(); return; }
|
|
468
34
|
if (selector === "guid") return guid();
|
|
469
|
-
if (selector === "mode") return
|
|
470
|
-
if (selector === "theme") return
|
|
35
|
+
if (selector === "mode") return updateMode(options as string);
|
|
36
|
+
if (selector === "theme") return updateTheme(options);
|
|
471
37
|
|
|
472
38
|
const to = query(selector);
|
|
473
39
|
if (!to) return;
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const elements = queryAll("[data-ui]");
|
|
478
|
-
for (let i = 0, n = elements.length; i < n; i++) on(elements[i], "click", onClickElement);
|
|
479
|
-
|
|
480
|
-
const labels = queryAll(".field > label");
|
|
481
|
-
for (let i = 0, n = labels.length; i < n; i++) on(labels[i], "click", onClickLabel);
|
|
482
|
-
|
|
483
|
-
const inputs = queryAll(".field > input:not([type=file], [type=color], [type=range]), .field > select, .field > textarea");
|
|
484
|
-
for (let i = 0, n = inputs.length; i < n; i++) {
|
|
485
|
-
const input = inputs[i];
|
|
486
|
-
on(input, "focus", onFocusInput);
|
|
487
|
-
on(input, "blur", onBlurInput);
|
|
488
|
-
updateInput(input);
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
const files = queryAll(".field > input[type=file]");
|
|
492
|
-
for (let i = 0, n = files.length; i < n; i++) {
|
|
493
|
-
const file = files[i];
|
|
494
|
-
on(file, "change", onChangeFile);
|
|
495
|
-
updateFile(file);
|
|
40
|
+
run(to, to, options);
|
|
496
41
|
}
|
|
497
42
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
updateColor(color);
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
const textareas = queryAll(".field.textarea > textarea");
|
|
506
|
-
for (let i = 0, n = textareas.length; i < n; i++) {
|
|
507
|
-
const textarea = textareas[i];
|
|
508
|
-
on(textarea, "input", onInputTextarea);
|
|
509
|
-
updateTextarea(textarea);
|
|
510
|
-
}
|
|
43
|
+
updateAllDataUis();
|
|
44
|
+
updateAllFields();
|
|
45
|
+
updateAllSliders();
|
|
46
|
+
}
|
|
511
47
|
|
|
512
|
-
|
|
48
|
+
function start() {
|
|
49
|
+
const context = (globalThis as any);
|
|
50
|
+
const body = context?.document?.body;
|
|
51
|
+
|
|
52
|
+
if (body && !body.classList.contains("dark") && !body.classList.contains("light")) updateMode("auto");
|
|
53
|
+
|
|
54
|
+
on(context, "load", setup, false);
|
|
55
|
+
context.beercss = ui;
|
|
56
|
+
context.ui = ui;
|
|
513
57
|
}
|
|
514
58
|
|
|
515
|
-
|
|
516
|
-
(globalThis as any).beercss = ui;
|
|
517
|
-
(globalThis as any).ui = ui;
|
|
59
|
+
start();
|
|
518
60
|
export default ui;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { addClass, next, prev, hasTag, insertBefore, wait, create, hasClass, removeClass, on, off, queryAllDataUi, isTouchable, blurActiveElement } from "../utils";
|
|
2
|
+
|
|
3
|
+
const _dialogs: Array<HTMLDialogElement> = [];
|
|
4
|
+
|
|
5
|
+
function onKeydownDialog(e: KeyboardEvent) {
|
|
6
|
+
if (e.key === "Escape") {
|
|
7
|
+
const dialog = e.currentTarget as HTMLDialogElement;
|
|
8
|
+
updateDialog(dialog, dialog);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function closeDialog(dialog: HTMLDialogElement, overlay: Element) {
|
|
13
|
+
removeClass(queryAllDataUi(dialog.id), "active");
|
|
14
|
+
removeClass(dialog, "active");
|
|
15
|
+
removeClass(overlay, "active");
|
|
16
|
+
|
|
17
|
+
dialog.close();
|
|
18
|
+
_dialogs.pop();
|
|
19
|
+
|
|
20
|
+
const previousDialog = _dialogs[_dialogs.length - 1];
|
|
21
|
+
if (previousDialog) previousDialog.focus();
|
|
22
|
+
else if (isTouchable()) document.body.classList.remove("no-scroll");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function openDialog(dialog: HTMLDialogElement, overlay: Element, isModal: boolean, from: Element) {
|
|
26
|
+
if (!hasTag(from, "button") && !hasClass(from, "button") && !hasClass(from, "chip")) addClass(from, "active");
|
|
27
|
+
addClass(overlay, "active");
|
|
28
|
+
addClass(dialog, "active");
|
|
29
|
+
|
|
30
|
+
if (isModal) dialog.showModal();
|
|
31
|
+
else dialog.show();
|
|
32
|
+
|
|
33
|
+
await wait(90);
|
|
34
|
+
|
|
35
|
+
if (!isModal) on(dialog, "keydown", onKeydownDialog, false);
|
|
36
|
+
|
|
37
|
+
_dialogs.push(dialog);
|
|
38
|
+
dialog.focus();
|
|
39
|
+
|
|
40
|
+
if (isTouchable()) document.body.classList.add("no-scroll");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function onClickOverlay(e: Event) {
|
|
44
|
+
const overlay = e.currentTarget as Element;
|
|
45
|
+
const dialog = next(overlay) as HTMLDialogElement;
|
|
46
|
+
if (hasTag(dialog, "dialog")) closeDialog(dialog, overlay);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function updateDialog(from: Element, dialog: HTMLDialogElement): Promise<void> {
|
|
50
|
+
blurActiveElement();
|
|
51
|
+
|
|
52
|
+
let overlay = prev(dialog) as HTMLElement;
|
|
53
|
+
const isActive = hasClass(dialog, "active") || dialog.open;
|
|
54
|
+
const isModal = hasClass(dialog, "modal");
|
|
55
|
+
|
|
56
|
+
if (!isModal) off(dialog, "keydown", onKeydownDialog, false);
|
|
57
|
+
|
|
58
|
+
if (!hasClass(overlay, "overlay")) {
|
|
59
|
+
overlay = create({ class: "overlay" });
|
|
60
|
+
insertBefore(overlay, dialog);
|
|
61
|
+
await wait(90);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!isModal) on(overlay, "click", onClickOverlay, false);
|
|
65
|
+
|
|
66
|
+
if (isActive) closeDialog(dialog, overlay);
|
|
67
|
+
else openDialog(dialog, overlay, isModal, from);
|
|
68
|
+
}
|
|
@@ -129,7 +129,7 @@ input::-webkit-date-and-time-value {
|
|
|
129
129
|
|
|
130
130
|
:is(input, select, textarea):-webkit-autofill {
|
|
131
131
|
-webkit-background-clip: text;
|
|
132
|
-
-webkit-text-fill-color:
|
|
132
|
+
-webkit-text-fill-color: var(--on-surface);
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
.field > :is(input, textarea, select):focus {
|
|
@@ -141,6 +141,7 @@ input::-webkit-date-and-time-value {
|
|
|
141
141
|
overflow: hidden;
|
|
142
142
|
position: absolute;
|
|
143
143
|
inset: 0;
|
|
144
|
+
max-block-size: 12rem;
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
input[type=file],
|