@taybart/corvid 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dom.d.ts CHANGED
@@ -58,7 +58,7 @@ export declare class el {
58
58
  content(content: any, { text }?: {
59
59
  text?: boolean;
60
60
  }): this;
61
- html(content: string): this;
61
+ html(content: string | HTMLElement | el): this;
62
62
  src(url: string): this;
63
63
  attrs(attrs: Object): this;
64
64
  attr(key: string, val: string): this;
@@ -66,6 +66,7 @@ export declare class el {
66
66
  /*** Style ***/
67
67
  style(update: Object | string, stringify?: boolean): this;
68
68
  hasClass(className: string): boolean;
69
+ toggleClass(className: string): this;
69
70
  addClass(className: string | string[]): this;
70
71
  removeClass(className: string | string[]): this;
71
72
  /*** Events ***/
@@ -84,20 +85,7 @@ export declare class el {
84
85
  */
85
86
  export declare function create<T extends HTMLElement = HTMLElement>(opts: elOpts, verbose?: boolean): T;
86
87
  /*** 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
- */
88
+ export declare function registerComponents(components: (typeof component)[], verbose?: boolean): void;
101
89
  export declare class component extends HTMLElement {
102
90
  #private;
103
91
  /** the name to register as; must contain a hyphen */
@@ -108,12 +96,38 @@ export declare class component extends HTMLElement {
108
96
  * the class actually registered under.
109
97
  */
110
98
  static styles: style.declarations | null;
99
+ /**
100
+ * Opt in to a shadow root: `static shadow = { mode: 'open' }`.
101
+ *
102
+ * Without it a component's `styles` are injected at document level and
103
+ * compile to plain descendant selectors, so an outer component's `ul` or
104
+ * `.meta` rule reaches an inner component's markup — and only has to name a
105
+ * property the inner rule leaves unset to take effect. A shadow root ends
106
+ * that by construction, in both directions.
107
+ *
108
+ * What changes for the component: put children in `this.root`, not `this`.
109
+ * Two things to know before turning it on —
110
+ *
111
+ * - light-dom children are not rendered unless the root has a `<slot>`, so a
112
+ * component that takes `content` needs one
113
+ * - a nested custom element loses its document styles inside the root, so
114
+ * anything rendered in here has to be shadowed too
115
+ * DOCS: https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM
116
+ */
117
+ static shadow: ShadowRootInit | null;
118
+ constructor();
119
+ /**
120
+ * Where this component's children belong: its shadow root when it has one,
121
+ * otherwise the element itself. Use it instead of `this` for `append`,
122
+ * `replaceChildren` and `querySelector`, and the component works either way.
123
+ */
124
+ get root(): ShadowRoot | this;
111
125
  /**
112
126
  * Inject this component's styles and define it. Idempotent, so calling it
113
127
  * twice (or after an HMR reload) is harmless.
114
128
  * @param tag - overrides `static tag`
115
129
  */
116
- static register(tag?: string): void;
130
+ static register(tag?: string, verbose?: boolean): void;
117
131
  /**
118
132
  * Called once, the first time the element is connected. Build the subtree and
119
133
  * wire listeners here — a custom element cannot give itself children before
package/dist/dom.js CHANGED
@@ -27,9 +27,52 @@ function splitSelectors(selector) {
27
27
  if (current.trim()) out.push(current.trim());
28
28
  return out;
29
29
  }
30
+ function hostCompound(selector) {
31
+ if (!selector.startsWith(':host')) return selector;
32
+ let i = 5;
33
+ let inner = '';
34
+ if ('(' === selector[i]) {
35
+ const open = i;
36
+ let depth = 0;
37
+ let quote = '';
38
+ while(i < selector.length){
39
+ const ch = selector[i];
40
+ if (quote) {
41
+ if (ch === quote) quote = '';
42
+ } else if ('"' === ch || "'" === ch) quote = ch;
43
+ else if ('(' === ch) depth++;
44
+ else if (')' === ch) {
45
+ depth--;
46
+ if (0 === depth) {
47
+ i++;
48
+ break;
49
+ }
50
+ }
51
+ i++;
52
+ }
53
+ inner = selector.slice(open + 1, i - 1);
54
+ }
55
+ const start = i;
56
+ let depth = 0;
57
+ let quote = '';
58
+ while(i < selector.length){
59
+ const ch = selector[i];
60
+ if (quote) {
61
+ if (ch === quote) quote = '';
62
+ } else if ('"' === ch || "'" === ch) quote = ch;
63
+ else if (0 === depth && (' ' === ch || '>' === ch || '+' === ch || '~' === ch)) break;
64
+ else if (0 === depth && ':' === ch && ':' === selector[i + 1]) break;
65
+ else if ('(' === ch || '[' === ch) depth++;
66
+ else if (')' === ch || ']' === ch) depth--;
67
+ i++;
68
+ }
69
+ const compound = selector.slice(start, i);
70
+ if (!compound) return selector;
71
+ return `:host(${inner}${compound})${selector.slice(i)}`;
72
+ }
30
73
  function resolve(parents, selector) {
31
74
  const out = [];
32
- for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
75
+ for (const parent of parents)for (const part of splitSelectors(selector))out.push(hostCompound(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`));
33
76
  return out;
34
77
  }
35
78
  function compile(parents, decls, indent = '') {
@@ -97,6 +140,20 @@ function inject(selector, style, { key = selector } = {}) {
97
140
  sheets.set(key, node);
98
141
  return rules;
99
142
  }
143
+ function shadowSheet(key, style) {
144
+ const rules = css(':host', style);
145
+ if ('undefined' == typeof CSSStyleSheet || !('replaceSync' in CSSStyleSheet.prototype) || 'undefined' == typeof ShadowRoot || !('adoptedStyleSheets' in ShadowRoot.prototype)) return rules;
146
+ const sheets = registry();
147
+ const existing = sheets.get(key);
148
+ if (existing && 'replaceSync' in existing) {
149
+ existing.replaceSync(rules);
150
+ return existing;
151
+ }
152
+ const sheet = new CSSStyleSheet();
153
+ sheet.replaceSync(rules);
154
+ sheets.set(key, sheet);
155
+ return sheet;
156
+ }
100
157
  function _define_property(obj, key, value) {
101
158
  if (key in obj) Object.defineProperty(obj, key, {
102
159
  value: value,
@@ -297,7 +354,10 @@ class dom_el {
297
354
  }
298
355
  html(content) {
299
356
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
300
- this.el.innerHTML = content;
357
+ if ('string' == typeof content) this.el.innerHTML = content;
358
+ else if (content instanceof dom_el) {
359
+ if (content.el) this.el.replaceChildren(content.el);
360
+ } else this.el.replaceChildren(content);
301
361
  return this;
302
362
  }
303
363
  src(url) {
@@ -338,6 +398,12 @@ class dom_el {
338
398
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
339
399
  return this.el.classList.contains(className);
340
400
  }
401
+ toggleClass(className) {
402
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
403
+ if (this.el.classList.contains(className)) this.el.classList.remove(className);
404
+ else this.el.classList.add(className);
405
+ return this;
406
+ }
341
407
  addClass(className) {
342
408
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
343
409
  if ('string' == typeof className) this.el.classList.add(className);
@@ -433,13 +499,22 @@ function create(opts, verbose = false) {
433
499
  if (!node) throw new Error(`could not create element: ${opts.tag ?? opts.query ?? '?'}`);
434
500
  return node;
435
501
  }
436
- var _mounted = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
502
+ function registerComponents(components, verbose = false) {
503
+ for (const c of components)c.register(void 0, verbose);
504
+ }
505
+ const dom_sheets = new WeakMap();
506
+ var _mounted = /*#__PURE__*/ new WeakMap(), _root = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
437
507
  class component extends HTMLElement {
438
- static register(tag) {
508
+ get root() {
509
+ return _class_private_field_get(this, _root) ?? this;
510
+ }
511
+ static register(tag, verbose = false) {
439
512
  const name = tag ?? this.tag;
440
513
  if (!name) throw new Error(`${this.name}: nothing to register as, set \`static tag = 'x-...'\``);
441
514
  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);
515
+ if (this.styles) if (this.shadow) dom_sheets.set(this, shadowSheet(`shadow:${name}`, this.styles));
516
+ else inject(name, this.styles);
517
+ if (verbose) console.log(`registering ${name}`);
443
518
  registerElement(name, this);
444
519
  }
445
520
  mount() {}
@@ -466,18 +541,35 @@ class component extends HTMLElement {
466
541
  ]);
467
542
  this.onAttr(name, value, prev);
468
543
  }
469
- constructor(...args){
470
- super(...args), _class_private_field_init(this, _mounted, {
544
+ constructor(){
545
+ super(), _class_private_field_init(this, _mounted, {
471
546
  writable: true,
472
547
  value: false
548
+ }), _class_private_field_init(this, _root, {
549
+ writable: true,
550
+ value: null
473
551
  }), _class_private_field_init(this, _pendingAttrs, {
474
552
  writable: true,
475
553
  value: []
476
554
  });
555
+ const ctor = this.constructor;
556
+ if (!ctor.shadow) return;
557
+ _class_private_field_set(this, _root, this.attachShadow(ctor.shadow));
558
+ const sheet = dom_sheets.get(ctor);
559
+ if (void 0 === sheet) return;
560
+ if ('string' == typeof sheet) {
561
+ const node = document.createElement('style');
562
+ node.textContent = sheet;
563
+ _class_private_field_get(this, _root).append(node);
564
+ } else _class_private_field_get(this, _root).adoptedStyleSheets = [
565
+ ..._class_private_field_get(this, _root).adoptedStyleSheets,
566
+ sheet
567
+ ];
477
568
  }
478
569
  }
479
570
  dom_define_property(component, "tag", '');
480
571
  dom_define_property(component, "styles", null);
572
+ dom_define_property(component, "shadow", null);
481
573
  function interpolate(str, params) {
482
574
  let names = Object.keys(params).map((k)=>`_${k}`);
483
575
  let vals = Object.values(params);
@@ -493,4 +585,4 @@ const dom = {
493
585
  on,
494
586
  onKey
495
587
  };
496
- export { component, create, dom as default, dom_el as el, els, interpolate, on, onBlur, onFocus, onKey, ready, registerElement };
588
+ export { component, create, dom as default, dom_el as el, els, interpolate, on, onBlur, onFocus, onKey, ready, registerComponents, registerElement };
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@ __webpack_require__.d(style_namespaceObject, {
38
38
  isDarkMode: ()=>isDarkMode,
39
39
  onDarkMode: ()=>onDarkMode,
40
40
  render: ()=>render,
41
+ shadowSheet: ()=>shadowSheet,
41
42
  switchTheme: ()=>switchTheme
42
43
  });
43
44
  var dom_namespaceObject = {};
@@ -54,6 +55,7 @@ __webpack_require__.d(dom_namespaceObject, {
54
55
  onFocus: ()=>onFocus,
55
56
  onKey: ()=>onKey,
56
57
  ready: ()=>ready,
58
+ registerComponents: ()=>registerComponents,
57
59
  registerElement: ()=>registerElement
58
60
  });
59
61
  var network_namespaceObject = {};
@@ -152,9 +154,52 @@ function splitSelectors(selector) {
152
154
  if (current.trim()) out.push(current.trim());
153
155
  return out;
154
156
  }
157
+ function hostCompound(selector) {
158
+ if (!selector.startsWith(':host')) return selector;
159
+ let i = 5;
160
+ let inner = '';
161
+ if ('(' === selector[i]) {
162
+ const open = i;
163
+ let depth = 0;
164
+ let quote = '';
165
+ while(i < selector.length){
166
+ const ch = selector[i];
167
+ if (quote) {
168
+ if (ch === quote) quote = '';
169
+ } else if ('"' === ch || "'" === ch) quote = ch;
170
+ else if ('(' === ch) depth++;
171
+ else if (')' === ch) {
172
+ depth--;
173
+ if (0 === depth) {
174
+ i++;
175
+ break;
176
+ }
177
+ }
178
+ i++;
179
+ }
180
+ inner = selector.slice(open + 1, i - 1);
181
+ }
182
+ const start = i;
183
+ let depth = 0;
184
+ let quote = '';
185
+ while(i < selector.length){
186
+ const ch = selector[i];
187
+ if (quote) {
188
+ if (ch === quote) quote = '';
189
+ } else if ('"' === ch || "'" === ch) quote = ch;
190
+ else if (0 === depth && (' ' === ch || '>' === ch || '+' === ch || '~' === ch)) break;
191
+ else if (0 === depth && ':' === ch && ':' === selector[i + 1]) break;
192
+ else if ('(' === ch || '[' === ch) depth++;
193
+ else if (')' === ch || ']' === ch) depth--;
194
+ i++;
195
+ }
196
+ const compound = selector.slice(start, i);
197
+ if (!compound) return selector;
198
+ return `:host(${inner}${compound})${selector.slice(i)}`;
199
+ }
155
200
  function resolve(parents, selector) {
156
201
  const out = [];
157
- for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
202
+ for (const parent of parents)for (const part of splitSelectors(selector))out.push(hostCompound(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`));
158
203
  return out;
159
204
  }
160
205
  function compile(parents, decls, indent = '') {
@@ -222,6 +267,20 @@ function inject(selector, style, { key = selector } = {}) {
222
267
  sheets.set(key, node);
223
268
  return rules;
224
269
  }
270
+ function shadowSheet(key, style) {
271
+ const rules = css(':host', style);
272
+ if ('undefined' == typeof CSSStyleSheet || !('replaceSync' in CSSStyleSheet.prototype) || 'undefined' == typeof ShadowRoot || !('adoptedStyleSheets' in ShadowRoot.prototype)) return rules;
273
+ const sheets = registry();
274
+ const existing = sheets.get(key);
275
+ if (existing && 'replaceSync' in existing) {
276
+ existing.replaceSync(rules);
277
+ return existing;
278
+ }
279
+ const sheet = new CSSStyleSheet();
280
+ sheet.replaceSync(rules);
281
+ sheets.set(key, sheet);
282
+ return sheet;
283
+ }
225
284
  function eject(key) {
226
285
  const sheets = registry();
227
286
  const sheet = sheets.get(key);
@@ -509,7 +568,10 @@ class dom_el {
509
568
  }
510
569
  html(content) {
511
570
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
512
- this.el.innerHTML = content;
571
+ if ('string' == typeof content) this.el.innerHTML = content;
572
+ else if (content instanceof dom_el) {
573
+ if (content.el) this.el.replaceChildren(content.el);
574
+ } else this.el.replaceChildren(content);
513
575
  return this;
514
576
  }
515
577
  src(url) {
@@ -550,6 +612,12 @@ class dom_el {
550
612
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
551
613
  return this.el.classList.contains(className);
552
614
  }
615
+ toggleClass(className) {
616
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
617
+ if (this.el.classList.contains(className)) this.el.classList.remove(className);
618
+ else this.el.classList.add(className);
619
+ return this;
620
+ }
553
621
  addClass(className) {
554
622
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
555
623
  if ('string' == typeof className) this.el.classList.add(className);
@@ -645,13 +713,22 @@ function create(opts, verbose = false) {
645
713
  if (!node) throw new Error(`could not create element: ${opts.tag ?? opts.query ?? '?'}`);
646
714
  return node;
647
715
  }
648
- var _mounted = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
716
+ function registerComponents(components, verbose = false) {
717
+ for (const c of components)c.register(void 0, verbose);
718
+ }
719
+ const dom_sheets = new WeakMap();
720
+ var _mounted = /*#__PURE__*/ new WeakMap(), _root = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
649
721
  class component extends HTMLElement {
650
- static register(tag) {
722
+ get root() {
723
+ return _class_private_field_get(this, _root) ?? this;
724
+ }
725
+ static register(tag, verbose = false) {
651
726
  const name = tag ?? this.tag;
652
727
  if (!name) throw new Error(`${this.name}: nothing to register as, set \`static tag = 'x-...'\``);
653
728
  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);
729
+ if (this.styles) if (this.shadow) dom_sheets.set(this, shadowSheet(`shadow:${name}`, this.styles));
730
+ else inject(name, this.styles);
731
+ if (verbose) console.log(`registering ${name}`);
655
732
  registerElement(name, this);
656
733
  }
657
734
  mount() {}
@@ -678,18 +755,35 @@ class component extends HTMLElement {
678
755
  ]);
679
756
  this.onAttr(name, value, prev);
680
757
  }
681
- constructor(...args){
682
- super(...args), _class_private_field_init(this, _mounted, {
758
+ constructor(){
759
+ super(), _class_private_field_init(this, _mounted, {
683
760
  writable: true,
684
761
  value: false
762
+ }), _class_private_field_init(this, _root, {
763
+ writable: true,
764
+ value: null
685
765
  }), _class_private_field_init(this, _pendingAttrs, {
686
766
  writable: true,
687
767
  value: []
688
768
  });
769
+ const ctor = this.constructor;
770
+ if (!ctor.shadow) return;
771
+ _class_private_field_set(this, _root, this.attachShadow(ctor.shadow));
772
+ const sheet = dom_sheets.get(ctor);
773
+ if (void 0 === sheet) return;
774
+ if ('string' == typeof sheet) {
775
+ const node = document.createElement('style');
776
+ node.textContent = sheet;
777
+ _class_private_field_get(this, _root).append(node);
778
+ } else _class_private_field_get(this, _root).adoptedStyleSheets = [
779
+ ..._class_private_field_get(this, _root).adoptedStyleSheets,
780
+ sheet
781
+ ];
689
782
  }
690
783
  }
691
784
  dom_define_property(component, "tag", '');
692
785
  dom_define_property(component, "styles", null);
786
+ dom_define_property(component, "shadow", null);
693
787
  function interpolate(str, params) {
694
788
  let names = Object.keys(params).map((k)=>`_${k}`);
695
789
  let vals = Object.values(params);
package/dist/ls.js CHANGED
@@ -27,9 +27,52 @@ function splitSelectors(selector) {
27
27
  if (current.trim()) out.push(current.trim());
28
28
  return out;
29
29
  }
30
+ function hostCompound(selector) {
31
+ if (!selector.startsWith(':host')) return selector;
32
+ let i = 5;
33
+ let inner = '';
34
+ if ('(' === selector[i]) {
35
+ const open = i;
36
+ let depth = 0;
37
+ let quote = '';
38
+ while(i < selector.length){
39
+ const ch = selector[i];
40
+ if (quote) {
41
+ if (ch === quote) quote = '';
42
+ } else if ('"' === ch || "'" === ch) quote = ch;
43
+ else if ('(' === ch) depth++;
44
+ else if (')' === ch) {
45
+ depth--;
46
+ if (0 === depth) {
47
+ i++;
48
+ break;
49
+ }
50
+ }
51
+ i++;
52
+ }
53
+ inner = selector.slice(open + 1, i - 1);
54
+ }
55
+ const start = i;
56
+ let depth = 0;
57
+ let quote = '';
58
+ while(i < selector.length){
59
+ const ch = selector[i];
60
+ if (quote) {
61
+ if (ch === quote) quote = '';
62
+ } else if ('"' === ch || "'" === ch) quote = ch;
63
+ else if (0 === depth && (' ' === ch || '>' === ch || '+' === ch || '~' === ch)) break;
64
+ else if (0 === depth && ':' === ch && ':' === selector[i + 1]) break;
65
+ else if ('(' === ch || '[' === ch) depth++;
66
+ else if (')' === ch || ']' === ch) depth--;
67
+ i++;
68
+ }
69
+ const compound = selector.slice(start, i);
70
+ if (!compound) return selector;
71
+ return `:host(${inner}${compound})${selector.slice(i)}`;
72
+ }
30
73
  function resolve(parents, selector) {
31
74
  const out = [];
32
- for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
75
+ for (const parent of parents)for (const part of splitSelectors(selector))out.push(hostCompound(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`));
33
76
  return out;
34
77
  }
35
78
  function compile(parents, decls, indent = '') {
@@ -97,6 +140,20 @@ function inject(selector, style, { key = selector } = {}) {
97
140
  sheets.set(key, node);
98
141
  return rules;
99
142
  }
143
+ function shadowSheet(key, style) {
144
+ const rules = css(':host', style);
145
+ if ('undefined' == typeof CSSStyleSheet || !('replaceSync' in CSSStyleSheet.prototype) || 'undefined' == typeof ShadowRoot || !('adoptedStyleSheets' in ShadowRoot.prototype)) return rules;
146
+ const sheets = registry();
147
+ const existing = sheets.get(key);
148
+ if (existing && 'replaceSync' in existing) {
149
+ existing.replaceSync(rules);
150
+ return existing;
151
+ }
152
+ const sheet = new CSSStyleSheet();
153
+ sheet.replaceSync(rules);
154
+ sheets.set(key, sheet);
155
+ return sheet;
156
+ }
100
157
  function _define_property(obj, key, value) {
101
158
  if (key in obj) Object.defineProperty(obj, key, {
102
159
  value: value,
@@ -258,7 +315,10 @@ class dom_el {
258
315
  }
259
316
  html(content) {
260
317
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
261
- this.el.innerHTML = content;
318
+ if ('string' == typeof content) this.el.innerHTML = content;
319
+ else if (content instanceof dom_el) {
320
+ if (content.el) this.el.replaceChildren(content.el);
321
+ } else this.el.replaceChildren(content);
262
322
  return this;
263
323
  }
264
324
  src(url) {
@@ -299,6 +359,12 @@ class dom_el {
299
359
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
300
360
  return this.el.classList.contains(className);
301
361
  }
362
+ toggleClass(className) {
363
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
364
+ if (this.el.classList.contains(className)) this.el.classList.remove(className);
365
+ else this.el.classList.add(className);
366
+ return this;
367
+ }
302
368
  addClass(className) {
303
369
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
304
370
  if ('string' == typeof className) this.el.classList.add(className);
@@ -389,13 +455,19 @@ class dom_el {
389
455
  }
390
456
  }
391
457
  }
392
- var _mounted = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
458
+ const dom_sheets = new WeakMap();
459
+ var _mounted = /*#__PURE__*/ new WeakMap(), _root = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
393
460
  class component extends HTMLElement {
394
- static register(tag) {
461
+ get root() {
462
+ return _class_private_field_get(this, _root) ?? this;
463
+ }
464
+ static register(tag, verbose = false) {
395
465
  const name = tag ?? this.tag;
396
466
  if (!name) throw new Error(`${this.name}: nothing to register as, set \`static tag = 'x-...'\``);
397
467
  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);
468
+ if (this.styles) if (this.shadow) dom_sheets.set(this, shadowSheet(`shadow:${name}`, this.styles));
469
+ else inject(name, this.styles);
470
+ if (verbose) console.log(`registering ${name}`);
399
471
  registerElement(name, this);
400
472
  }
401
473
  mount() {}
@@ -422,18 +494,35 @@ class component extends HTMLElement {
422
494
  ]);
423
495
  this.onAttr(name, value, prev);
424
496
  }
425
- constructor(...args){
426
- super(...args), _class_private_field_init(this, _mounted, {
497
+ constructor(){
498
+ super(), _class_private_field_init(this, _mounted, {
427
499
  writable: true,
428
500
  value: false
501
+ }), _class_private_field_init(this, _root, {
502
+ writable: true,
503
+ value: null
429
504
  }), _class_private_field_init(this, _pendingAttrs, {
430
505
  writable: true,
431
506
  value: []
432
507
  });
508
+ const ctor = this.constructor;
509
+ if (!ctor.shadow) return;
510
+ _class_private_field_set(this, _root, this.attachShadow(ctor.shadow));
511
+ const sheet = dom_sheets.get(ctor);
512
+ if (void 0 === sheet) return;
513
+ if ('string' == typeof sheet) {
514
+ const node = document.createElement('style');
515
+ node.textContent = sheet;
516
+ _class_private_field_get(this, _root).append(node);
517
+ } else _class_private_field_get(this, _root).adoptedStyleSheets = [
518
+ ..._class_private_field_get(this, _root).adoptedStyleSheets,
519
+ sheet
520
+ ];
433
521
  }
434
522
  }
435
523
  dom_define_property(component, "tag", '');
436
524
  dom_define_property(component, "styles", null);
525
+ dom_define_property(component, "shadow", null);
437
526
  function get(key, _default) {
438
527
  let ret = localStorage.getItem(key);
439
528
  if (null === ret && null != _default) {
package/dist/qr.js CHANGED
@@ -1933,9 +1933,52 @@ function splitSelectors(selector) {
1933
1933
  if (current.trim()) out.push(current.trim());
1934
1934
  return out;
1935
1935
  }
1936
+ function hostCompound(selector) {
1937
+ if (!selector.startsWith(':host')) return selector;
1938
+ let i = 5;
1939
+ let inner = '';
1940
+ if ('(' === selector[i]) {
1941
+ const open = i;
1942
+ let depth = 0;
1943
+ let quote = '';
1944
+ while(i < selector.length){
1945
+ const ch = selector[i];
1946
+ if (quote) {
1947
+ if (ch === quote) quote = '';
1948
+ } else if ('"' === ch || "'" === ch) quote = ch;
1949
+ else if ('(' === ch) depth++;
1950
+ else if (')' === ch) {
1951
+ depth--;
1952
+ if (0 === depth) {
1953
+ i++;
1954
+ break;
1955
+ }
1956
+ }
1957
+ i++;
1958
+ }
1959
+ inner = selector.slice(open + 1, i - 1);
1960
+ }
1961
+ const start = i;
1962
+ let depth = 0;
1963
+ let quote = '';
1964
+ while(i < selector.length){
1965
+ const ch = selector[i];
1966
+ if (quote) {
1967
+ if (ch === quote) quote = '';
1968
+ } else if ('"' === ch || "'" === ch) quote = ch;
1969
+ else if (0 === depth && (' ' === ch || '>' === ch || '+' === ch || '~' === ch)) break;
1970
+ else if (0 === depth && ':' === ch && ':' === selector[i + 1]) break;
1971
+ else if ('(' === ch || '[' === ch) depth++;
1972
+ else if (')' === ch || ']' === ch) depth--;
1973
+ i++;
1974
+ }
1975
+ const compound = selector.slice(start, i);
1976
+ if (!compound) return selector;
1977
+ return `:host(${inner}${compound})${selector.slice(i)}`;
1978
+ }
1936
1979
  function resolve(parents, selector) {
1937
1980
  const out = [];
1938
- for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
1981
+ for (const parent of parents)for (const part of splitSelectors(selector))out.push(hostCompound(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`));
1939
1982
  return out;
1940
1983
  }
1941
1984
  function compile(parents, decls, indent = '') {
@@ -2003,6 +2046,20 @@ function inject(selector, style, { key = selector } = {}) {
2003
2046
  sheets.set(key, node);
2004
2047
  return rules;
2005
2048
  }
2049
+ function shadowSheet(key, style) {
2050
+ const rules = css(':host', style);
2051
+ if ('undefined' == typeof CSSStyleSheet || !('replaceSync' in CSSStyleSheet.prototype) || 'undefined' == typeof ShadowRoot || !('adoptedStyleSheets' in ShadowRoot.prototype)) return rules;
2052
+ const sheets = registry();
2053
+ const existing = sheets.get(key);
2054
+ if (existing && 'replaceSync' in existing) {
2055
+ existing.replaceSync(rules);
2056
+ return existing;
2057
+ }
2058
+ const sheet = new CSSStyleSheet();
2059
+ sheet.replaceSync(rules);
2060
+ sheets.set(key, sheet);
2061
+ return sheet;
2062
+ }
2006
2063
  function utils_define_property(obj, key, value) {
2007
2064
  if (key in obj) Object.defineProperty(obj, key, {
2008
2065
  value: value,
@@ -2164,7 +2221,10 @@ class dom_el {
2164
2221
  }
2165
2222
  html(content) {
2166
2223
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
2167
- this.el.innerHTML = content;
2224
+ if ('string' == typeof content) this.el.innerHTML = content;
2225
+ else if (content instanceof dom_el) {
2226
+ if (content.el) this.el.replaceChildren(content.el);
2227
+ } else this.el.replaceChildren(content);
2168
2228
  return this;
2169
2229
  }
2170
2230
  src(url) {
@@ -2205,6 +2265,12 @@ class dom_el {
2205
2265
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
2206
2266
  return this.el.classList.contains(className);
2207
2267
  }
2268
+ toggleClass(className) {
2269
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
2270
+ if (this.el.classList.contains(className)) this.el.classList.remove(className);
2271
+ else this.el.classList.add(className);
2272
+ return this;
2273
+ }
2208
2274
  addClass(className) {
2209
2275
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
2210
2276
  if ('string' == typeof className) this.el.classList.add(className);
@@ -2295,13 +2361,19 @@ class dom_el {
2295
2361
  }
2296
2362
  }
2297
2363
  }
2298
- var _mounted = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
2364
+ const dom_sheets = new WeakMap();
2365
+ var _mounted = /*#__PURE__*/ new WeakMap(), _root = /*#__PURE__*/ new WeakMap(), _pendingAttrs = /*#__PURE__*/ new WeakMap();
2299
2366
  class component extends HTMLElement {
2300
- static register(tag) {
2367
+ get root() {
2368
+ return _class_private_field_get(this, _root) ?? this;
2369
+ }
2370
+ static register(tag, verbose = false) {
2301
2371
  const name = tag ?? this.tag;
2302
2372
  if (!name) throw new Error(`${this.name}: nothing to register as, set \`static tag = 'x-...'\``);
2303
2373
  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);
2374
+ if (this.styles) if (this.shadow) dom_sheets.set(this, shadowSheet(`shadow:${name}`, this.styles));
2375
+ else inject(name, this.styles);
2376
+ if (verbose) console.log(`registering ${name}`);
2305
2377
  registerElement(name, this);
2306
2378
  }
2307
2379
  mount() {}
@@ -2328,18 +2400,35 @@ class component extends HTMLElement {
2328
2400
  ]);
2329
2401
  this.onAttr(name, value, prev);
2330
2402
  }
2331
- constructor(...args){
2332
- super(...args), _class_private_field_init(this, _mounted, {
2403
+ constructor(){
2404
+ super(), _class_private_field_init(this, _mounted, {
2333
2405
  writable: true,
2334
2406
  value: false
2407
+ }), _class_private_field_init(this, _root, {
2408
+ writable: true,
2409
+ value: null
2335
2410
  }), _class_private_field_init(this, _pendingAttrs, {
2336
2411
  writable: true,
2337
2412
  value: []
2338
2413
  });
2414
+ const ctor = this.constructor;
2415
+ if (!ctor.shadow) return;
2416
+ _class_private_field_set(this, _root, this.attachShadow(ctor.shadow));
2417
+ const sheet = dom_sheets.get(ctor);
2418
+ if (void 0 === sheet) return;
2419
+ if ('string' == typeof sheet) {
2420
+ const node = document.createElement('style');
2421
+ node.textContent = sheet;
2422
+ _class_private_field_get(this, _root).append(node);
2423
+ } else _class_private_field_get(this, _root).adoptedStyleSheets = [
2424
+ ..._class_private_field_get(this, _root).adoptedStyleSheets,
2425
+ sheet
2426
+ ];
2339
2427
  }
2340
2428
  }
2341
2429
  dom_define_property(component, "tag", '');
2342
2430
  dom_define_property(component, "styles", null);
2431
+ dom_define_property(component, "shadow", null);
2343
2432
  class QR {
2344
2433
  static render(config, element) {
2345
2434
  const settings = this.getDefaultSettings(config);
package/dist/style.d.ts CHANGED
@@ -34,6 +34,20 @@ export declare function css(selector: string, style: declarations): string;
34
34
  export declare function inject(selector: string, style: declarations, { key }?: {
35
35
  key?: string;
36
36
  }): string;
37
+ /**
38
+ * Compile `style` for a shadow root, rooted at `:host`.
39
+ *
40
+ * Hands back a constructable sheet where the platform has them — one per key,
41
+ * shared by every instance of the component, so a thousand cards cost one
42
+ * sheet — and the css text otherwise, for the caller to put in a `<style>`
43
+ * inside the root. Re-compiling an existing key replaces that sheet's contents
44
+ * in place, so live instances pick the change up (which is what makes an HMR
45
+ * reload work rather than stack a second sheet).
46
+ *
47
+ * Document styles do not reach into a shadow tree, so this is the only way a
48
+ * shadowed component gets styled at all.
49
+ */
50
+ export declare function shadowSheet(key: string, style: declarations): CSSStyleSheet | string;
37
51
  /**
38
52
  * Remove a stylesheet installed by `inject`
39
53
  * @param key - the key it was injected under (the selector, unless overridden)
package/dist/style.js CHANGED
@@ -31,9 +31,52 @@ function splitSelectors(selector) {
31
31
  if (current.trim()) out.push(current.trim());
32
32
  return out;
33
33
  }
34
+ function hostCompound(selector) {
35
+ if (!selector.startsWith(':host')) return selector;
36
+ let i = 5;
37
+ let inner = '';
38
+ if ('(' === selector[i]) {
39
+ const open = i;
40
+ let depth = 0;
41
+ let quote = '';
42
+ while(i < selector.length){
43
+ const ch = selector[i];
44
+ if (quote) {
45
+ if (ch === quote) quote = '';
46
+ } else if ('"' === ch || "'" === ch) quote = ch;
47
+ else if ('(' === ch) depth++;
48
+ else if (')' === ch) {
49
+ depth--;
50
+ if (0 === depth) {
51
+ i++;
52
+ break;
53
+ }
54
+ }
55
+ i++;
56
+ }
57
+ inner = selector.slice(open + 1, i - 1);
58
+ }
59
+ const start = i;
60
+ let depth = 0;
61
+ let quote = '';
62
+ while(i < selector.length){
63
+ const ch = selector[i];
64
+ if (quote) {
65
+ if (ch === quote) quote = '';
66
+ } else if ('"' === ch || "'" === ch) quote = ch;
67
+ else if (0 === depth && (' ' === ch || '>' === ch || '+' === ch || '~' === ch)) break;
68
+ else if (0 === depth && ':' === ch && ':' === selector[i + 1]) break;
69
+ else if ('(' === ch || '[' === ch) depth++;
70
+ else if (')' === ch || ']' === ch) depth--;
71
+ i++;
72
+ }
73
+ const compound = selector.slice(start, i);
74
+ if (!compound) return selector;
75
+ return `:host(${inner}${compound})${selector.slice(i)}`;
76
+ }
34
77
  function resolve(parents, selector) {
35
78
  const out = [];
36
- for (const parent of parents)for (const part of splitSelectors(selector))out.push(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`);
79
+ for (const parent of parents)for (const part of splitSelectors(selector))out.push(hostCompound(part.includes('&') ? part.replaceAll('&', parent) : `${parent} ${part}`));
37
80
  return out;
38
81
  }
39
82
  function compile(parents, decls, indent = '') {
@@ -101,6 +144,20 @@ function inject(selector, style, { key = selector } = {}) {
101
144
  sheets.set(key, node);
102
145
  return rules;
103
146
  }
147
+ function shadowSheet(key, style) {
148
+ const rules = css(':host', style);
149
+ if ('undefined' == typeof CSSStyleSheet || !('replaceSync' in CSSStyleSheet.prototype) || 'undefined' == typeof ShadowRoot || !('adoptedStyleSheets' in ShadowRoot.prototype)) return rules;
150
+ const sheets = registry();
151
+ const existing = sheets.get(key);
152
+ if (existing && 'replaceSync' in existing) {
153
+ existing.replaceSync(rules);
154
+ return existing;
155
+ }
156
+ const sheet = new CSSStyleSheet();
157
+ sheet.replaceSync(rules);
158
+ sheets.set(key, sheet);
159
+ return sheet;
160
+ }
104
161
  function eject(key) {
105
162
  const sheets = registry();
106
163
  const sheet = sheets.get(key);
@@ -133,4 +190,4 @@ function gradient(start, end, value) {
133
190
  const blue = Math.round(start.blue + (end.blue - start.blue) * value / 100);
134
191
  return `rgb(${red}, ${green}, ${blue})`;
135
192
  }
136
- export { css, cssVar, eject, gradient, handleThemeSwitch, inject, isDarkMode, onDarkMode, render, switchTheme };
193
+ export { css, cssVar, eject, gradient, handleThemeSwitch, inject, isDarkMode, onDarkMode, render, shadowSheet, switchTheme };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taybart/corvid",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {