@taybart/corvid 0.1.31 → 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 +99 -14
- package/dist/dom.js +247 -36
- package/dist/index.js +263 -36
- package/dist/ls.js +227 -39
- package/dist/qr.js +227 -39
- package/dist/style.d.ts +36 -0
- package/dist/style.js +100 -1
- package/dist/style.test.d.ts +1 -0
- package/package.json +11 -9
package/dist/qr.js
CHANGED
|
@@ -1912,6 +1912,97 @@ function render(style) {
|
|
|
1912
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);
|
|
@@ -1999,21 +2129,29 @@ class dom_el {
|
|
|
1999
2129
|
parent.appendChild(this.el);
|
|
2000
2130
|
return this;
|
|
2001
2131
|
}
|
|
2132
|
+
append(ch) {
|
|
2133
|
+
return this.child(ch);
|
|
2134
|
+
}
|
|
2002
2135
|
appendChild(ch) {
|
|
2003
2136
|
return this.child(ch);
|
|
2004
2137
|
}
|
|
2005
2138
|
child(ch) {
|
|
2006
2139
|
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2007
|
-
if (
|
|
2140
|
+
if ('string' == typeof ch) this.el.append(ch);
|
|
2141
|
+
else if (ch instanceof dom_el) this.el.appendChild(ch.el);
|
|
2008
2142
|
else this.el.appendChild(ch);
|
|
2009
2143
|
return this;
|
|
2010
2144
|
}
|
|
2011
|
-
|
|
2145
|
+
prepend(ch) {
|
|
2012
2146
|
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2013
|
-
if (
|
|
2147
|
+
if ('string' == typeof ch) this.el.prepend(ch);
|
|
2148
|
+
else if (ch instanceof dom_el) this.el.prepend(ch.el);
|
|
2014
2149
|
else this.el.prepend(ch);
|
|
2015
2150
|
return this;
|
|
2016
2151
|
}
|
|
2152
|
+
prependChild(ch) {
|
|
2153
|
+
return this.prepend(ch);
|
|
2154
|
+
}
|
|
2017
2155
|
empty() {
|
|
2018
2156
|
if (this.el) this.el.innerHTML = '';
|
|
2019
2157
|
return this;
|
|
@@ -2024,17 +2162,37 @@ class dom_el {
|
|
|
2024
2162
|
else this.el.innerHTML = content;
|
|
2025
2163
|
return this;
|
|
2026
2164
|
}
|
|
2165
|
+
html(content) {
|
|
2166
|
+
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2167
|
+
this.el.innerHTML = content;
|
|
2168
|
+
return this;
|
|
2169
|
+
}
|
|
2027
2170
|
src(url) {
|
|
2028
2171
|
if (this.el && 'src' in this.el) this.el.src = url;
|
|
2029
2172
|
return this;
|
|
2030
2173
|
}
|
|
2174
|
+
attrs(attrs) {
|
|
2175
|
+
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2176
|
+
for (const [k, v] of Object.entries(attrs))this.el.setAttribute(k, v);
|
|
2177
|
+
return this;
|
|
2178
|
+
}
|
|
2179
|
+
attr(key, val) {
|
|
2180
|
+
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2181
|
+
this.el.setAttribute(key, val);
|
|
2182
|
+
return this;
|
|
2183
|
+
}
|
|
2184
|
+
removeAttr(key) {
|
|
2185
|
+
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2186
|
+
this.el.removeAttribute(key);
|
|
2187
|
+
return this;
|
|
2188
|
+
}
|
|
2031
2189
|
style(update, stringify = false) {
|
|
2032
2190
|
if (this.el) {
|
|
2033
2191
|
if ('string' == typeof update) this.el.style = update;
|
|
2034
2192
|
else if ('object' == typeof update) {
|
|
2035
2193
|
if (!stringify) {
|
|
2036
2194
|
for (const [k, v] of Object.entries(update))this.el.style[k] = v;
|
|
2037
|
-
return;
|
|
2195
|
+
return this;
|
|
2038
2196
|
}
|
|
2039
2197
|
const s = render(update);
|
|
2040
2198
|
this.log.debug(`set style: ${this.el.style} -> ${s}`);
|
|
@@ -2059,38 +2217,23 @@ class dom_el {
|
|
|
2059
2217
|
else for (const sc of className)this.el.classList.remove(sc);
|
|
2060
2218
|
return this;
|
|
2061
2219
|
}
|
|
2062
|
-
|
|
2063
|
-
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2064
|
-
this.el.innerHTML = content;
|
|
2065
|
-
}
|
|
2066
|
-
render(vars = {}) {
|
|
2067
|
-
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2068
|
-
try {
|
|
2069
|
-
return interpolate(this.el.innerHTML, vars);
|
|
2070
|
-
} catch (e) {
|
|
2071
|
-
throw new Error(`could not render template ${this.query}: ${e}`);
|
|
2072
|
-
}
|
|
2073
|
-
}
|
|
2074
|
-
appendTemplate(template, vars) {
|
|
2075
|
-
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2076
|
-
if (!template.el) throw new Error("template does not contain element");
|
|
2077
|
-
const tmpl = template.render(vars);
|
|
2078
|
-
this.el.insertAdjacentHTML('beforeend', tmpl);
|
|
2079
|
-
}
|
|
2080
|
-
on(event, cb) {
|
|
2220
|
+
on(event, cb, options) {
|
|
2081
2221
|
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2082
2222
|
if (!this.listeners[event]) this.listeners[event] = [];
|
|
2083
|
-
this.listeners[event].push(
|
|
2084
|
-
|
|
2223
|
+
this.listeners[event].push({
|
|
2224
|
+
cb,
|
|
2225
|
+
options
|
|
2226
|
+
});
|
|
2227
|
+
this.el.addEventListener(event, cb, options);
|
|
2085
2228
|
return this;
|
|
2086
2229
|
}
|
|
2087
|
-
listen(event, cb) {
|
|
2088
|
-
return this.on(event, cb);
|
|
2230
|
+
listen(event, cb, options) {
|
|
2231
|
+
return this.on(event, cb, options);
|
|
2089
2232
|
}
|
|
2090
2233
|
removeListeners(event) {
|
|
2091
2234
|
if (!this.el) throw new Error(`no element from query: ${this.query}`);
|
|
2092
2235
|
if (!this.listeners[event]) return this;
|
|
2093
|
-
for (const cb of this.listeners[event])this.el.removeEventListener(event, cb);
|
|
2236
|
+
for (const { cb, options } of this.listeners[event])this.el.removeEventListener(event, cb, options);
|
|
2094
2237
|
this.listeners[event] = [];
|
|
2095
2238
|
return this;
|
|
2096
2239
|
}
|
|
@@ -2110,7 +2253,7 @@ class dom_el {
|
|
|
2110
2253
|
this.el = opts;
|
|
2111
2254
|
return;
|
|
2112
2255
|
}
|
|
2113
|
-
const { query, element,
|
|
2256
|
+
const { query, element, tag, class: styleClass, style, id, content, parent, attrs } = opts;
|
|
2114
2257
|
if (query) {
|
|
2115
2258
|
this.log.debug(`using query: ${query}`);
|
|
2116
2259
|
this.query = query;
|
|
@@ -2119,11 +2262,11 @@ class dom_el {
|
|
|
2119
2262
|
} else if (element) {
|
|
2120
2263
|
this.log.debug(`using existing element: ${element}`);
|
|
2121
2264
|
this.el = element;
|
|
2122
|
-
} else if (
|
|
2123
|
-
this.query =
|
|
2124
|
-
this.log.debug(`creating element: ${
|
|
2125
|
-
this.el = document.createElement(
|
|
2126
|
-
} else throw new Error('no query or
|
|
2265
|
+
} else if (tag) {
|
|
2266
|
+
this.query = tag;
|
|
2267
|
+
this.log.debug(`creating element: ${tag}`);
|
|
2268
|
+
this.el = document.createElement(tag);
|
|
2269
|
+
} else throw new Error('no query or tag provided');
|
|
2127
2270
|
if (this.el) {
|
|
2128
2271
|
if (id) {
|
|
2129
2272
|
this.log.debug(`setting id: ${id}`);
|
|
@@ -2138,7 +2281,12 @@ class dom_el {
|
|
|
2138
2281
|
}
|
|
2139
2282
|
if (parent) {
|
|
2140
2283
|
this.log.debug("adding to parent");
|
|
2141
|
-
parent
|
|
2284
|
+
let p = parent;
|
|
2285
|
+
if ('string' == typeof parent) {
|
|
2286
|
+
this.log.debug(`parent query: ${parent}`);
|
|
2287
|
+
p = document.querySelector(parent);
|
|
2288
|
+
}
|
|
2289
|
+
p.appendChild(this.el);
|
|
2142
2290
|
}
|
|
2143
2291
|
}
|
|
2144
2292
|
if (attrs) for (const [key, val] of Object.entries(attrs)){
|
|
@@ -2147,11 +2295,51 @@ class dom_el {
|
|
|
2147
2295
|
}
|
|
2148
2296
|
}
|
|
2149
2297
|
}
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
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
|
+
}
|
|
2154
2340
|
}
|
|
2341
|
+
dom_define_property(component, "tag", '');
|
|
2342
|
+
dom_define_property(component, "styles", null);
|
|
2155
2343
|
class QR {
|
|
2156
2344
|
static render(config, element) {
|
|
2157
2345
|
const settings = this.getDefaultSettings(config);
|
package/dist/style.d.ts
CHANGED
|
@@ -3,6 +3,42 @@
|
|
|
3
3
|
**************/
|
|
4
4
|
export declare function cssVar(name: string): string;
|
|
5
5
|
export declare function render(style: Object): string;
|
|
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;
|
|
6
42
|
/**
|
|
7
43
|
* Check if the current theme is dark
|
|
8
44
|
*/
|
package/dist/style.js
CHANGED
|
@@ -10,6 +10,105 @@ function render(style) {
|
|
|
10
10
|
Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
|
|
11
11
|
return s;
|
|
12
12
|
}
|
|
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);
|
|
111
|
+
}
|
|
13
112
|
function isDarkMode() {
|
|
14
113
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
15
114
|
}
|
|
@@ -34,4 +133,4 @@ function gradient(start, end, value) {
|
|
|
34
133
|
const blue = Math.round(start.blue + (end.blue - start.blue) * value / 100);
|
|
35
134
|
return `rgb(${red}, ${green}, ${blue})`;
|
|
36
135
|
}
|
|
37
|
-
export { cssVar, gradient, handleThemeSwitch, isDarkMode, onDarkMode, render, switchTheme };
|
|
136
|
+
export { css, cssVar, eject, gradient, handleThemeSwitch, inject, isDarkMode, onDarkMode, render, switchTheme };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taybart/corvid",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -38,18 +38,20 @@
|
|
|
38
38
|
"files": [
|
|
39
39
|
"dist"
|
|
40
40
|
],
|
|
41
|
-
"scripts": {
|
|
42
|
-
"build": "rslib build",
|
|
43
|
-
"dev": "rslib build --watch"
|
|
44
|
-
},
|
|
45
41
|
"devDependencies": {
|
|
46
|
-
"@happy-dom/global-registrator": "^17.4.7",
|
|
47
42
|
"@rslib/core": "^0.6.2",
|
|
48
43
|
"@testing-library/dom": "^10.4.0",
|
|
49
44
|
"@testing-library/jest-dom": "^6.6.3",
|
|
50
|
-
"@types/bun": "^1.2.13",
|
|
51
45
|
"@types/jsdom": "^21.1.7",
|
|
52
46
|
"@types/node": "^22.8.1",
|
|
53
|
-
"
|
|
47
|
+
"happy-dom": "^18.0.1",
|
|
48
|
+
"typescript": "^5.8.3",
|
|
49
|
+
"vitest": "^3.2.4"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "rslib build",
|
|
53
|
+
"dev": "rslib build --watch",
|
|
54
|
+
"test": "vitest run",
|
|
55
|
+
"test:watch": "vitest"
|
|
54
56
|
}
|
|
55
|
-
}
|
|
57
|
+
}
|