@taybart/corvid 0.2.0 → 0.2.2
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/dist/dom.d.ts +82 -5
- package/dist/dom.js +188 -4
- package/dist/index.js +198 -13
- package/dist/ls.js +179 -3
- package/dist/qr.js +179 -3
- package/dist/style.d.ts +36 -1
- package/dist/style.js +99 -12
- package/dist/style.test.d.ts +1 -0
- package/package.json +1 -1
package/dist/dom.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as style from './style';
|
|
1
2
|
import { logger } from './utils';
|
|
2
3
|
/****************
|
|
3
4
|
* DOM *
|
|
@@ -17,8 +18,14 @@ export declare function onKey(key: string, cb: (ev: {
|
|
|
17
18
|
shift: boolean;
|
|
18
19
|
}) => void, verbose?: boolean): () => void;
|
|
19
20
|
export declare function els(query: string, verbose?: boolean): el[];
|
|
21
|
+
/**
|
|
22
|
+
* Define a custom element. Defining the same name with the same class again is a
|
|
23
|
+
* no-op rather than a `NotSupportedError`, so a double import or an HMR reload
|
|
24
|
+
* does not blow up; a *different* class on a taken name is still an error.
|
|
25
|
+
*/
|
|
26
|
+
export declare function registerElement(name: string, ctor: CustomElementConstructor): void;
|
|
20
27
|
/*** element ***/
|
|
21
|
-
type elOpts = {
|
|
28
|
+
export type elOpts = {
|
|
22
29
|
element?: HTMLElement;
|
|
23
30
|
query?: string;
|
|
24
31
|
tag?: string;
|
|
@@ -40,7 +47,7 @@ export declare class el {
|
|
|
40
47
|
constructor(opts: HTMLElement | string | elOpts, verbose?: boolean);
|
|
41
48
|
static query(query: string, verbose?: boolean): el;
|
|
42
49
|
/*** dom manipulation ***/
|
|
43
|
-
value(update?: string): string |
|
|
50
|
+
value(update?: string): string | this;
|
|
44
51
|
parent(parent: HTMLElement | el): this;
|
|
45
52
|
append(ch: HTMLElement | el | string): this;
|
|
46
53
|
appendChild(ch: HTMLElement | el): this;
|
|
@@ -51,22 +58,89 @@ export declare class el {
|
|
|
51
58
|
content(content: any, { text }?: {
|
|
52
59
|
text?: boolean;
|
|
53
60
|
}): this;
|
|
54
|
-
html(content: string):
|
|
61
|
+
html(content: string): this;
|
|
55
62
|
src(url: string): this;
|
|
56
63
|
attrs(attrs: Object): this;
|
|
57
64
|
attr(key: string, val: string): this;
|
|
58
65
|
removeAttr(key: string): this;
|
|
59
66
|
/*** Style ***/
|
|
60
|
-
style(update: Object | string, stringify?: boolean): this
|
|
67
|
+
style(update: Object | string, stringify?: boolean): this;
|
|
61
68
|
hasClass(className: string): boolean;
|
|
62
69
|
addClass(className: string | string[]): this;
|
|
63
70
|
removeClass(className: string | string[]): this;
|
|
64
|
-
/*** Templates ***/
|
|
65
71
|
/*** Events ***/
|
|
66
72
|
on(event: string, cb: (ev: Event) => void, options?: AddEventListenerOptions | boolean): this;
|
|
67
73
|
listen(event: string, cb: (ev: Event) => void, options?: AddEventListenerOptions | boolean): this;
|
|
68
74
|
removeListeners(event: string): this;
|
|
69
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Create an element and return the node itself, not an `el` wrapper. Takes the
|
|
78
|
+
* same options as `el`, so a custom element comes back ready to talk to:
|
|
79
|
+
*
|
|
80
|
+
* const form = create({ tag: 'x-search-form', parent: '#query-form' })
|
|
81
|
+
* form.onSubmit(...) // its own methods, no `.el` hop
|
|
82
|
+
*
|
|
83
|
+
* Wrap it later with `new el(node)` if you want the chainable helpers.
|
|
84
|
+
*/
|
|
85
|
+
export declare function create<T extends HTMLElement = HTMLElement>(opts: elOpts, verbose?: boolean): T;
|
|
86
|
+
/*** component ***/
|
|
87
|
+
/**
|
|
88
|
+
* Base class for custom elements. It handles registration, the component's
|
|
89
|
+
* stylesheet, and a mount hook
|
|
90
|
+
* class SearchForm extends component {
|
|
91
|
+
* static tag = 'x-search-form'
|
|
92
|
+
* static styles = { input: { border: 'none' } }
|
|
93
|
+
* input = create({ tag: 'input' })
|
|
94
|
+
* mount() {
|
|
95
|
+
* this.input.addEventListener('keydown', (e) => ...)
|
|
96
|
+
* this.append(this.input)
|
|
97
|
+
* }
|
|
98
|
+
* }
|
|
99
|
+
* SearchForm.register()
|
|
100
|
+
*/
|
|
101
|
+
export declare class component extends HTMLElement {
|
|
102
|
+
#private;
|
|
103
|
+
/** the name to register as; must contain a hyphen */
|
|
104
|
+
static tag: string;
|
|
105
|
+
/**
|
|
106
|
+
* Injected once at `register()`, scoped to the tag. Written *relative* to the
|
|
107
|
+
* component — no tag selector of its own — so it always matches whatever name
|
|
108
|
+
* the class actually registered under.
|
|
109
|
+
*/
|
|
110
|
+
static styles: style.declarations | null;
|
|
111
|
+
/**
|
|
112
|
+
* Inject this component's styles and define it. Idempotent, so calling it
|
|
113
|
+
* twice (or after an HMR reload) is harmless.
|
|
114
|
+
* @param tag - overrides `static tag`
|
|
115
|
+
*/
|
|
116
|
+
static register(tag?: string): void;
|
|
117
|
+
/**
|
|
118
|
+
* Called once, the first time the element is connected. Build the subtree and
|
|
119
|
+
* wire listeners here — a custom element cannot give itself children before
|
|
120
|
+
* it is connected, and `connectedCallback` runs again on every re-insertion.
|
|
121
|
+
*/
|
|
122
|
+
mount(): void;
|
|
123
|
+
/**
|
|
124
|
+
* Called every time the element is disconnected. Listeners on this element
|
|
125
|
+
* and on children it owns go away with it; undo document/window listeners
|
|
126
|
+
* here, using the removers `on()` and `onKey()` hand back.
|
|
127
|
+
*/
|
|
128
|
+
unmount(): void;
|
|
129
|
+
/**
|
|
130
|
+
* Called for every change to an attribute named in `static observedAttributes`,
|
|
131
|
+
* and never before `mount()` — changes that arrive earlier (anything set at
|
|
132
|
+
* creation or parse time, which the platform reports *before*
|
|
133
|
+
* `connectedCallback`) are held and delivered in order right after mount.
|
|
134
|
+
*
|
|
135
|
+
* Attributes are strings. For structured data use a property with a setter
|
|
136
|
+
* that re-renders; an object put through `setAttribute` becomes
|
|
137
|
+
* "[object Object]".
|
|
138
|
+
*/
|
|
139
|
+
onAttr(_name: string, _value: string | null, _prev: string | null): void;
|
|
140
|
+
connectedCallback(): void;
|
|
141
|
+
disconnectedCallback(): void;
|
|
142
|
+
attributeChangedCallback(name: string, prev: string | null, value: string | null): void;
|
|
143
|
+
}
|
|
70
144
|
/**
|
|
71
145
|
* Get a template from a string
|
|
72
146
|
* https://stackoverflow.com/a/41015840
|
|
@@ -78,6 +152,9 @@ export declare function interpolate(str: string, params: Object): string;
|
|
|
78
152
|
declare const _default: {
|
|
79
153
|
el: typeof el;
|
|
80
154
|
els: typeof els;
|
|
155
|
+
create: typeof create;
|
|
156
|
+
component: typeof component;
|
|
157
|
+
registerElement: typeof registerElement;
|
|
81
158
|
ready: typeof ready;
|
|
82
159
|
on: typeof on;
|
|
83
160
|
onKey: typeof onKey;
|
package/dist/dom.js
CHANGED
|
@@ -1,11 +1,102 @@
|
|
|
1
|
-
function
|
|
1
|
+
function toKebab(str) {
|
|
2
2
|
return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, ofs)=>(ofs ? '-' : '') + s.toLowerCase());
|
|
3
3
|
}
|
|
4
4
|
function render(style) {
|
|
5
5
|
let s = '';
|
|
6
|
-
Object.entries(style).forEach(([k, v])=>s += `${
|
|
6
|
+
Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
|
|
7
7
|
return s;
|
|
8
8
|
}
|
|
9
|
+
function splitSelectors(selector) {
|
|
10
|
+
const out = [];
|
|
11
|
+
let depth = 0;
|
|
12
|
+
let quote = '';
|
|
13
|
+
let current = '';
|
|
14
|
+
for (const ch of selector){
|
|
15
|
+
if (quote) {
|
|
16
|
+
if (ch === quote) quote = '';
|
|
17
|
+
} else if ('"' === ch || "'" === ch) quote = ch;
|
|
18
|
+
else if ('(' === ch || '[' === ch) depth++;
|
|
19
|
+
else if (')' === ch || ']' === ch) depth--;
|
|
20
|
+
else if (',' === ch && 0 === depth) {
|
|
21
|
+
if (current.trim()) out.push(current.trim());
|
|
22
|
+
current = '';
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
current += ch;
|
|
26
|
+
}
|
|
27
|
+
if (current.trim()) out.push(current.trim());
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
function resolve(parents, selector) {
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function compile(parents, decls, indent = '') {
|
|
36
|
+
const blocks = [];
|
|
37
|
+
const props = [];
|
|
38
|
+
const nested = [];
|
|
39
|
+
for (const [k, v] of Object.entries(decls))if (null !== v && 'object' == typeof v) nested.push([
|
|
40
|
+
k,
|
|
41
|
+
v
|
|
42
|
+
]);
|
|
43
|
+
else props.push(`${indent} ${toKebab(k)}: ${v};`);
|
|
44
|
+
if (props.length) blocks.push(`${indent}${parents.join(', ')} {\n${props.join('\n')}\n${indent}}`);
|
|
45
|
+
for (const [selector, block] of nested){
|
|
46
|
+
if (selector.startsWith('@')) {
|
|
47
|
+
const inner = selector.startsWith('@keyframes') ? Object.entries(block).flatMap(([step, d])=>null !== d && 'object' == typeof d ? compile([
|
|
48
|
+
step
|
|
49
|
+
], d, `${indent} `) : []) : compile(parents, block, `${indent} `);
|
|
50
|
+
if (inner.length) blocks.push(`${indent}${selector} {\n${inner.join('\n')}\n${indent}}`);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
blocks.push(...compile(resolve(parents, selector), block, indent));
|
|
54
|
+
}
|
|
55
|
+
return blocks;
|
|
56
|
+
}
|
|
57
|
+
function css(selector, style) {
|
|
58
|
+
return compile(splitSelectors(selector), style).join('\n');
|
|
59
|
+
}
|
|
60
|
+
function registry() {
|
|
61
|
+
const doc = document;
|
|
62
|
+
if (!doc.__corvidSheets) doc.__corvidSheets = new Map();
|
|
63
|
+
return doc.__corvidSheets;
|
|
64
|
+
}
|
|
65
|
+
function adoptable() {
|
|
66
|
+
return 'undefined' != typeof CSSStyleSheet && 'replaceSync' in CSSStyleSheet.prototype && 'undefined' != typeof Document && 'adoptedStyleSheets' in Document.prototype;
|
|
67
|
+
}
|
|
68
|
+
function styleTag(key) {
|
|
69
|
+
const tagged = Array.from(document.head.querySelectorAll('style[data-corvid]'));
|
|
70
|
+
for (const node of tagged)if (node.dataset.corvid === key) return node;
|
|
71
|
+
const node = document.createElement('style');
|
|
72
|
+
node.dataset.corvid = key;
|
|
73
|
+
document.head.appendChild(node);
|
|
74
|
+
return node;
|
|
75
|
+
}
|
|
76
|
+
function inject(selector, style, { key = selector } = {}) {
|
|
77
|
+
const rules = css(selector, style);
|
|
78
|
+
const sheets = registry();
|
|
79
|
+
const existing = sheets.get(key);
|
|
80
|
+
if (existing) {
|
|
81
|
+
if ('replaceSync' in existing) existing.replaceSync(rules);
|
|
82
|
+
else existing.textContent = rules;
|
|
83
|
+
return rules;
|
|
84
|
+
}
|
|
85
|
+
if (adoptable()) {
|
|
86
|
+
const sheet = new CSSStyleSheet();
|
|
87
|
+
sheet.replaceSync(rules);
|
|
88
|
+
document.adoptedStyleSheets = [
|
|
89
|
+
...document.adoptedStyleSheets,
|
|
90
|
+
sheet
|
|
91
|
+
];
|
|
92
|
+
sheets.set(key, sheet);
|
|
93
|
+
return rules;
|
|
94
|
+
}
|
|
95
|
+
const node = styleTag(key);
|
|
96
|
+
node.textContent = rules;
|
|
97
|
+
sheets.set(key, node);
|
|
98
|
+
return rules;
|
|
99
|
+
}
|
|
9
100
|
function _define_property(obj, key, value) {
|
|
10
101
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
11
102
|
value: value,
|
|
@@ -61,6 +152,37 @@ class logger {
|
|
|
61
152
|
});
|
|
62
153
|
}
|
|
63
154
|
}
|
|
155
|
+
function _check_private_redeclaration(obj, privateCollection) {
|
|
156
|
+
if (privateCollection.has(obj)) throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
157
|
+
}
|
|
158
|
+
function _class_apply_descriptor_get(receiver, descriptor) {
|
|
159
|
+
if (descriptor.get) return descriptor.get.call(receiver);
|
|
160
|
+
return descriptor.value;
|
|
161
|
+
}
|
|
162
|
+
function _class_apply_descriptor_set(receiver, descriptor, value) {
|
|
163
|
+
if (descriptor.set) descriptor.set.call(receiver, value);
|
|
164
|
+
else {
|
|
165
|
+
if (!descriptor.writable) throw new TypeError("attempted to set read only private field");
|
|
166
|
+
descriptor.value = value;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function _class_extract_field_descriptor(receiver, privateMap, action) {
|
|
170
|
+
if (!privateMap.has(receiver)) throw new TypeError("attempted to " + action + " private field on non-instance");
|
|
171
|
+
return privateMap.get(receiver);
|
|
172
|
+
}
|
|
173
|
+
function _class_private_field_get(receiver, privateMap) {
|
|
174
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
|
|
175
|
+
return _class_apply_descriptor_get(receiver, descriptor);
|
|
176
|
+
}
|
|
177
|
+
function _class_private_field_init(obj, privateMap, value) {
|
|
178
|
+
_check_private_redeclaration(obj, privateMap);
|
|
179
|
+
privateMap.set(obj, value);
|
|
180
|
+
}
|
|
181
|
+
function _class_private_field_set(receiver, privateMap, value) {
|
|
182
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
|
|
183
|
+
_class_apply_descriptor_set(receiver, descriptor, value);
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
64
186
|
function dom_define_property(obj, key, value) {
|
|
65
187
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
66
188
|
value: value,
|
|
@@ -110,6 +232,14 @@ function onKey(key, cb, verbose = false) {
|
|
|
110
232
|
function els(query, verbose = false) {
|
|
111
233
|
return Array.from(document.querySelectorAll(query)).map((n)=>new dom_el(n, verbose));
|
|
112
234
|
}
|
|
235
|
+
function registerElement(name, ctor) {
|
|
236
|
+
const existing = customElements.get(name);
|
|
237
|
+
if (existing) {
|
|
238
|
+
if (existing !== ctor) throw new Error(`custom element ${name} is already registered by ${existing.name}`);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
customElements.define(name, ctor);
|
|
242
|
+
}
|
|
113
243
|
class dom_el {
|
|
114
244
|
static query(query, verbose = false) {
|
|
115
245
|
return new dom_el(query, verbose);
|
|
@@ -168,6 +298,7 @@ class dom_el {
|
|
|
168
298
|
html(content) {
|
|
169
299
|
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
170
300
|
this.el.innerHTML = content;
|
|
301
|
+
return this;
|
|
171
302
|
}
|
|
172
303
|
src(url) {
|
|
173
304
|
if (this.el && 'src' in this.el) this.el.src = url;
|
|
@@ -194,7 +325,7 @@ class dom_el {
|
|
|
194
325
|
else if ('object' == typeof update) {
|
|
195
326
|
if (!stringify) {
|
|
196
327
|
for (const [k, v] of Object.entries(update))this.el.style[k] = v;
|
|
197
|
-
return;
|
|
328
|
+
return this;
|
|
198
329
|
}
|
|
199
330
|
const s = render(update);
|
|
200
331
|
this.log.debug(`set style: ${this.el.style} -> ${s}`);
|
|
@@ -297,6 +428,56 @@ class dom_el {
|
|
|
297
428
|
}
|
|
298
429
|
}
|
|
299
430
|
}
|
|
431
|
+
function create(opts, verbose = false) {
|
|
432
|
+
const node = new dom_el(opts, verbose).el;
|
|
433
|
+
if (!node) throw new Error(`could not create element: ${opts.tag ?? opts.query ?? '?'}`);
|
|
434
|
+
return node;
|
|
435
|
+
}
|
|
436
|
+
var _mounted = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
|
|
437
|
+
class component extends HTMLElement {
|
|
438
|
+
static register(tag) {
|
|
439
|
+
const name = tag ?? this.tag;
|
|
440
|
+
if (!name) throw new Error(`${this.name}: nothing to register as, set \`static tag = 'x-...'\``);
|
|
441
|
+
if (!name.includes('-')) throw new Error(`${this.name}: '${name}' is not a valid custom element name, it needs a hyphen`);
|
|
442
|
+
if (this.styles) inject(name, this.styles);
|
|
443
|
+
registerElement(name, this);
|
|
444
|
+
}
|
|
445
|
+
mount() {}
|
|
446
|
+
unmount() {}
|
|
447
|
+
onAttr(_name, _value, _prev) {}
|
|
448
|
+
connectedCallback() {
|
|
449
|
+
if (!_class_private_field_get(this, _mounted)) {
|
|
450
|
+
_class_private_field_set(this, _mounted, true);
|
|
451
|
+
this.mount();
|
|
452
|
+
const queued = _class_private_field_get(this, _pendingAttrs);
|
|
453
|
+
_class_private_field_set(this, _pendingAttrs, []);
|
|
454
|
+
for (const [name, value, prev] of queued)this.onAttr(name, value, prev);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
disconnectedCallback() {
|
|
458
|
+
this.unmount();
|
|
459
|
+
}
|
|
460
|
+
attributeChangedCallback(name, prev, value) {
|
|
461
|
+
if (prev === value) return;
|
|
462
|
+
if (!_class_private_field_get(this, _mounted)) return void _class_private_field_get(this, _pendingAttrs).push([
|
|
463
|
+
name,
|
|
464
|
+
value,
|
|
465
|
+
prev
|
|
466
|
+
]);
|
|
467
|
+
this.onAttr(name, value, prev);
|
|
468
|
+
}
|
|
469
|
+
constructor(...args){
|
|
470
|
+
super(...args), _class_private_field_init(this, _mounted, {
|
|
471
|
+
writable: true,
|
|
472
|
+
value: false
|
|
473
|
+
}), _class_private_field_init(this, _pendingAttrs, {
|
|
474
|
+
writable: true,
|
|
475
|
+
value: []
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
dom_define_property(component, "tag", '');
|
|
480
|
+
dom_define_property(component, "styles", null);
|
|
300
481
|
function interpolate(str, params) {
|
|
301
482
|
let names = Object.keys(params).map((k)=>`_${k}`);
|
|
302
483
|
let vals = Object.values(params);
|
|
@@ -305,8 +486,11 @@ function interpolate(str, params) {
|
|
|
305
486
|
const dom = {
|
|
306
487
|
el: dom_el,
|
|
307
488
|
els,
|
|
489
|
+
create,
|
|
490
|
+
component,
|
|
491
|
+
registerElement,
|
|
308
492
|
ready,
|
|
309
493
|
on,
|
|
310
494
|
onKey
|
|
311
495
|
};
|
|
312
|
-
export { dom as default, dom_el as el, els, interpolate, on, onBlur, onFocus, onKey, ready };
|
|
496
|
+
export { component, create, dom as default, dom_el as el, els, interpolate, on, onBlur, onFocus, onKey, ready, registerElement };
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,9 @@ __webpack_require__.d(strings_namespaceObject, {
|
|
|
29
29
|
var style_namespaceObject = {};
|
|
30
30
|
__webpack_require__.r(style_namespaceObject);
|
|
31
31
|
__webpack_require__.d(style_namespaceObject, {
|
|
32
|
+
css: ()=>css,
|
|
32
33
|
cssVar: ()=>cssVar,
|
|
34
|
+
eject: ()=>eject,
|
|
33
35
|
gradient: ()=>gradient,
|
|
34
36
|
handleThemeSwitch: ()=>handleThemeSwitch,
|
|
35
37
|
inject: ()=>inject,
|
|
@@ -41,6 +43,8 @@ __webpack_require__.d(style_namespaceObject, {
|
|
|
41
43
|
var dom_namespaceObject = {};
|
|
42
44
|
__webpack_require__.r(dom_namespaceObject);
|
|
43
45
|
__webpack_require__.d(dom_namespaceObject, {
|
|
46
|
+
component: ()=>component,
|
|
47
|
+
create: ()=>create,
|
|
44
48
|
default: ()=>dom,
|
|
45
49
|
el: ()=>dom_el,
|
|
46
50
|
els: ()=>els,
|
|
@@ -49,7 +53,8 @@ __webpack_require__.d(dom_namespaceObject, {
|
|
|
49
53
|
onBlur: ()=>onBlur,
|
|
50
54
|
onFocus: ()=>onFocus,
|
|
51
55
|
onKey: ()=>onKey,
|
|
52
|
-
ready: ()=>ready
|
|
56
|
+
ready: ()=>ready,
|
|
57
|
+
registerElement: ()=>registerElement
|
|
53
58
|
});
|
|
54
59
|
var network_namespaceObject = {};
|
|
55
60
|
__webpack_require__.r(network_namespaceObject);
|
|
@@ -126,17 +131,104 @@ function render(style) {
|
|
|
126
131
|
Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
|
|
127
132
|
return s;
|
|
128
133
|
}
|
|
129
|
-
function
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
function splitSelectors(selector) {
|
|
135
|
+
const out = [];
|
|
136
|
+
let depth = 0;
|
|
137
|
+
let quote = '';
|
|
138
|
+
let current = '';
|
|
139
|
+
for (const ch of selector){
|
|
140
|
+
if (quote) {
|
|
141
|
+
if (ch === quote) quote = '';
|
|
142
|
+
} else if ('"' === ch || "'" === ch) quote = ch;
|
|
143
|
+
else if ('(' === ch || '[' === ch) depth++;
|
|
144
|
+
else if (')' === ch || ']' === ch) depth--;
|
|
145
|
+
else if (',' === ch && 0 === depth) {
|
|
146
|
+
if (current.trim()) out.push(current.trim());
|
|
147
|
+
current = '';
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
current += ch;
|
|
151
|
+
}
|
|
152
|
+
if (current.trim()) out.push(current.trim());
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
function resolve(parents, selector) {
|
|
156
|
+
const out = [];
|
|
157
|
+
for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
function compile(parents, decls, indent = '') {
|
|
161
|
+
const blocks = [];
|
|
162
|
+
const props = [];
|
|
163
|
+
const nested = [];
|
|
164
|
+
for (const [k, v] of Object.entries(decls))if (null !== v && 'object' == typeof v) nested.push([
|
|
165
|
+
k,
|
|
166
|
+
v
|
|
167
|
+
]);
|
|
168
|
+
else props.push(`${indent} ${toKebab(k)}: ${v};`);
|
|
169
|
+
if (props.length) blocks.push(`${indent}${parents.join(', ')} {\n${props.join('\n')}\n${indent}}`);
|
|
170
|
+
for (const [selector, block] of nested){
|
|
171
|
+
if (selector.startsWith('@')) {
|
|
172
|
+
const inner = selector.startsWith('@keyframes') ? Object.entries(block).flatMap(([step, d])=>null !== d && 'object' == typeof d ? compile([
|
|
173
|
+
step
|
|
174
|
+
], d, `${indent} `) : []) : compile(parents, block, `${indent} `);
|
|
175
|
+
if (inner.length) blocks.push(`${indent}${selector} {\n${inner.join('\n')}\n${indent}}`);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
blocks.push(...compile(resolve(parents, selector), block, indent));
|
|
179
|
+
}
|
|
180
|
+
return blocks;
|
|
181
|
+
}
|
|
182
|
+
function css(selector, style) {
|
|
183
|
+
return compile(splitSelectors(selector), style).join('\n');
|
|
184
|
+
}
|
|
185
|
+
function registry() {
|
|
186
|
+
const doc = document;
|
|
187
|
+
if (!doc.__corvidSheets) doc.__corvidSheets = new Map();
|
|
188
|
+
return doc.__corvidSheets;
|
|
189
|
+
}
|
|
190
|
+
function adoptable() {
|
|
191
|
+
return 'undefined' != typeof CSSStyleSheet && 'replaceSync' in CSSStyleSheet.prototype && 'undefined' != typeof Document && 'adoptedStyleSheets' in Document.prototype;
|
|
192
|
+
}
|
|
193
|
+
function styleTag(key) {
|
|
194
|
+
const tagged = Array.from(document.head.querySelectorAll('style[data-corvid]'));
|
|
195
|
+
for (const node of tagged)if (node.dataset.corvid === key) return node;
|
|
196
|
+
const node = document.createElement('style');
|
|
197
|
+
node.dataset.corvid = key;
|
|
198
|
+
document.head.appendChild(node);
|
|
199
|
+
return node;
|
|
200
|
+
}
|
|
201
|
+
function inject(selector, style, { key = selector } = {}) {
|
|
202
|
+
const rules = css(selector, style);
|
|
203
|
+
const sheets = registry();
|
|
204
|
+
const existing = sheets.get(key);
|
|
205
|
+
if (existing) {
|
|
206
|
+
if ('replaceSync' in existing) existing.replaceSync(rules);
|
|
207
|
+
else existing.textContent = rules;
|
|
208
|
+
return rules;
|
|
209
|
+
}
|
|
210
|
+
if (adoptable()) {
|
|
211
|
+
const sheet = new CSSStyleSheet();
|
|
212
|
+
sheet.replaceSync(rules);
|
|
213
|
+
document.adoptedStyleSheets = [
|
|
214
|
+
...document.adoptedStyleSheets,
|
|
215
|
+
sheet
|
|
216
|
+
];
|
|
217
|
+
sheets.set(key, sheet);
|
|
218
|
+
return rules;
|
|
219
|
+
}
|
|
220
|
+
const node = styleTag(key);
|
|
221
|
+
node.textContent = rules;
|
|
222
|
+
sheets.set(key, node);
|
|
223
|
+
return rules;
|
|
224
|
+
}
|
|
225
|
+
function eject(key) {
|
|
226
|
+
const sheets = registry();
|
|
227
|
+
const sheet = sheets.get(key);
|
|
228
|
+
if (!sheet) return;
|
|
229
|
+
if ('replaceSync' in sheet) document.adoptedStyleSheets = document.adoptedStyleSheets.filter((s)=>s !== sheet);
|
|
230
|
+
else sheet.remove();
|
|
231
|
+
sheets.delete(key);
|
|
140
232
|
}
|
|
141
233
|
function isDarkMode() {
|
|
142
234
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
@@ -272,6 +364,37 @@ class logger {
|
|
|
272
364
|
});
|
|
273
365
|
}
|
|
274
366
|
}
|
|
367
|
+
function _check_private_redeclaration(obj, privateCollection) {
|
|
368
|
+
if (privateCollection.has(obj)) throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
369
|
+
}
|
|
370
|
+
function _class_apply_descriptor_get(receiver, descriptor) {
|
|
371
|
+
if (descriptor.get) return descriptor.get.call(receiver);
|
|
372
|
+
return descriptor.value;
|
|
373
|
+
}
|
|
374
|
+
function _class_apply_descriptor_set(receiver, descriptor, value) {
|
|
375
|
+
if (descriptor.set) descriptor.set.call(receiver, value);
|
|
376
|
+
else {
|
|
377
|
+
if (!descriptor.writable) throw new TypeError("attempted to set read only private field");
|
|
378
|
+
descriptor.value = value;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
function _class_extract_field_descriptor(receiver, privateMap, action) {
|
|
382
|
+
if (!privateMap.has(receiver)) throw new TypeError("attempted to " + action + " private field on non-instance");
|
|
383
|
+
return privateMap.get(receiver);
|
|
384
|
+
}
|
|
385
|
+
function _class_private_field_get(receiver, privateMap) {
|
|
386
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
|
|
387
|
+
return _class_apply_descriptor_get(receiver, descriptor);
|
|
388
|
+
}
|
|
389
|
+
function _class_private_field_init(obj, privateMap, value) {
|
|
390
|
+
_check_private_redeclaration(obj, privateMap);
|
|
391
|
+
privateMap.set(obj, value);
|
|
392
|
+
}
|
|
393
|
+
function _class_private_field_set(receiver, privateMap, value) {
|
|
394
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
|
|
395
|
+
_class_apply_descriptor_set(receiver, descriptor, value);
|
|
396
|
+
return value;
|
|
397
|
+
}
|
|
275
398
|
function dom_define_property(obj, key, value) {
|
|
276
399
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
277
400
|
value: value,
|
|
@@ -321,6 +444,14 @@ function onKey(key, cb, verbose = false) {
|
|
|
321
444
|
function els(query, verbose = false) {
|
|
322
445
|
return Array.from(document.querySelectorAll(query)).map((n)=>new dom_el(n, verbose));
|
|
323
446
|
}
|
|
447
|
+
function registerElement(name, ctor) {
|
|
448
|
+
const existing = customElements.get(name);
|
|
449
|
+
if (existing) {
|
|
450
|
+
if (existing !== ctor) throw new Error(`custom element ${name} is already registered by ${existing.name}`);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
customElements.define(name, ctor);
|
|
454
|
+
}
|
|
324
455
|
class dom_el {
|
|
325
456
|
static query(query, verbose = false) {
|
|
326
457
|
return new dom_el(query, verbose);
|
|
@@ -379,6 +510,7 @@ class dom_el {
|
|
|
379
510
|
html(content) {
|
|
380
511
|
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
381
512
|
this.el.innerHTML = content;
|
|
513
|
+
return this;
|
|
382
514
|
}
|
|
383
515
|
src(url) {
|
|
384
516
|
if (this.el && 'src' in this.el) this.el.src = url;
|
|
@@ -405,7 +537,7 @@ class dom_el {
|
|
|
405
537
|
else if ('object' == typeof update) {
|
|
406
538
|
if (!stringify) {
|
|
407
539
|
for (const [k, v] of Object.entries(update))this.el.style[k] = v;
|
|
408
|
-
return;
|
|
540
|
+
return this;
|
|
409
541
|
}
|
|
410
542
|
const s = render(update);
|
|
411
543
|
this.log.debug(`set style: ${this.el.style} -> ${s}`);
|
|
@@ -508,6 +640,56 @@ class dom_el {
|
|
|
508
640
|
}
|
|
509
641
|
}
|
|
510
642
|
}
|
|
643
|
+
function create(opts, verbose = false) {
|
|
644
|
+
const node = new dom_el(opts, verbose).el;
|
|
645
|
+
if (!node) throw new Error(`could not create element: ${opts.tag ?? opts.query ?? '?'}`);
|
|
646
|
+
return node;
|
|
647
|
+
}
|
|
648
|
+
var _mounted = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
|
|
649
|
+
class component extends HTMLElement {
|
|
650
|
+
static register(tag) {
|
|
651
|
+
const name = tag ?? this.tag;
|
|
652
|
+
if (!name) throw new Error(`${this.name}: nothing to register as, set \`static tag = 'x-...'\``);
|
|
653
|
+
if (!name.includes('-')) throw new Error(`${this.name}: '${name}' is not a valid custom element name, it needs a hyphen`);
|
|
654
|
+
if (this.styles) inject(name, this.styles);
|
|
655
|
+
registerElement(name, this);
|
|
656
|
+
}
|
|
657
|
+
mount() {}
|
|
658
|
+
unmount() {}
|
|
659
|
+
onAttr(_name, _value, _prev) {}
|
|
660
|
+
connectedCallback() {
|
|
661
|
+
if (!_class_private_field_get(this, _mounted)) {
|
|
662
|
+
_class_private_field_set(this, _mounted, true);
|
|
663
|
+
this.mount();
|
|
664
|
+
const queued = _class_private_field_get(this, _pendingAttrs);
|
|
665
|
+
_class_private_field_set(this, _pendingAttrs, []);
|
|
666
|
+
for (const [name, value, prev] of queued)this.onAttr(name, value, prev);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
disconnectedCallback() {
|
|
670
|
+
this.unmount();
|
|
671
|
+
}
|
|
672
|
+
attributeChangedCallback(name, prev, value) {
|
|
673
|
+
if (prev === value) return;
|
|
674
|
+
if (!_class_private_field_get(this, _mounted)) return void _class_private_field_get(this, _pendingAttrs).push([
|
|
675
|
+
name,
|
|
676
|
+
value,
|
|
677
|
+
prev
|
|
678
|
+
]);
|
|
679
|
+
this.onAttr(name, value, prev);
|
|
680
|
+
}
|
|
681
|
+
constructor(...args){
|
|
682
|
+
super(...args), _class_private_field_init(this, _mounted, {
|
|
683
|
+
writable: true,
|
|
684
|
+
value: false
|
|
685
|
+
}), _class_private_field_init(this, _pendingAttrs, {
|
|
686
|
+
writable: true,
|
|
687
|
+
value: []
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
dom_define_property(component, "tag", '');
|
|
692
|
+
dom_define_property(component, "styles", null);
|
|
511
693
|
function interpolate(str, params) {
|
|
512
694
|
let names = Object.keys(params).map((k)=>`_${k}`);
|
|
513
695
|
let vals = Object.values(params);
|
|
@@ -516,6 +698,9 @@ function interpolate(str, params) {
|
|
|
516
698
|
const dom = {
|
|
517
699
|
el: dom_el,
|
|
518
700
|
els,
|
|
701
|
+
create,
|
|
702
|
+
component,
|
|
703
|
+
registerElement,
|
|
519
704
|
ready,
|
|
520
705
|
on,
|
|
521
706
|
onKey
|
package/dist/ls.js
CHANGED
|
@@ -1,11 +1,102 @@
|
|
|
1
|
-
function
|
|
1
|
+
function toKebab(str) {
|
|
2
2
|
return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, ofs)=>(ofs ? '-' : '') + s.toLowerCase());
|
|
3
3
|
}
|
|
4
4
|
function render(style) {
|
|
5
5
|
let s = '';
|
|
6
|
-
Object.entries(style).forEach(([k, v])=>s += `${
|
|
6
|
+
Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
|
|
7
7
|
return s;
|
|
8
8
|
}
|
|
9
|
+
function splitSelectors(selector) {
|
|
10
|
+
const out = [];
|
|
11
|
+
let depth = 0;
|
|
12
|
+
let quote = '';
|
|
13
|
+
let current = '';
|
|
14
|
+
for (const ch of selector){
|
|
15
|
+
if (quote) {
|
|
16
|
+
if (ch === quote) quote = '';
|
|
17
|
+
} else if ('"' === ch || "'" === ch) quote = ch;
|
|
18
|
+
else if ('(' === ch || '[' === ch) depth++;
|
|
19
|
+
else if (')' === ch || ']' === ch) depth--;
|
|
20
|
+
else if (',' === ch && 0 === depth) {
|
|
21
|
+
if (current.trim()) out.push(current.trim());
|
|
22
|
+
current = '';
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
current += ch;
|
|
26
|
+
}
|
|
27
|
+
if (current.trim()) out.push(current.trim());
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
function resolve(parents, selector) {
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function compile(parents, decls, indent = '') {
|
|
36
|
+
const blocks = [];
|
|
37
|
+
const props = [];
|
|
38
|
+
const nested = [];
|
|
39
|
+
for (const [k, v] of Object.entries(decls))if (null !== v && 'object' == typeof v) nested.push([
|
|
40
|
+
k,
|
|
41
|
+
v
|
|
42
|
+
]);
|
|
43
|
+
else props.push(`${indent} ${toKebab(k)}: ${v};`);
|
|
44
|
+
if (props.length) blocks.push(`${indent}${parents.join(', ')} {\n${props.join('\n')}\n${indent}}`);
|
|
45
|
+
for (const [selector, block] of nested){
|
|
46
|
+
if (selector.startsWith('@')) {
|
|
47
|
+
const inner = selector.startsWith('@keyframes') ? Object.entries(block).flatMap(([step, d])=>null !== d && 'object' == typeof d ? compile([
|
|
48
|
+
step
|
|
49
|
+
], d, `${indent} `) : []) : compile(parents, block, `${indent} `);
|
|
50
|
+
if (inner.length) blocks.push(`${indent}${selector} {\n${inner.join('\n')}\n${indent}}`);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
blocks.push(...compile(resolve(parents, selector), block, indent));
|
|
54
|
+
}
|
|
55
|
+
return blocks;
|
|
56
|
+
}
|
|
57
|
+
function css(selector, style) {
|
|
58
|
+
return compile(splitSelectors(selector), style).join('\n');
|
|
59
|
+
}
|
|
60
|
+
function registry() {
|
|
61
|
+
const doc = document;
|
|
62
|
+
if (!doc.__corvidSheets) doc.__corvidSheets = new Map();
|
|
63
|
+
return doc.__corvidSheets;
|
|
64
|
+
}
|
|
65
|
+
function adoptable() {
|
|
66
|
+
return 'undefined' != typeof CSSStyleSheet && 'replaceSync' in CSSStyleSheet.prototype && 'undefined' != typeof Document && 'adoptedStyleSheets' in Document.prototype;
|
|
67
|
+
}
|
|
68
|
+
function styleTag(key) {
|
|
69
|
+
const tagged = Array.from(document.head.querySelectorAll('style[data-corvid]'));
|
|
70
|
+
for (const node of tagged)if (node.dataset.corvid === key) return node;
|
|
71
|
+
const node = document.createElement('style');
|
|
72
|
+
node.dataset.corvid = key;
|
|
73
|
+
document.head.appendChild(node);
|
|
74
|
+
return node;
|
|
75
|
+
}
|
|
76
|
+
function inject(selector, style, { key = selector } = {}) {
|
|
77
|
+
const rules = css(selector, style);
|
|
78
|
+
const sheets = registry();
|
|
79
|
+
const existing = sheets.get(key);
|
|
80
|
+
if (existing) {
|
|
81
|
+
if ('replaceSync' in existing) existing.replaceSync(rules);
|
|
82
|
+
else existing.textContent = rules;
|
|
83
|
+
return rules;
|
|
84
|
+
}
|
|
85
|
+
if (adoptable()) {
|
|
86
|
+
const sheet = new CSSStyleSheet();
|
|
87
|
+
sheet.replaceSync(rules);
|
|
88
|
+
document.adoptedStyleSheets = [
|
|
89
|
+
...document.adoptedStyleSheets,
|
|
90
|
+
sheet
|
|
91
|
+
];
|
|
92
|
+
sheets.set(key, sheet);
|
|
93
|
+
return rules;
|
|
94
|
+
}
|
|
95
|
+
const node = styleTag(key);
|
|
96
|
+
node.textContent = rules;
|
|
97
|
+
sheets.set(key, node);
|
|
98
|
+
return rules;
|
|
99
|
+
}
|
|
9
100
|
function _define_property(obj, key, value) {
|
|
10
101
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
11
102
|
value: value,
|
|
@@ -61,6 +152,37 @@ class utils_logger {
|
|
|
61
152
|
});
|
|
62
153
|
}
|
|
63
154
|
}
|
|
155
|
+
function _check_private_redeclaration(obj, privateCollection) {
|
|
156
|
+
if (privateCollection.has(obj)) throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
157
|
+
}
|
|
158
|
+
function _class_apply_descriptor_get(receiver, descriptor) {
|
|
159
|
+
if (descriptor.get) return descriptor.get.call(receiver);
|
|
160
|
+
return descriptor.value;
|
|
161
|
+
}
|
|
162
|
+
function _class_apply_descriptor_set(receiver, descriptor, value) {
|
|
163
|
+
if (descriptor.set) descriptor.set.call(receiver, value);
|
|
164
|
+
else {
|
|
165
|
+
if (!descriptor.writable) throw new TypeError("attempted to set read only private field");
|
|
166
|
+
descriptor.value = value;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function _class_extract_field_descriptor(receiver, privateMap, action) {
|
|
170
|
+
if (!privateMap.has(receiver)) throw new TypeError("attempted to " + action + " private field on non-instance");
|
|
171
|
+
return privateMap.get(receiver);
|
|
172
|
+
}
|
|
173
|
+
function _class_private_field_get(receiver, privateMap) {
|
|
174
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
|
|
175
|
+
return _class_apply_descriptor_get(receiver, descriptor);
|
|
176
|
+
}
|
|
177
|
+
function _class_private_field_init(obj, privateMap, value) {
|
|
178
|
+
_check_private_redeclaration(obj, privateMap);
|
|
179
|
+
privateMap.set(obj, value);
|
|
180
|
+
}
|
|
181
|
+
function _class_private_field_set(receiver, privateMap, value) {
|
|
182
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
|
|
183
|
+
_class_apply_descriptor_set(receiver, descriptor, value);
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
64
186
|
function dom_define_property(obj, key, value) {
|
|
65
187
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
66
188
|
value: value,
|
|
@@ -71,6 +193,14 @@ function dom_define_property(obj, key, value) {
|
|
|
71
193
|
else obj[key] = value;
|
|
72
194
|
return obj;
|
|
73
195
|
}
|
|
196
|
+
function registerElement(name, ctor) {
|
|
197
|
+
const existing = customElements.get(name);
|
|
198
|
+
if (existing) {
|
|
199
|
+
if (existing !== ctor) throw new Error(`custom element ${name} is already registered by ${existing.name}`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
customElements.define(name, ctor);
|
|
203
|
+
}
|
|
74
204
|
class dom_el {
|
|
75
205
|
static query(query, verbose = false) {
|
|
76
206
|
return new dom_el(query, verbose);
|
|
@@ -129,6 +259,7 @@ class dom_el {
|
|
|
129
259
|
html(content) {
|
|
130
260
|
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
131
261
|
this.el.innerHTML = content;
|
|
262
|
+
return this;
|
|
132
263
|
}
|
|
133
264
|
src(url) {
|
|
134
265
|
if (this.el && 'src' in this.el) this.el.src = url;
|
|
@@ -155,7 +286,7 @@ class dom_el {
|
|
|
155
286
|
else if ('object' == typeof update) {
|
|
156
287
|
if (!stringify) {
|
|
157
288
|
for (const [k, v] of Object.entries(update))this.el.style[k] = v;
|
|
158
|
-
return;
|
|
289
|
+
return this;
|
|
159
290
|
}
|
|
160
291
|
const s = render(update);
|
|
161
292
|
this.log.debug(`set style: ${this.el.style} -> ${s}`);
|
|
@@ -258,6 +389,51 @@ class dom_el {
|
|
|
258
389
|
}
|
|
259
390
|
}
|
|
260
391
|
}
|
|
392
|
+
var _mounted = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
|
|
393
|
+
class component extends HTMLElement {
|
|
394
|
+
static register(tag) {
|
|
395
|
+
const name = tag ?? this.tag;
|
|
396
|
+
if (!name) throw new Error(`${this.name}: nothing to register as, set \`static tag = 'x-...'\``);
|
|
397
|
+
if (!name.includes('-')) throw new Error(`${this.name}: '${name}' is not a valid custom element name, it needs a hyphen`);
|
|
398
|
+
if (this.styles) inject(name, this.styles);
|
|
399
|
+
registerElement(name, this);
|
|
400
|
+
}
|
|
401
|
+
mount() {}
|
|
402
|
+
unmount() {}
|
|
403
|
+
onAttr(_name, _value, _prev) {}
|
|
404
|
+
connectedCallback() {
|
|
405
|
+
if (!_class_private_field_get(this, _mounted)) {
|
|
406
|
+
_class_private_field_set(this, _mounted, true);
|
|
407
|
+
this.mount();
|
|
408
|
+
const queued = _class_private_field_get(this, _pendingAttrs);
|
|
409
|
+
_class_private_field_set(this, _pendingAttrs, []);
|
|
410
|
+
for (const [name, value, prev] of queued)this.onAttr(name, value, prev);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
disconnectedCallback() {
|
|
414
|
+
this.unmount();
|
|
415
|
+
}
|
|
416
|
+
attributeChangedCallback(name, prev, value) {
|
|
417
|
+
if (prev === value) return;
|
|
418
|
+
if (!_class_private_field_get(this, _mounted)) return void _class_private_field_get(this, _pendingAttrs).push([
|
|
419
|
+
name,
|
|
420
|
+
value,
|
|
421
|
+
prev
|
|
422
|
+
]);
|
|
423
|
+
this.onAttr(name, value, prev);
|
|
424
|
+
}
|
|
425
|
+
constructor(...args){
|
|
426
|
+
super(...args), _class_private_field_init(this, _mounted, {
|
|
427
|
+
writable: true,
|
|
428
|
+
value: false
|
|
429
|
+
}), _class_private_field_init(this, _pendingAttrs, {
|
|
430
|
+
writable: true,
|
|
431
|
+
value: []
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
dom_define_property(component, "tag", '');
|
|
436
|
+
dom_define_property(component, "styles", null);
|
|
261
437
|
function get(key, _default) {
|
|
262
438
|
let ret = localStorage.getItem(key);
|
|
263
439
|
if (null === ret && null != _default) {
|
package/dist/qr.js
CHANGED
|
@@ -1904,14 +1904,105 @@ const QRErrorCorrectLevel = {
|
|
|
1904
1904
|
Q: 3,
|
|
1905
1905
|
H: 2
|
|
1906
1906
|
};
|
|
1907
|
-
function
|
|
1907
|
+
function toKebab(str) {
|
|
1908
1908
|
return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, ofs)=>(ofs ? '-' : '') + s.toLowerCase());
|
|
1909
1909
|
}
|
|
1910
1910
|
function render(style) {
|
|
1911
1911
|
let s = '';
|
|
1912
|
-
Object.entries(style).forEach(([k, v])=>s += `${
|
|
1912
|
+
Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
|
|
1913
1913
|
return s;
|
|
1914
1914
|
}
|
|
1915
|
+
function splitSelectors(selector) {
|
|
1916
|
+
const out = [];
|
|
1917
|
+
let depth = 0;
|
|
1918
|
+
let quote = '';
|
|
1919
|
+
let current = '';
|
|
1920
|
+
for (const ch of selector){
|
|
1921
|
+
if (quote) {
|
|
1922
|
+
if (ch === quote) quote = '';
|
|
1923
|
+
} else if ('"' === ch || "'" === ch) quote = ch;
|
|
1924
|
+
else if ('(' === ch || '[' === ch) depth++;
|
|
1925
|
+
else if (')' === ch || ']' === ch) depth--;
|
|
1926
|
+
else if (',' === ch && 0 === depth) {
|
|
1927
|
+
if (current.trim()) out.push(current.trim());
|
|
1928
|
+
current = '';
|
|
1929
|
+
continue;
|
|
1930
|
+
}
|
|
1931
|
+
current += ch;
|
|
1932
|
+
}
|
|
1933
|
+
if (current.trim()) out.push(current.trim());
|
|
1934
|
+
return out;
|
|
1935
|
+
}
|
|
1936
|
+
function resolve(parents, selector) {
|
|
1937
|
+
const out = [];
|
|
1938
|
+
for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
|
|
1939
|
+
return out;
|
|
1940
|
+
}
|
|
1941
|
+
function compile(parents, decls, indent = '') {
|
|
1942
|
+
const blocks = [];
|
|
1943
|
+
const props = [];
|
|
1944
|
+
const nested = [];
|
|
1945
|
+
for (const [k, v] of Object.entries(decls))if (null !== v && 'object' == typeof v) nested.push([
|
|
1946
|
+
k,
|
|
1947
|
+
v
|
|
1948
|
+
]);
|
|
1949
|
+
else props.push(`${indent} ${toKebab(k)}: ${v};`);
|
|
1950
|
+
if (props.length) blocks.push(`${indent}${parents.join(', ')} {\n${props.join('\n')}\n${indent}}`);
|
|
1951
|
+
for (const [selector, block] of nested){
|
|
1952
|
+
if (selector.startsWith('@')) {
|
|
1953
|
+
const inner = selector.startsWith('@keyframes') ? Object.entries(block).flatMap(([step, d])=>null !== d && 'object' == typeof d ? compile([
|
|
1954
|
+
step
|
|
1955
|
+
], d, `${indent} `) : []) : compile(parents, block, `${indent} `);
|
|
1956
|
+
if (inner.length) blocks.push(`${indent}${selector} {\n${inner.join('\n')}\n${indent}}`);
|
|
1957
|
+
continue;
|
|
1958
|
+
}
|
|
1959
|
+
blocks.push(...compile(resolve(parents, selector), block, indent));
|
|
1960
|
+
}
|
|
1961
|
+
return blocks;
|
|
1962
|
+
}
|
|
1963
|
+
function css(selector, style) {
|
|
1964
|
+
return compile(splitSelectors(selector), style).join('\n');
|
|
1965
|
+
}
|
|
1966
|
+
function registry() {
|
|
1967
|
+
const doc = document;
|
|
1968
|
+
if (!doc.__corvidSheets) doc.__corvidSheets = new Map();
|
|
1969
|
+
return doc.__corvidSheets;
|
|
1970
|
+
}
|
|
1971
|
+
function adoptable() {
|
|
1972
|
+
return 'undefined' != typeof CSSStyleSheet && 'replaceSync' in CSSStyleSheet.prototype && 'undefined' != typeof Document && 'adoptedStyleSheets' in Document.prototype;
|
|
1973
|
+
}
|
|
1974
|
+
function styleTag(key) {
|
|
1975
|
+
const tagged = Array.from(document.head.querySelectorAll('style[data-corvid]'));
|
|
1976
|
+
for (const node of tagged)if (node.dataset.corvid === key) return node;
|
|
1977
|
+
const node = document.createElement('style');
|
|
1978
|
+
node.dataset.corvid = key;
|
|
1979
|
+
document.head.appendChild(node);
|
|
1980
|
+
return node;
|
|
1981
|
+
}
|
|
1982
|
+
function inject(selector, style, { key = selector } = {}) {
|
|
1983
|
+
const rules = css(selector, style);
|
|
1984
|
+
const sheets = registry();
|
|
1985
|
+
const existing = sheets.get(key);
|
|
1986
|
+
if (existing) {
|
|
1987
|
+
if ('replaceSync' in existing) existing.replaceSync(rules);
|
|
1988
|
+
else existing.textContent = rules;
|
|
1989
|
+
return rules;
|
|
1990
|
+
}
|
|
1991
|
+
if (adoptable()) {
|
|
1992
|
+
const sheet = new CSSStyleSheet();
|
|
1993
|
+
sheet.replaceSync(rules);
|
|
1994
|
+
document.adoptedStyleSheets = [
|
|
1995
|
+
...document.adoptedStyleSheets,
|
|
1996
|
+
sheet
|
|
1997
|
+
];
|
|
1998
|
+
sheets.set(key, sheet);
|
|
1999
|
+
return rules;
|
|
2000
|
+
}
|
|
2001
|
+
const node = styleTag(key);
|
|
2002
|
+
node.textContent = rules;
|
|
2003
|
+
sheets.set(key, node);
|
|
2004
|
+
return rules;
|
|
2005
|
+
}
|
|
1915
2006
|
function utils_define_property(obj, key, value) {
|
|
1916
2007
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
1917
2008
|
value: value,
|
|
@@ -1967,6 +2058,37 @@ class utils_logger {
|
|
|
1967
2058
|
});
|
|
1968
2059
|
}
|
|
1969
2060
|
}
|
|
2061
|
+
function _check_private_redeclaration(obj, privateCollection) {
|
|
2062
|
+
if (privateCollection.has(obj)) throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
2063
|
+
}
|
|
2064
|
+
function _class_apply_descriptor_get(receiver, descriptor) {
|
|
2065
|
+
if (descriptor.get) return descriptor.get.call(receiver);
|
|
2066
|
+
return descriptor.value;
|
|
2067
|
+
}
|
|
2068
|
+
function _class_apply_descriptor_set(receiver, descriptor, value) {
|
|
2069
|
+
if (descriptor.set) descriptor.set.call(receiver, value);
|
|
2070
|
+
else {
|
|
2071
|
+
if (!descriptor.writable) throw new TypeError("attempted to set read only private field");
|
|
2072
|
+
descriptor.value = value;
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
function _class_extract_field_descriptor(receiver, privateMap, action) {
|
|
2076
|
+
if (!privateMap.has(receiver)) throw new TypeError("attempted to " + action + " private field on non-instance");
|
|
2077
|
+
return privateMap.get(receiver);
|
|
2078
|
+
}
|
|
2079
|
+
function _class_private_field_get(receiver, privateMap) {
|
|
2080
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
|
|
2081
|
+
return _class_apply_descriptor_get(receiver, descriptor);
|
|
2082
|
+
}
|
|
2083
|
+
function _class_private_field_init(obj, privateMap, value) {
|
|
2084
|
+
_check_private_redeclaration(obj, privateMap);
|
|
2085
|
+
privateMap.set(obj, value);
|
|
2086
|
+
}
|
|
2087
|
+
function _class_private_field_set(receiver, privateMap, value) {
|
|
2088
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
|
|
2089
|
+
_class_apply_descriptor_set(receiver, descriptor, value);
|
|
2090
|
+
return value;
|
|
2091
|
+
}
|
|
1970
2092
|
function dom_define_property(obj, key, value) {
|
|
1971
2093
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
1972
2094
|
value: value,
|
|
@@ -1977,6 +2099,14 @@ function dom_define_property(obj, key, value) {
|
|
|
1977
2099
|
else obj[key] = value;
|
|
1978
2100
|
return obj;
|
|
1979
2101
|
}
|
|
2102
|
+
function registerElement(name, ctor) {
|
|
2103
|
+
const existing = customElements.get(name);
|
|
2104
|
+
if (existing) {
|
|
2105
|
+
if (existing !== ctor) throw new Error(`custom element ${name} is already registered by ${existing.name}`);
|
|
2106
|
+
return;
|
|
2107
|
+
}
|
|
2108
|
+
customElements.define(name, ctor);
|
|
2109
|
+
}
|
|
1980
2110
|
class dom_el {
|
|
1981
2111
|
static query(query, verbose = false) {
|
|
1982
2112
|
return new dom_el(query, verbose);
|
|
@@ -2035,6 +2165,7 @@ class dom_el {
|
|
|
2035
2165
|
html(content) {
|
|
2036
2166
|
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2037
2167
|
this.el.innerHTML = content;
|
|
2168
|
+
return this;
|
|
2038
2169
|
}
|
|
2039
2170
|
src(url) {
|
|
2040
2171
|
if (this.el && 'src' in this.el) this.el.src = url;
|
|
@@ -2061,7 +2192,7 @@ class dom_el {
|
|
|
2061
2192
|
else if ('object' == typeof update) {
|
|
2062
2193
|
if (!stringify) {
|
|
2063
2194
|
for (const [k, v] of Object.entries(update))this.el.style[k] = v;
|
|
2064
|
-
return;
|
|
2195
|
+
return this;
|
|
2065
2196
|
}
|
|
2066
2197
|
const s = render(update);
|
|
2067
2198
|
this.log.debug(`set style: ${this.el.style} -> ${s}`);
|
|
@@ -2164,6 +2295,51 @@ class dom_el {
|
|
|
2164
2295
|
}
|
|
2165
2296
|
}
|
|
2166
2297
|
}
|
|
2298
|
+
var _mounted = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
|
|
2299
|
+
class component extends HTMLElement {
|
|
2300
|
+
static register(tag) {
|
|
2301
|
+
const name = tag ?? this.tag;
|
|
2302
|
+
if (!name) throw new Error(`${this.name}: nothing to register as, set \`static tag = 'x-...'\``);
|
|
2303
|
+
if (!name.includes('-')) throw new Error(`${this.name}: '${name}' is not a valid custom element name, it needs a hyphen`);
|
|
2304
|
+
if (this.styles) inject(name, this.styles);
|
|
2305
|
+
registerElement(name, this);
|
|
2306
|
+
}
|
|
2307
|
+
mount() {}
|
|
2308
|
+
unmount() {}
|
|
2309
|
+
onAttr(_name, _value, _prev) {}
|
|
2310
|
+
connectedCallback() {
|
|
2311
|
+
if (!_class_private_field_get(this, _mounted)) {
|
|
2312
|
+
_class_private_field_set(this, _mounted, true);
|
|
2313
|
+
this.mount();
|
|
2314
|
+
const queued = _class_private_field_get(this, _pendingAttrs);
|
|
2315
|
+
_class_private_field_set(this, _pendingAttrs, []);
|
|
2316
|
+
for (const [name, value, prev] of queued)this.onAttr(name, value, prev);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
disconnectedCallback() {
|
|
2320
|
+
this.unmount();
|
|
2321
|
+
}
|
|
2322
|
+
attributeChangedCallback(name, prev, value) {
|
|
2323
|
+
if (prev === value) return;
|
|
2324
|
+
if (!_class_private_field_get(this, _mounted)) return void _class_private_field_get(this, _pendingAttrs).push([
|
|
2325
|
+
name,
|
|
2326
|
+
value,
|
|
2327
|
+
prev
|
|
2328
|
+
]);
|
|
2329
|
+
this.onAttr(name, value, prev);
|
|
2330
|
+
}
|
|
2331
|
+
constructor(...args){
|
|
2332
|
+
super(...args), _class_private_field_init(this, _mounted, {
|
|
2333
|
+
writable: true,
|
|
2334
|
+
value: false
|
|
2335
|
+
}), _class_private_field_init(this, _pendingAttrs, {
|
|
2336
|
+
writable: true,
|
|
2337
|
+
value: []
|
|
2338
|
+
});
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
dom_define_property(component, "tag", '');
|
|
2342
|
+
dom_define_property(component, "styles", null);
|
|
2167
2343
|
class QR {
|
|
2168
2344
|
static render(config, element) {
|
|
2169
2345
|
const settings = this.getDefaultSettings(config);
|
package/dist/style.d.ts
CHANGED
|
@@ -3,7 +3,42 @@
|
|
|
3
3
|
**************/
|
|
4
4
|
export declare function cssVar(name: string): string;
|
|
5
5
|
export declare function render(style: Object): string;
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* A block of css declarations. A value that is itself an object is a nested
|
|
8
|
+
* rule: the key is a selector (`&:focus`, `input`) or an at-rule (`@media ...`)
|
|
9
|
+
* rather than a property.
|
|
10
|
+
*/
|
|
11
|
+
export type declarations = {
|
|
12
|
+
[key: string]: string | number | declarations;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Render a declaration block to css without touching the document.
|
|
16
|
+
*/
|
|
17
|
+
export declare function css(selector: string, style: declarations): string;
|
|
18
|
+
/**
|
|
19
|
+
* Install a stylesheet for `selector`. Nested objects become nested rules, so
|
|
20
|
+
* a component declares its styles in one call:
|
|
21
|
+
*
|
|
22
|
+
* inject('x-search-form', {
|
|
23
|
+
* marginTop: '33vh',
|
|
24
|
+
* input: {
|
|
25
|
+
* border: 'none',
|
|
26
|
+
* '&:focus': { borderBottomColor: 'var(--ring)' },
|
|
27
|
+
* },
|
|
28
|
+
* })
|
|
29
|
+
*
|
|
30
|
+
* Injecting the same key again replaces that sheet rather than adding to it;
|
|
31
|
+
* `key` defaults to the selector.
|
|
32
|
+
* @return the generated css
|
|
33
|
+
*/
|
|
34
|
+
export declare function inject(selector: string, style: declarations, { key }?: {
|
|
35
|
+
key?: string;
|
|
36
|
+
}): string;
|
|
37
|
+
/**
|
|
38
|
+
* Remove a stylesheet installed by `inject`
|
|
39
|
+
* @param key - the key it was injected under (the selector, unless overridden)
|
|
40
|
+
*/
|
|
41
|
+
export declare function eject(key: string): void;
|
|
7
42
|
/**
|
|
8
43
|
* Check if the current theme is dark
|
|
9
44
|
*/
|
package/dist/style.js
CHANGED
|
@@ -10,17 +10,104 @@ function render(style) {
|
|
|
10
10
|
Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
|
|
11
11
|
return s;
|
|
12
12
|
}
|
|
13
|
-
function
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
function splitSelectors(selector) {
|
|
14
|
+
const out = [];
|
|
15
|
+
let depth = 0;
|
|
16
|
+
let quote = '';
|
|
17
|
+
let current = '';
|
|
18
|
+
for (const ch of selector){
|
|
19
|
+
if (quote) {
|
|
20
|
+
if (ch === quote) quote = '';
|
|
21
|
+
} else if ('"' === ch || "'" === ch) quote = ch;
|
|
22
|
+
else if ('(' === ch || '[' === ch) depth++;
|
|
23
|
+
else if (')' === ch || ']' === ch) depth--;
|
|
24
|
+
else if (',' === ch && 0 === depth) {
|
|
25
|
+
if (current.trim()) out.push(current.trim());
|
|
26
|
+
current = '';
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
current += ch;
|
|
30
|
+
}
|
|
31
|
+
if (current.trim()) out.push(current.trim());
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
function resolve(parents, selector) {
|
|
35
|
+
const out = [];
|
|
36
|
+
for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
function compile(parents, decls, indent = '') {
|
|
40
|
+
const blocks = [];
|
|
41
|
+
const props = [];
|
|
42
|
+
const nested = [];
|
|
43
|
+
for (const [k, v] of Object.entries(decls))if (null !== v && 'object' == typeof v) nested.push([
|
|
44
|
+
k,
|
|
45
|
+
v
|
|
46
|
+
]);
|
|
47
|
+
else props.push(`${indent} ${toKebab(k)}: ${v};`);
|
|
48
|
+
if (props.length) blocks.push(`${indent}${parents.join(', ')} {\n${props.join('\n')}\n${indent}}`);
|
|
49
|
+
for (const [selector, block] of nested){
|
|
50
|
+
if (selector.startsWith('@')) {
|
|
51
|
+
const inner = selector.startsWith('@keyframes') ? Object.entries(block).flatMap(([step, d])=>null !== d && 'object' == typeof d ? compile([
|
|
52
|
+
step
|
|
53
|
+
], d, `${indent} `) : []) : compile(parents, block, `${indent} `);
|
|
54
|
+
if (inner.length) blocks.push(`${indent}${selector} {\n${inner.join('\n')}\n${indent}}`);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
blocks.push(...compile(resolve(parents, selector), block, indent));
|
|
58
|
+
}
|
|
59
|
+
return blocks;
|
|
60
|
+
}
|
|
61
|
+
function css(selector, style) {
|
|
62
|
+
return compile(splitSelectors(selector), style).join('\n');
|
|
63
|
+
}
|
|
64
|
+
function registry() {
|
|
65
|
+
const doc = document;
|
|
66
|
+
if (!doc.__corvidSheets) doc.__corvidSheets = new Map();
|
|
67
|
+
return doc.__corvidSheets;
|
|
68
|
+
}
|
|
69
|
+
function adoptable() {
|
|
70
|
+
return 'undefined' != typeof CSSStyleSheet && 'replaceSync' in CSSStyleSheet.prototype && 'undefined' != typeof Document && 'adoptedStyleSheets' in Document.prototype;
|
|
71
|
+
}
|
|
72
|
+
function styleTag(key) {
|
|
73
|
+
const tagged = Array.from(document.head.querySelectorAll('style[data-corvid]'));
|
|
74
|
+
for (const node of tagged)if (node.dataset.corvid === key) return node;
|
|
75
|
+
const node = document.createElement('style');
|
|
76
|
+
node.dataset.corvid = key;
|
|
77
|
+
document.head.appendChild(node);
|
|
78
|
+
return node;
|
|
79
|
+
}
|
|
80
|
+
function inject(selector, style, { key = selector } = {}) {
|
|
81
|
+
const rules = css(selector, style);
|
|
82
|
+
const sheets = registry();
|
|
83
|
+
const existing = sheets.get(key);
|
|
84
|
+
if (existing) {
|
|
85
|
+
if ('replaceSync' in existing) existing.replaceSync(rules);
|
|
86
|
+
else existing.textContent = rules;
|
|
87
|
+
return rules;
|
|
88
|
+
}
|
|
89
|
+
if (adoptable()) {
|
|
90
|
+
const sheet = new CSSStyleSheet();
|
|
91
|
+
sheet.replaceSync(rules);
|
|
92
|
+
document.adoptedStyleSheets = [
|
|
93
|
+
...document.adoptedStyleSheets,
|
|
94
|
+
sheet
|
|
95
|
+
];
|
|
96
|
+
sheets.set(key, sheet);
|
|
97
|
+
return rules;
|
|
98
|
+
}
|
|
99
|
+
const node = styleTag(key);
|
|
100
|
+
node.textContent = rules;
|
|
101
|
+
sheets.set(key, node);
|
|
102
|
+
return rules;
|
|
103
|
+
}
|
|
104
|
+
function eject(key) {
|
|
105
|
+
const sheets = registry();
|
|
106
|
+
const sheet = sheets.get(key);
|
|
107
|
+
if (!sheet) return;
|
|
108
|
+
if ('replaceSync' in sheet) document.adoptedStyleSheets = document.adoptedStyleSheets.filter((s)=>s !== sheet);
|
|
109
|
+
else sheet.remove();
|
|
110
|
+
sheets.delete(key);
|
|
24
111
|
}
|
|
25
112
|
function isDarkMode() {
|
|
26
113
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
@@ -46,4 +133,4 @@ function gradient(start, end, value) {
|
|
|
46
133
|
const blue = Math.round(start.blue + (end.blue - start.blue) * value / 100);
|
|
47
134
|
return `rgb(${red}, ${green}, ${blue})`;
|
|
48
135
|
}
|
|
49
|
-
export { cssVar, gradient, handleThemeSwitch, inject, isDarkMode, onDarkMode, render, switchTheme };
|
|
136
|
+
export { css, cssVar, eject, gradient, handleThemeSwitch, inject, isDarkMode, onDarkMode, render, switchTheme };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|