@taybart/corvid 0.1.30 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dom.d.ts CHANGED
@@ -7,6 +7,8 @@ import { logger } from './utils';
7
7
  * onDomContentLoaded callback
8
8
  */
9
9
  export declare function ready(cb: () => void): void;
10
+ export declare function onFocus(cb: () => void): void;
11
+ export declare function onBlur(cb: () => void): void;
10
12
  export declare function on(event: string, cb: (ev: Event) => void): () => void;
11
13
  export declare function onKey(key: string, cb: (ev: {
12
14
  ctrl: boolean;
@@ -19,44 +21,50 @@ export declare function els(query: string, verbose?: boolean): el[];
19
21
  type elOpts = {
20
22
  element?: HTMLElement;
21
23
  query?: string;
22
- type?: string;
24
+ tag?: string;
23
25
  content?: any;
24
26
  class?: string | string[];
25
27
  style?: Object;
26
28
  id?: string;
27
- parent?: HTMLElement | el;
29
+ parent?: string | HTMLElement | el;
28
30
  attrs?: Object;
29
31
  };
30
32
  export declare class el {
31
33
  el: HTMLElement | null;
32
34
  query: string;
33
35
  log: logger;
34
- listeners: Record<string, Array<(ev: Event) => void>>;
36
+ listeners: Record<string, Array<{
37
+ cb: (ev: Event) => void;
38
+ options?: AddEventListenerOptions | boolean;
39
+ }>>;
35
40
  constructor(opts: HTMLElement | string | elOpts, verbose?: boolean);
36
41
  static query(query: string, verbose?: boolean): el;
37
42
  /*** dom manipulation ***/
38
43
  value(update?: string): string | el;
39
44
  parent(parent: HTMLElement | el): this;
45
+ append(ch: HTMLElement | el | string): this;
40
46
  appendChild(ch: HTMLElement | el): this;
41
- child(ch: HTMLElement | el): this;
42
- prependChild(ch: HTMLElement | el): this;
47
+ child(ch: HTMLElement | el | string): this;
48
+ prepend(ch: HTMLElement | el | string): this;
49
+ prependChild(ch: HTMLElement | el | string): this;
43
50
  empty(): this;
44
51
  content(content: any, { text }?: {
45
52
  text?: boolean;
46
53
  }): this;
54
+ html(content: string): void;
47
55
  src(url: string): this;
56
+ attrs(attrs: Object): this;
57
+ attr(key: string, val: string): this;
58
+ removeAttr(key: string): this;
48
59
  /*** Style ***/
49
60
  style(update: Object | string, stringify?: boolean): this | undefined;
50
61
  hasClass(className: string): boolean;
51
62
  addClass(className: string | string[]): this;
52
63
  removeClass(className: string | string[]): this;
53
64
  /*** Templates ***/
54
- html(content: string): void;
55
- render(vars?: {}): string;
56
- appendTemplate(template: el, vars: any): void;
57
65
  /*** Events ***/
58
- on(event: string, cb: (ev: Event) => void): this;
59
- listen(event: string, cb: (ev: Event) => void): this;
66
+ on(event: string, cb: (ev: Event) => void, options?: AddEventListenerOptions | boolean): this;
67
+ listen(event: string, cb: (ev: Event) => void, options?: AddEventListenerOptions | boolean): this;
60
68
  removeListeners(event: string): this;
61
69
  }
62
70
  /**
package/dist/dom.js CHANGED
@@ -1,9 +1,9 @@
1
- function toKebab(str) {
1
+ function strings_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 += `${toKebab(k)}:${v};`);
6
+ Object.entries(style).forEach(([k, v])=>s += `${strings_toKebab(k)}:${v};`);
7
7
  return s;
8
8
  }
9
9
  function _define_property(obj, key, value) {
@@ -74,6 +74,16 @@ function dom_define_property(obj, key, value) {
74
74
  function ready(cb) {
75
75
  window.addEventListener('DOMContentLoaded', cb);
76
76
  }
77
+ function onFocus(cb) {
78
+ window.addEventListener('focus', ()=>{
79
+ cb();
80
+ });
81
+ }
82
+ function onBlur(cb) {
83
+ window.addEventListener('blur', ()=>{
84
+ cb();
85
+ });
86
+ }
77
87
  function on(event, cb) {
78
88
  document.addEventListener(event, cb);
79
89
  return ()=>{
@@ -122,21 +132,29 @@ class dom_el {
122
132
  parent.appendChild(this.el);
123
133
  return this;
124
134
  }
135
+ append(ch) {
136
+ return this.child(ch);
137
+ }
125
138
  appendChild(ch) {
126
139
  return this.child(ch);
127
140
  }
128
141
  child(ch) {
129
142
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
130
- if (ch instanceof dom_el) this.el.appendChild(ch.el);
143
+ if ('string' == typeof ch) this.el.append(ch);
144
+ else if (ch instanceof dom_el) this.el.appendChild(ch.el);
131
145
  else this.el.appendChild(ch);
132
146
  return this;
133
147
  }
134
- prependChild(ch) {
148
+ prepend(ch) {
135
149
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
136
- if (ch instanceof dom_el) this.el.prepend(ch.el);
150
+ if ('string' == typeof ch) this.el.prepend(ch);
151
+ else if (ch instanceof dom_el) this.el.prepend(ch.el);
137
152
  else this.el.prepend(ch);
138
153
  return this;
139
154
  }
155
+ prependChild(ch) {
156
+ return this.prepend(ch);
157
+ }
140
158
  empty() {
141
159
  if (this.el) this.el.innerHTML = '';
142
160
  return this;
@@ -147,10 +165,29 @@ class dom_el {
147
165
  else this.el.innerHTML = content;
148
166
  return this;
149
167
  }
168
+ html(content) {
169
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
170
+ this.el.innerHTML = content;
171
+ }
150
172
  src(url) {
151
173
  if (this.el && 'src' in this.el) this.el.src = url;
152
174
  return this;
153
175
  }
176
+ attrs(attrs) {
177
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
178
+ for (const [k, v] of Object.entries(attrs))this.el.setAttribute(k, v);
179
+ return this;
180
+ }
181
+ attr(key, val) {
182
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
183
+ this.el.setAttribute(key, val);
184
+ return this;
185
+ }
186
+ removeAttr(key) {
187
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
188
+ this.el.removeAttribute(key);
189
+ return this;
190
+ }
154
191
  style(update, stringify = false) {
155
192
  if (this.el) {
156
193
  if ('string' == typeof update) this.el.style = update;
@@ -182,38 +219,23 @@ class dom_el {
182
219
  else for (const sc of className)this.el.classList.remove(sc);
183
220
  return this;
184
221
  }
185
- html(content) {
186
- if (!this.el) throw new Error(`no element from query: ${this.query}`);
187
- this.el.innerHTML = content;
188
- }
189
- render(vars = {}) {
190
- if (!this.el) throw new Error(`no element from query: ${this.query}`);
191
- try {
192
- return interpolate(this.el.innerHTML, vars);
193
- } catch (e) {
194
- throw new Error(`could not render template ${this.query}: ${e}`);
195
- }
196
- }
197
- appendTemplate(template, vars) {
198
- if (!this.el) throw new Error(`no element from query: ${this.query}`);
199
- if (!template.el) throw new Error("template does not contain element");
200
- const tmpl = template.render(vars);
201
- this.el.insertAdjacentHTML('beforeend', tmpl);
202
- }
203
- on(event, cb) {
222
+ on(event, cb, options) {
204
223
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
205
224
  if (!this.listeners[event]) this.listeners[event] = [];
206
- this.listeners[event].push(cb);
207
- this.el.addEventListener(event, cb);
225
+ this.listeners[event].push({
226
+ cb,
227
+ options
228
+ });
229
+ this.el.addEventListener(event, cb, options);
208
230
  return this;
209
231
  }
210
- listen(event, cb) {
211
- return this.on(event, cb);
232
+ listen(event, cb, options) {
233
+ return this.on(event, cb, options);
212
234
  }
213
235
  removeListeners(event) {
214
236
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
215
237
  if (!this.listeners[event]) return this;
216
- for (const cb of this.listeners[event])this.el.removeEventListener(event, cb);
238
+ for (const { cb, options } of this.listeners[event])this.el.removeEventListener(event, cb, options);
217
239
  this.listeners[event] = [];
218
240
  return this;
219
241
  }
@@ -233,7 +255,7 @@ class dom_el {
233
255
  this.el = opts;
234
256
  return;
235
257
  }
236
- const { query, element, type, class: styleClass, style, id, content, parent, attrs } = opts;
258
+ const { query, element, tag, class: styleClass, style, id, content, parent, attrs } = opts;
237
259
  if (query) {
238
260
  this.log.debug(`using query: ${query}`);
239
261
  this.query = query;
@@ -242,11 +264,11 @@ class dom_el {
242
264
  } else if (element) {
243
265
  this.log.debug(`using existing element: ${element}`);
244
266
  this.el = element;
245
- } else if (type) {
246
- this.query = type;
247
- this.log.debug(`creating element: ${type}`);
248
- this.el = document.createElement(type);
249
- } else throw new Error('no query or type provided');
267
+ } else if (tag) {
268
+ this.query = tag;
269
+ this.log.debug(`creating element: ${tag}`);
270
+ this.el = document.createElement(tag);
271
+ } else throw new Error('no query or tag provided');
250
272
  if (this.el) {
251
273
  if (id) {
252
274
  this.log.debug(`setting id: ${id}`);
@@ -261,7 +283,12 @@ class dom_el {
261
283
  }
262
284
  if (parent) {
263
285
  this.log.debug("adding to parent");
264
- parent.appendChild(this.el);
286
+ let p = parent;
287
+ if ('string' == typeof parent) {
288
+ this.log.debug(`parent query: ${parent}`);
289
+ p = document.querySelector(parent);
290
+ }
291
+ p.appendChild(this.el);
265
292
  }
266
293
  }
267
294
  if (attrs) for (const [key, val] of Object.entries(attrs)){
@@ -282,4 +309,4 @@ const dom = {
282
309
  on,
283
310
  onKey
284
311
  };
285
- export { dom as default, dom_el as el, els, interpolate, on, onKey, ready };
312
+ export { dom as default, dom_el as el, els, interpolate, on, onBlur, onFocus, onKey, ready };
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ __webpack_require__.d(style_namespaceObject, {
32
32
  cssVar: ()=>cssVar,
33
33
  gradient: ()=>gradient,
34
34
  handleThemeSwitch: ()=>handleThemeSwitch,
35
+ inject: ()=>inject,
35
36
  isDarkMode: ()=>isDarkMode,
36
37
  onDarkMode: ()=>onDarkMode,
37
38
  render: ()=>render,
@@ -45,6 +46,8 @@ __webpack_require__.d(dom_namespaceObject, {
45
46
  els: ()=>els,
46
47
  interpolate: ()=>interpolate,
47
48
  on: ()=>on,
49
+ onBlur: ()=>onBlur,
50
+ onFocus: ()=>onFocus,
48
51
  onKey: ()=>onKey,
49
52
  ready: ()=>ready
50
53
  });
@@ -123,6 +126,18 @@ function render(style) {
123
126
  Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
124
127
  return s;
125
128
  }
129
+ function inject(selector, style) {
130
+ const existing = document.getElementById(`corvid-injected-${encodeURIComponent(selector)}`);
131
+ if (existing) existing.remove();
132
+ const injected = document.createElement('style');
133
+ injected.id = `corvid-injected-${encodeURIComponent(selector)}`;
134
+ let s = `${selector} {\n`;
135
+ Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}: ${v};\n`);
136
+ s += '}';
137
+ injected.textContent = s;
138
+ document.head.appendChild(injected);
139
+ return s;
140
+ }
126
141
  function isDarkMode() {
127
142
  return window.matchMedia('(prefers-color-scheme: dark)').matches;
128
143
  }
@@ -270,6 +285,16 @@ function dom_define_property(obj, key, value) {
270
285
  function ready(cb) {
271
286
  window.addEventListener('DOMContentLoaded', cb);
272
287
  }
288
+ function onFocus(cb) {
289
+ window.addEventListener('focus', ()=>{
290
+ cb();
291
+ });
292
+ }
293
+ function onBlur(cb) {
294
+ window.addEventListener('blur', ()=>{
295
+ cb();
296
+ });
297
+ }
273
298
  function on(event, cb) {
274
299
  document.addEventListener(event, cb);
275
300
  return ()=>{
@@ -318,21 +343,29 @@ class dom_el {
318
343
  parent.appendChild(this.el);
319
344
  return this;
320
345
  }
346
+ append(ch) {
347
+ return this.child(ch);
348
+ }
321
349
  appendChild(ch) {
322
350
  return this.child(ch);
323
351
  }
324
352
  child(ch) {
325
353
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
326
- if (ch instanceof dom_el) this.el.appendChild(ch.el);
354
+ if ('string' == typeof ch) this.el.append(ch);
355
+ else if (ch instanceof dom_el) this.el.appendChild(ch.el);
327
356
  else this.el.appendChild(ch);
328
357
  return this;
329
358
  }
330
- prependChild(ch) {
359
+ prepend(ch) {
331
360
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
332
- if (ch instanceof dom_el) this.el.prepend(ch.el);
361
+ if ('string' == typeof ch) this.el.prepend(ch);
362
+ else if (ch instanceof dom_el) this.el.prepend(ch.el);
333
363
  else this.el.prepend(ch);
334
364
  return this;
335
365
  }
366
+ prependChild(ch) {
367
+ return this.prepend(ch);
368
+ }
336
369
  empty() {
337
370
  if (this.el) this.el.innerHTML = '';
338
371
  return this;
@@ -343,10 +376,29 @@ class dom_el {
343
376
  else this.el.innerHTML = content;
344
377
  return this;
345
378
  }
379
+ html(content) {
380
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
381
+ this.el.innerHTML = content;
382
+ }
346
383
  src(url) {
347
384
  if (this.el && 'src' in this.el) this.el.src = url;
348
385
  return this;
349
386
  }
387
+ attrs(attrs) {
388
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
389
+ for (const [k, v] of Object.entries(attrs))this.el.setAttribute(k, v);
390
+ return this;
391
+ }
392
+ attr(key, val) {
393
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
394
+ this.el.setAttribute(key, val);
395
+ return this;
396
+ }
397
+ removeAttr(key) {
398
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
399
+ this.el.removeAttribute(key);
400
+ return this;
401
+ }
350
402
  style(update, stringify = false) {
351
403
  if (this.el) {
352
404
  if ('string' == typeof update) this.el.style = update;
@@ -378,38 +430,23 @@ class dom_el {
378
430
  else for (const sc of className)this.el.classList.remove(sc);
379
431
  return this;
380
432
  }
381
- html(content) {
382
- if (!this.el) throw new Error(`no element from query: ${this.query}`);
383
- this.el.innerHTML = content;
384
- }
385
- render(vars = {}) {
386
- if (!this.el) throw new Error(`no element from query: ${this.query}`);
387
- try {
388
- return interpolate(this.el.innerHTML, vars);
389
- } catch (e) {
390
- throw new Error(`could not render template ${this.query}: ${e}`);
391
- }
392
- }
393
- appendTemplate(template, vars) {
394
- if (!this.el) throw new Error(`no element from query: ${this.query}`);
395
- if (!template.el) throw new Error("template does not contain element");
396
- const tmpl = template.render(vars);
397
- this.el.insertAdjacentHTML('beforeend', tmpl);
398
- }
399
- on(event, cb) {
433
+ on(event, cb, options) {
400
434
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
401
435
  if (!this.listeners[event]) this.listeners[event] = [];
402
- this.listeners[event].push(cb);
403
- this.el.addEventListener(event, cb);
436
+ this.listeners[event].push({
437
+ cb,
438
+ options
439
+ });
440
+ this.el.addEventListener(event, cb, options);
404
441
  return this;
405
442
  }
406
- listen(event, cb) {
407
- return this.on(event, cb);
443
+ listen(event, cb, options) {
444
+ return this.on(event, cb, options);
408
445
  }
409
446
  removeListeners(event) {
410
447
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
411
448
  if (!this.listeners[event]) return this;
412
- for (const cb of this.listeners[event])this.el.removeEventListener(event, cb);
449
+ for (const { cb, options } of this.listeners[event])this.el.removeEventListener(event, cb, options);
413
450
  this.listeners[event] = [];
414
451
  return this;
415
452
  }
@@ -429,7 +466,7 @@ class dom_el {
429
466
  this.el = opts;
430
467
  return;
431
468
  }
432
- const { query, element, type, class: styleClass, style, id, content, parent, attrs } = opts;
469
+ const { query, element, tag, class: styleClass, style, id, content, parent, attrs } = opts;
433
470
  if (query) {
434
471
  this.log.debug(`using query: ${query}`);
435
472
  this.query = query;
@@ -438,11 +475,11 @@ class dom_el {
438
475
  } else if (element) {
439
476
  this.log.debug(`using existing element: ${element}`);
440
477
  this.el = element;
441
- } else if (type) {
442
- this.query = type;
443
- this.log.debug(`creating element: ${type}`);
444
- this.el = document.createElement(type);
445
- } else throw new Error('no query or type provided');
478
+ } else if (tag) {
479
+ this.query = tag;
480
+ this.log.debug(`creating element: ${tag}`);
481
+ this.el = document.createElement(tag);
482
+ } else throw new Error('no query or tag provided');
446
483
  if (this.el) {
447
484
  if (id) {
448
485
  this.log.debug(`setting id: ${id}`);
@@ -457,7 +494,12 @@ class dom_el {
457
494
  }
458
495
  if (parent) {
459
496
  this.log.debug("adding to parent");
460
- parent.appendChild(this.el);
497
+ let p = parent;
498
+ if ('string' == typeof parent) {
499
+ this.log.debug(`parent query: ${parent}`);
500
+ p = document.querySelector(parent);
501
+ }
502
+ p.appendChild(this.el);
461
503
  }
462
504
  }
463
505
  if (attrs) for (const [key, val] of Object.entries(attrs)){
package/dist/ls.js CHANGED
@@ -1,9 +1,9 @@
1
- function toKebab(str) {
1
+ function strings_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 += `${toKebab(k)}:${v};`);
6
+ Object.entries(style).forEach(([k, v])=>s += `${strings_toKebab(k)}:${v};`);
7
7
  return s;
8
8
  }
9
9
  function _define_property(obj, key, value) {
@@ -93,21 +93,29 @@ class dom_el {
93
93
  parent.appendChild(this.el);
94
94
  return this;
95
95
  }
96
+ append(ch) {
97
+ return this.child(ch);
98
+ }
96
99
  appendChild(ch) {
97
100
  return this.child(ch);
98
101
  }
99
102
  child(ch) {
100
103
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
101
- if (ch instanceof dom_el) this.el.appendChild(ch.el);
104
+ if ('string' == typeof ch) this.el.append(ch);
105
+ else if (ch instanceof dom_el) this.el.appendChild(ch.el);
102
106
  else this.el.appendChild(ch);
103
107
  return this;
104
108
  }
105
- prependChild(ch) {
109
+ prepend(ch) {
106
110
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
107
- if (ch instanceof dom_el) this.el.prepend(ch.el);
111
+ if ('string' == typeof ch) this.el.prepend(ch);
112
+ else if (ch instanceof dom_el) this.el.prepend(ch.el);
108
113
  else this.el.prepend(ch);
109
114
  return this;
110
115
  }
116
+ prependChild(ch) {
117
+ return this.prepend(ch);
118
+ }
111
119
  empty() {
112
120
  if (this.el) this.el.innerHTML = '';
113
121
  return this;
@@ -118,10 +126,29 @@ class dom_el {
118
126
  else this.el.innerHTML = content;
119
127
  return this;
120
128
  }
129
+ html(content) {
130
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
131
+ this.el.innerHTML = content;
132
+ }
121
133
  src(url) {
122
134
  if (this.el && 'src' in this.el) this.el.src = url;
123
135
  return this;
124
136
  }
137
+ attrs(attrs) {
138
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
139
+ for (const [k, v] of Object.entries(attrs))this.el.setAttribute(k, v);
140
+ return this;
141
+ }
142
+ attr(key, val) {
143
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
144
+ this.el.setAttribute(key, val);
145
+ return this;
146
+ }
147
+ removeAttr(key) {
148
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
149
+ this.el.removeAttribute(key);
150
+ return this;
151
+ }
125
152
  style(update, stringify = false) {
126
153
  if (this.el) {
127
154
  if ('string' == typeof update) this.el.style = update;
@@ -153,38 +180,23 @@ class dom_el {
153
180
  else for (const sc of className)this.el.classList.remove(sc);
154
181
  return this;
155
182
  }
156
- html(content) {
157
- if (!this.el) throw new Error(`no element from query: ${this.query}`);
158
- this.el.innerHTML = content;
159
- }
160
- render(vars = {}) {
161
- if (!this.el) throw new Error(`no element from query: ${this.query}`);
162
- try {
163
- return interpolate(this.el.innerHTML, vars);
164
- } catch (e) {
165
- throw new Error(`could not render template ${this.query}: ${e}`);
166
- }
167
- }
168
- appendTemplate(template, vars) {
169
- if (!this.el) throw new Error(`no element from query: ${this.query}`);
170
- if (!template.el) throw new Error("template does not contain element");
171
- const tmpl = template.render(vars);
172
- this.el.insertAdjacentHTML('beforeend', tmpl);
173
- }
174
- on(event, cb) {
183
+ on(event, cb, options) {
175
184
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
176
185
  if (!this.listeners[event]) this.listeners[event] = [];
177
- this.listeners[event].push(cb);
178
- this.el.addEventListener(event, cb);
186
+ this.listeners[event].push({
187
+ cb,
188
+ options
189
+ });
190
+ this.el.addEventListener(event, cb, options);
179
191
  return this;
180
192
  }
181
- listen(event, cb) {
182
- return this.on(event, cb);
193
+ listen(event, cb, options) {
194
+ return this.on(event, cb, options);
183
195
  }
184
196
  removeListeners(event) {
185
197
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
186
198
  if (!this.listeners[event]) return this;
187
- for (const cb of this.listeners[event])this.el.removeEventListener(event, cb);
199
+ for (const { cb, options } of this.listeners[event])this.el.removeEventListener(event, cb, options);
188
200
  this.listeners[event] = [];
189
201
  return this;
190
202
  }
@@ -204,7 +216,7 @@ class dom_el {
204
216
  this.el = opts;
205
217
  return;
206
218
  }
207
- const { query, element, type, class: styleClass, style, id, content, parent, attrs } = opts;
219
+ const { query, element, tag, class: styleClass, style, id, content, parent, attrs } = opts;
208
220
  if (query) {
209
221
  this.log.debug(`using query: ${query}`);
210
222
  this.query = query;
@@ -213,11 +225,11 @@ class dom_el {
213
225
  } else if (element) {
214
226
  this.log.debug(`using existing element: ${element}`);
215
227
  this.el = element;
216
- } else if (type) {
217
- this.query = type;
218
- this.log.debug(`creating element: ${type}`);
219
- this.el = document.createElement(type);
220
- } else throw new Error('no query or type provided');
228
+ } else if (tag) {
229
+ this.query = tag;
230
+ this.log.debug(`creating element: ${tag}`);
231
+ this.el = document.createElement(tag);
232
+ } else throw new Error('no query or tag provided');
221
233
  if (this.el) {
222
234
  if (id) {
223
235
  this.log.debug(`setting id: ${id}`);
@@ -232,7 +244,12 @@ class dom_el {
232
244
  }
233
245
  if (parent) {
234
246
  this.log.debug("adding to parent");
235
- parent.appendChild(this.el);
247
+ let p = parent;
248
+ if ('string' == typeof parent) {
249
+ this.log.debug(`parent query: ${parent}`);
250
+ p = document.querySelector(parent);
251
+ }
252
+ p.appendChild(this.el);
236
253
  }
237
254
  }
238
255
  if (attrs) for (const [key, val] of Object.entries(attrs)){
@@ -241,11 +258,6 @@ class dom_el {
241
258
  }
242
259
  }
243
260
  }
244
- function interpolate(str, params) {
245
- let names = Object.keys(params).map((k)=>`_${k}`);
246
- let vals = Object.values(params);
247
- return new Function(...names, `return \`${str.replace(/\$\{(\w*)\}/g, '${_$1}')}\`;`)(...vals);
248
- }
249
261
  function get(key, _default) {
250
262
  let ret = localStorage.getItem(key);
251
263
  if (null === ret && null != _default) {
package/dist/qr.js CHANGED
@@ -1904,12 +1904,12 @@ const QRErrorCorrectLevel = {
1904
1904
  Q: 3,
1905
1905
  H: 2
1906
1906
  };
1907
- function toKebab(str) {
1907
+ function strings_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 += `${toKebab(k)}:${v};`);
1912
+ Object.entries(style).forEach(([k, v])=>s += `${strings_toKebab(k)}:${v};`);
1913
1913
  return s;
1914
1914
  }
1915
1915
  function utils_define_property(obj, key, value) {
@@ -1999,21 +1999,29 @@ class dom_el {
1999
1999
  parent.appendChild(this.el);
2000
2000
  return this;
2001
2001
  }
2002
+ append(ch) {
2003
+ return this.child(ch);
2004
+ }
2002
2005
  appendChild(ch) {
2003
2006
  return this.child(ch);
2004
2007
  }
2005
2008
  child(ch) {
2006
2009
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
2007
- if (ch instanceof dom_el) this.el.appendChild(ch.el);
2010
+ if ('string' == typeof ch) this.el.append(ch);
2011
+ else if (ch instanceof dom_el) this.el.appendChild(ch.el);
2008
2012
  else this.el.appendChild(ch);
2009
2013
  return this;
2010
2014
  }
2011
- prependChild(ch) {
2015
+ prepend(ch) {
2012
2016
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
2013
- if (ch instanceof dom_el) this.el.prepend(ch.el);
2017
+ if ('string' == typeof ch) this.el.prepend(ch);
2018
+ else if (ch instanceof dom_el) this.el.prepend(ch.el);
2014
2019
  else this.el.prepend(ch);
2015
2020
  return this;
2016
2021
  }
2022
+ prependChild(ch) {
2023
+ return this.prepend(ch);
2024
+ }
2017
2025
  empty() {
2018
2026
  if (this.el) this.el.innerHTML = '';
2019
2027
  return this;
@@ -2024,10 +2032,29 @@ class dom_el {
2024
2032
  else this.el.innerHTML = content;
2025
2033
  return this;
2026
2034
  }
2035
+ html(content) {
2036
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
2037
+ this.el.innerHTML = content;
2038
+ }
2027
2039
  src(url) {
2028
2040
  if (this.el && 'src' in this.el) this.el.src = url;
2029
2041
  return this;
2030
2042
  }
2043
+ attrs(attrs) {
2044
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
2045
+ for (const [k, v] of Object.entries(attrs))this.el.setAttribute(k, v);
2046
+ return this;
2047
+ }
2048
+ attr(key, val) {
2049
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
2050
+ this.el.setAttribute(key, val);
2051
+ return this;
2052
+ }
2053
+ removeAttr(key) {
2054
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
2055
+ this.el.removeAttribute(key);
2056
+ return this;
2057
+ }
2031
2058
  style(update, stringify = false) {
2032
2059
  if (this.el) {
2033
2060
  if ('string' == typeof update) this.el.style = update;
@@ -2059,38 +2086,23 @@ class dom_el {
2059
2086
  else for (const sc of className)this.el.classList.remove(sc);
2060
2087
  return this;
2061
2088
  }
2062
- html(content) {
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) {
2089
+ on(event, cb, options) {
2081
2090
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
2082
2091
  if (!this.listeners[event]) this.listeners[event] = [];
2083
- this.listeners[event].push(cb);
2084
- this.el.addEventListener(event, cb);
2092
+ this.listeners[event].push({
2093
+ cb,
2094
+ options
2095
+ });
2096
+ this.el.addEventListener(event, cb, options);
2085
2097
  return this;
2086
2098
  }
2087
- listen(event, cb) {
2088
- return this.on(event, cb);
2099
+ listen(event, cb, options) {
2100
+ return this.on(event, cb, options);
2089
2101
  }
2090
2102
  removeListeners(event) {
2091
2103
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
2092
2104
  if (!this.listeners[event]) return this;
2093
- for (const cb of this.listeners[event])this.el.removeEventListener(event, cb);
2105
+ for (const { cb, options } of this.listeners[event])this.el.removeEventListener(event, cb, options);
2094
2106
  this.listeners[event] = [];
2095
2107
  return this;
2096
2108
  }
@@ -2110,7 +2122,7 @@ class dom_el {
2110
2122
  this.el = opts;
2111
2123
  return;
2112
2124
  }
2113
- const { query, element, type, class: styleClass, style, id, content, parent, attrs } = opts;
2125
+ const { query, element, tag, class: styleClass, style, id, content, parent, attrs } = opts;
2114
2126
  if (query) {
2115
2127
  this.log.debug(`using query: ${query}`);
2116
2128
  this.query = query;
@@ -2119,11 +2131,11 @@ class dom_el {
2119
2131
  } else if (element) {
2120
2132
  this.log.debug(`using existing element: ${element}`);
2121
2133
  this.el = element;
2122
- } else if (type) {
2123
- this.query = type;
2124
- this.log.debug(`creating element: ${type}`);
2125
- this.el = document.createElement(type);
2126
- } else throw new Error('no query or type provided');
2134
+ } else if (tag) {
2135
+ this.query = tag;
2136
+ this.log.debug(`creating element: ${tag}`);
2137
+ this.el = document.createElement(tag);
2138
+ } else throw new Error('no query or tag provided');
2127
2139
  if (this.el) {
2128
2140
  if (id) {
2129
2141
  this.log.debug(`setting id: ${id}`);
@@ -2138,7 +2150,12 @@ class dom_el {
2138
2150
  }
2139
2151
  if (parent) {
2140
2152
  this.log.debug("adding to parent");
2141
- parent.appendChild(this.el);
2153
+ let p = parent;
2154
+ if ('string' == typeof parent) {
2155
+ this.log.debug(`parent query: ${parent}`);
2156
+ p = document.querySelector(parent);
2157
+ }
2158
+ p.appendChild(this.el);
2142
2159
  }
2143
2160
  }
2144
2161
  if (attrs) for (const [key, val] of Object.entries(attrs)){
@@ -2147,11 +2164,6 @@ class dom_el {
2147
2164
  }
2148
2165
  }
2149
2166
  }
2150
- function interpolate(str, params) {
2151
- let names = Object.keys(params).map((k)=>`_${k}`);
2152
- let vals = Object.values(params);
2153
- return new Function(...names, `return \`${str.replace(/\$\{(\w*)\}/g, '${_$1}')}\`;`)(...vals);
2154
- }
2155
2167
  class QR {
2156
2168
  static render(config, element) {
2157
2169
  const settings = this.getDefaultSettings(config);
package/dist/style.d.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  **************/
4
4
  export declare function cssVar(name: string): string;
5
5
  export declare function render(style: Object): string;
6
+ export declare function inject(selector: string, style: Object): string;
6
7
  /**
7
8
  * Check if the current theme is dark
8
9
  */
package/dist/style.js CHANGED
@@ -10,6 +10,18 @@ function render(style) {
10
10
  Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
11
11
  return s;
12
12
  }
13
+ function inject(selector, style) {
14
+ const existing = document.getElementById(`corvid-injected-${encodeURIComponent(selector)}`);
15
+ if (existing) existing.remove();
16
+ const injected = document.createElement('style');
17
+ injected.id = `corvid-injected-${encodeURIComponent(selector)}`;
18
+ let s = `${selector} {\n`;
19
+ Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}: ${v};\n`);
20
+ s += '}';
21
+ injected.textContent = s;
22
+ document.head.appendChild(injected);
23
+ return s;
24
+ }
13
25
  function isDarkMode() {
14
26
  return window.matchMedia('(prefers-color-scheme: dark)').matches;
15
27
  }
@@ -34,4 +46,4 @@ function gradient(start, end, value) {
34
46
  const blue = Math.round(start.blue + (end.blue - start.blue) * value / 100);
35
47
  return `rgb(${red}, ${green}, ${blue})`;
36
48
  }
37
- export { cssVar, gradient, handleThemeSwitch, isDarkMode, onDarkMode, render, switchTheme };
49
+ export { cssVar, gradient, handleThemeSwitch, inject, isDarkMode, onDarkMode, render, switchTheme };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taybart/corvid",
3
- "version": "0.1.30",
3
+ "version": "0.2.0",
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
- "typescript": "^5.8.3"
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
+ }