@taybart/corvid 0.1.1 → 0.1.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/README.md CHANGED
@@ -2,5 +2,117 @@
2
2
 
3
3
  fear the crow
4
4
 
5
+ ![crowtein](https://github.com/user-attachments/assets/b3bbf267-d7b0-4116-80a5-b932b409a111)
5
6
 
6
- ![crowtein_2](https://github.com/user-attachments/assets/b3bbf267-d7b0-4116-80a5-b932b409a111)
7
+ ## Usage
8
+
9
+ Non-exhastive list of features
10
+
11
+ ### DOM
12
+
13
+ ```js
14
+ import { dom } from '@taybart/corvid'
15
+
16
+ dom.ready(() => {
17
+ // query for existing element
18
+ const username = new dom.el('#username')
19
+ // listen for events
20
+ username.on('click', () => {
21
+ // set style, will kebab keys backgroundColor -> background-color
22
+ username.style({ color: 'red', backgroundColor: 'yellow' })
23
+ // set/get content
24
+ username.content(`evil: ${username.value()}`)
25
+ }))
26
+
27
+
28
+ // create new elements
29
+ new dom.el({
30
+ type: 'div',
31
+ id: 'hair-color',
32
+ class: 'hair user-info',
33
+ content: 'blue',
34
+ // will append element to username
35
+ parent: username,
36
+ })
37
+
38
+ // listen for keys and check for modifiers
39
+ dom.onKey('E', ({ ctrl, alt, meta, shift }) => {
40
+ console.log('E pressed')
41
+ })
42
+
43
+ /*
44
+ * Given a template:
45
+ * <template id="tmpl-test">
46
+ * <div> hello ${name} </div>
47
+ * </template>
48
+ */
49
+ const tmpl = new dom.el('#tmpl-test')
50
+ // append template to el
51
+ username.appendTemplate(tmpl, { name: 'corvid' })
52
+ // or just set content
53
+ document.body.innerHTML = tmpl.render({ name: 'corvid' })
54
+ })
55
+ ```
56
+
57
+ ### LocalStorage
58
+
59
+ ```js
60
+ import { ls, dom } from '@taybart/corvid'
61
+
62
+ dom.ready(() => {
63
+ const hpStat = new dom.el({ query: '#stat-hp', content: ls.get('stats.hp') })
64
+ // set element content when localstorage changes
65
+ ls.listen('stats.hp', hpStat)
66
+ // or just a callback
67
+ ls.listen('stats.hp', ({ key, value }) => {
68
+ console.log(`health is now ${value}`)
69
+ })
70
+ // set a value (required if listening for events)
71
+ ls.set('stats.hp', ls.get('stats.hp') - 1))
72
+ // set a flattened object, will update "stats.hp" and "stats.attack"
73
+ ls.set({ stats: { hp: 100, attack: 10 } })
74
+ })
75
+ ```
76
+
77
+ ### Network
78
+
79
+ ```js
80
+ import { network } '@taybart/corvid'
81
+
82
+ // create an api client
83
+ const api = network.create({
84
+ url: 'https://api.example.com',
85
+ credentials: 'include',
86
+ success: 250, // odd success code
87
+ // corvid params, string, or custom object that has .toString() and renders url safe params
88
+ params: new network.params({hello: 'corvid'})
89
+ })
90
+
91
+ // make a request
92
+ const { username } = await api.do({
93
+ path: '/users/1',
94
+ override: {
95
+ params: network.params.render({hello: 'world!'}) , // only for this request
96
+ },
97
+ })
98
+
99
+
100
+ ```
101
+
102
+ ### Styles
103
+
104
+ ```js
105
+ import { style } '@taybart/corvid'
106
+
107
+ // query css media prefers-color-scheme
108
+ if (style.isDarkMode()) {
109
+ console.log('dark mode')
110
+ }
111
+ // listen for theme switch
112
+ style.onDarkMode((isDark) => {
113
+ // set document attribute 'data-theme'
114
+ style.switchTheme(isDark ? 'light' : 'dark')
115
+ // get css variables
116
+ console.log(`is dark mode: ${isDark} and background is ${style.cssVar('--color-bg')`)
117
+ })
118
+ ```
package/dist/dom.d.ts CHANGED
@@ -13,6 +13,7 @@ export declare function onKey(key: string, cb: (ev: {
13
13
  meta: boolean;
14
14
  shift: boolean;
15
15
  }) => void): void;
16
+ export declare function els(query: string, verbose?: boolean): el[];
16
17
  /*** element ***/
17
18
  type elOpts = {
18
19
  element?: HTMLElement;
@@ -28,6 +29,7 @@ export declare class el {
28
29
  el: HTMLElement | null;
29
30
  query: string;
30
31
  log: logger;
32
+ listeners: Record<string, Array<(ev: Event) => void>>;
31
33
  constructor(opts: HTMLElement | string | elOpts, verbose?: boolean);
32
34
  /*** dom manipulation ***/
33
35
  value(update?: string): string | el;
@@ -40,12 +42,24 @@ export declare class el {
40
42
  }): this;
41
43
  src(url: string): this;
42
44
  /*** Style ***/
43
- style(style: Object | string): this;
45
+ style(update: Object | string, stringify?: boolean): this | undefined;
46
+ hasClass(className: string): boolean;
44
47
  addClass(className: string): this;
45
48
  removeClass(className: string): this;
49
+ /*** Templates ***/
50
+ render(vars?: {}): string;
51
+ appendTemplate(template: el, vars: any): void;
46
52
  /*** Events ***/
47
53
  on(event: string, cb: (ev: Event) => void): this;
48
54
  listen(event: string, cb: (ev: Event) => void): this;
49
- onClick(cb: (ev: Event) => void): this;
55
+ removeListeners(event: string): this;
50
56
  }
57
+ /**
58
+ * Get a template from a string
59
+ * https://stackoverflow.com/a/41015840
60
+ * @param str The string to interpolate
61
+ * @param params The parameters
62
+ * @return The interpolated string
63
+ */
64
+ export declare function interpolate(str: string, params: Object): string;
51
65
  export {};
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js CHANGED
@@ -26,22 +26,26 @@ __webpack_require__.d(strings_namespaceObject, {
26
26
  bytesToHuman: ()=>bytesToHuman,
27
27
  toKebab: ()=>toKebab
28
28
  });
29
- var dom_namespaceObject = {};
30
- __webpack_require__.r(dom_namespaceObject);
31
- __webpack_require__.d(dom_namespaceObject, {
32
- el: ()=>dom_el,
33
- onKey: ()=>onKey,
34
- ready: ()=>ready
35
- });
36
29
  var style_namespaceObject = {};
37
30
  __webpack_require__.r(style_namespaceObject);
38
31
  __webpack_require__.d(style_namespaceObject, {
39
32
  cssVar: ()=>cssVar,
40
33
  gradient: ()=>gradient,
34
+ handleThemeSwitch: ()=>handleThemeSwitch,
41
35
  isDarkMode: ()=>isDarkMode,
42
36
  onDarkMode: ()=>onDarkMode,
37
+ render: ()=>render,
43
38
  switchTheme: ()=>switchTheme
44
39
  });
40
+ var dom_namespaceObject = {};
41
+ __webpack_require__.r(dom_namespaceObject);
42
+ __webpack_require__.d(dom_namespaceObject, {
43
+ el: ()=>dom_el,
44
+ els: ()=>els,
45
+ interpolate: ()=>interpolate,
46
+ onKey: ()=>onKey,
47
+ ready: ()=>ready
48
+ });
45
49
  var network_namespaceObject = {};
46
50
  __webpack_require__.r(network_namespaceObject);
47
51
  __webpack_require__.d(network_namespaceObject, {
@@ -53,9 +57,12 @@ __webpack_require__.d(network_namespaceObject, {
53
57
  var local_storage_namespaceObject = {};
54
58
  __webpack_require__.r(local_storage_namespaceObject);
55
59
  __webpack_require__.d(local_storage_namespaceObject, {
60
+ clear: ()=>clear,
56
61
  get: ()=>get,
57
62
  listen: ()=>listen,
58
- set: ()=>set
63
+ set: ()=>set,
64
+ setObj: ()=>setObj,
65
+ update: ()=>local_storage_update
59
66
  });
60
67
  function bytesToHuman(bytes, options = {}) {
61
68
  const { useSI = false, decimals = 2, includeUnits = true, targetUnit = null } = options;
@@ -102,6 +109,39 @@ function bytesToHuman(bytes, options = {}) {
102
109
  function toKebab(str) {
103
110
  return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, ofs)=>(ofs ? '-' : '') + s.toLowerCase());
104
111
  }
112
+ function cssVar(name) {
113
+ const style = window.getComputedStyle(document.body);
114
+ return style.getPropertyValue(name);
115
+ }
116
+ function render(style) {
117
+ let s = '';
118
+ Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
119
+ return s;
120
+ }
121
+ function isDarkMode() {
122
+ return window.matchMedia('(prefers-color-scheme: dark)').matches;
123
+ }
124
+ function onDarkMode(cb) {
125
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (ev)=>{
126
+ cb(ev.matches);
127
+ });
128
+ }
129
+ function switchTheme(theme) {
130
+ document.documentElement.setAttribute('data-theme', theme);
131
+ }
132
+ function handleThemeSwitch() {
133
+ switchTheme(isDarkMode() ? 'dark' : 'light');
134
+ onDarkMode((dark)=>{
135
+ switchTheme(dark ? 'dark' : 'light');
136
+ });
137
+ }
138
+ function gradient(start, end, value) {
139
+ value = Math.max(0, Math.min(100, value));
140
+ const red = Math.round(start.red + (end.red - start.red) * value / 100);
141
+ const green = Math.round(start.green + (end.green - start.green) * value / 100);
142
+ const blue = Math.round(start.blue + (end.blue - start.blue) * value / 100);
143
+ return `rgb(${red}, ${green}, ${blue})`;
144
+ }
105
145
  function _define_property(obj, key, value) {
106
146
  if (key in obj) Object.defineProperty(obj, key, {
107
147
  value: value,
@@ -212,15 +252,20 @@ function onKey(key, cb) {
212
252
  });
213
253
  });
214
254
  }
255
+ function els(query, verbose = false) {
256
+ return Array.from(document.querySelectorAll(query)).map((n)=>new dom_el(n, verbose));
257
+ }
215
258
  class dom_el {
216
259
  value(update) {
217
260
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
218
- if (update) {
261
+ if (void 0 !== update) {
219
262
  if ('value' in this.el) this.el.value = update;
220
263
  if ('src' in this.el) this.el.src = update;
221
264
  return this;
222
265
  }
223
266
  if ('value' in this.el) return this.el.value;
267
+ if ('innerText' in this.el) return this.el.innerText;
268
+ if ('innerHTML' in this.el) return this.el.innerHTML;
224
269
  this.log.warn(`element (${this.query}) does not contain value, returning empty string`);
225
270
  return '';
226
271
  }
@@ -252,17 +297,25 @@ class dom_el {
252
297
  if (this.el && 'src' in this.el) this.el.src = url;
253
298
  return this;
254
299
  }
255
- style(style) {
300
+ style(update, stringify = false) {
256
301
  if (this.el) {
257
- if ('string' == typeof style) this.el.style = style;
258
- else if ('object' == typeof style) {
259
- let s = '';
260
- Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
302
+ if ('string' == typeof update) this.el.style = update;
303
+ else if ('object' == typeof update) {
304
+ if (!stringify) {
305
+ for (const [k, v] of Object.entries(update))this.el.style[k] = v;
306
+ return;
307
+ }
308
+ const s = render(update);
309
+ this.log.debug(`set style: ${this.el.style} -> ${s}`);
261
310
  this.el.style = s;
262
311
  }
263
312
  }
264
313
  return this;
265
314
  }
315
+ hasClass(className) {
316
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
317
+ return this.el.classList.contains(className);
318
+ }
266
319
  addClass(className) {
267
320
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
268
321
  this.el.classList.add(className);
@@ -273,27 +326,52 @@ class dom_el {
273
326
  this.el.classList.remove(className);
274
327
  return this;
275
328
  }
329
+ render(vars = {}) {
330
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
331
+ try {
332
+ return interpolate(this.el.innerHTML, vars);
333
+ } catch (e) {
334
+ throw new Error(`could not render template ${this.query}: ${e}`);
335
+ }
336
+ }
337
+ appendTemplate(template, vars) {
338
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
339
+ if (!template.el) throw new Error("template does not contain element");
340
+ const tmpl = template.render(vars);
341
+ this.el.insertAdjacentHTML('beforeend', tmpl);
342
+ }
276
343
  on(event, cb) {
277
344
  if (!this.el) throw new Error(`no element from query: ${this.query}`);
345
+ if (!this.listeners[event]) this.listeners[event] = [];
346
+ this.listeners[event].push(cb);
278
347
  this.el.addEventListener(event, cb);
279
348
  return this;
280
349
  }
281
350
  listen(event, cb) {
282
351
  return this.on(event, cb);
283
352
  }
284
- onClick(cb) {
285
- return this.on('click', cb);
353
+ removeListeners(event) {
354
+ if (!this.el) throw new Error(`no element from query: ${this.query}`);
355
+ for (const cb of this.listeners[event])this.el.removeEventListener(event, cb);
356
+ this.listeners[event] = [];
357
+ return this;
286
358
  }
287
359
  constructor(opts, verbose = false){
288
360
  dom_define_property(this, "el", void 0);
289
361
  dom_define_property(this, "query", '');
290
362
  dom_define_property(this, "log", void 0);
363
+ dom_define_property(this, "listeners", {});
291
364
  this.log = new logger(verbose ? utils_logLevel.debug : utils_logLevel.none, 'element');
292
365
  if ('string' == typeof opts) {
293
366
  this.query = opts;
294
367
  this.el = document.querySelector(opts);
295
368
  return;
296
369
  }
370
+ if (opts instanceof HTMLElement) {
371
+ this.log.debug(`using existing element: ${opts}`);
372
+ this.el = opts;
373
+ return;
374
+ }
297
375
  const { query, element, type, class: styleClass, style, id, content, parent } = opts;
298
376
  if (query) {
299
377
  this.log.debug(`using query: ${query}`);
@@ -304,6 +382,7 @@ class dom_el {
304
382
  this.log.debug(`using existing element: ${element}`);
305
383
  this.el = element;
306
384
  } else if (type) {
385
+ this.query = type;
307
386
  this.log.debug(`creating element: ${type}`);
308
387
  this.el = document.createElement(type);
309
388
  } else throw new Error('no query or type provided');
@@ -325,27 +404,10 @@ class dom_el {
325
404
  }
326
405
  }
327
406
  }
328
- function cssVar(name) {
329
- const style = window.getComputedStyle(document.body);
330
- return style.getPropertyValue(name);
331
- }
332
- function isDarkMode() {
333
- return window.matchMedia('(prefers-color-scheme: dark)').matches;
334
- }
335
- function onDarkMode(cb) {
336
- window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (ev)=>{
337
- cb(ev.matches);
338
- });
339
- }
340
- function switchTheme(theme) {
341
- document.documentElement.setAttribute('data-theme', theme);
342
- }
343
- function gradient(start, end, value) {
344
- value = Math.max(0, Math.min(100, value));
345
- const red = Math.round(start.red + (end.red - start.red) * value / 100);
346
- const green = Math.round(start.green + (end.green - start.green) * value / 100);
347
- const blue = Math.round(start.blue + (end.blue - start.blue) * value / 100);
348
- return `rgb(${red}, ${green}, ${blue})`;
407
+ function interpolate(str, params) {
408
+ let names = Object.keys(params).map((k)=>`_${k}`);
409
+ let vals = Object.values(params);
410
+ return new Function(...names, `return \`${str.replace(/\$\{(\w*)\}/g, '${_$1}')}\`;`)(...vals);
349
411
  }
350
412
  function network_define_property(obj, key, value) {
351
413
  if (key in obj) Object.defineProperty(obj, key, {
@@ -437,47 +499,54 @@ class request {
437
499
  class ws {
438
500
  setup() {
439
501
  this.recursion_level += 1;
502
+ if (this.ws) for(let key in this.event_listeners)this.event_listeners[key].forEach((cb)=>{
503
+ this.ws.removeEventListener(key, cb);
504
+ });
440
505
  this.ws = new WebSocket(this.url);
441
506
  this.backoff = 100;
442
507
  this.ws.addEventListener('open', ()=>{
443
508
  const rl = this.recursion_level;
444
509
  this.log.debug(`on open: reconnected (${rl})`);
445
510
  this.is_connected = true;
511
+ if (!this.ws) return;
446
512
  for(let key in this.event_listeners)this.event_listeners[key].forEach((cb)=>{
447
- this.log.debug(`adding listener (${rl}): ${key}`);
448
- this.ws.addEventListener(key, cb);
513
+ if (this.ws) {
514
+ this.log.debug(`adding listener (${rl}): ${key}`);
515
+ this.ws.addEventListener(key, cb);
516
+ }
449
517
  });
450
518
  });
451
519
  this.ws.addEventListener('close', ()=>{
452
520
  this.log.debug('connection closed');
453
521
  this.is_connected = false;
454
522
  this.backoff = Math.min(2 * this.backoff, this.max_timeout);
455
- this.log.debug('backoff: ' + this.backoff);
456
- setTimeout(()=>{
523
+ this.log.debug(`backoff: ${this.backoff}`);
524
+ this.reconnect_timer = window.setTimeout(()=>{
457
525
  if (this.should_reconnect) {
458
526
  this.ws = null;
459
527
  this.setup();
460
528
  }
461
529
  }, this.backoff + 50 * Math.random());
462
530
  });
531
+ this.ws.addEventListener('error', this.log.error);
463
532
  }
464
533
  send(data) {
465
534
  if (!this.is_connected || !this.ws) throw new Error('not connected');
466
- this.ws.send(data);
535
+ this.ws.send(JSON.stringify(data));
467
536
  }
468
537
  onMessage(cb) {
469
538
  if (!this.ws) throw new Error('ws is null');
470
539
  if (!this.event_listeners.message) this.event_listeners.message = [];
471
- this.event_listeners.message.push((e)=>{
472
- const rl = this.recursion_level;
473
- this.log.debug(`message(${rl}): ${e.data}`);
474
- cb(e.data);
475
- });
476
- this.ws.addEventListener('message', (e)=>{
540
+ const handler = (e)=>{
477
541
  const rl = this.recursion_level;
478
542
  this.log.debug(`message(${rl}): ${e.data}`);
479
543
  cb(e.data);
480
- });
544
+ };
545
+ this.event_listeners.message.push(handler);
546
+ this.ws.addEventListener('message', handler);
547
+ }
548
+ onJSON(cb) {
549
+ this.onMessage((d)=>cb(JSON.parse(d)));
481
550
  }
482
551
  on(event, cb) {
483
552
  if (!this.ws) throw new Error('ws is null');
@@ -486,6 +555,7 @@ class ws {
486
555
  this.ws.addEventListener(event, cb);
487
556
  }
488
557
  close() {
558
+ if (this.reconnect_timer) clearTimeout(this.reconnect_timer);
489
559
  if (!this.is_connected || !this.ws) return;
490
560
  this.should_reconnect = false;
491
561
  this.ws.close();
@@ -493,11 +563,12 @@ class ws {
493
563
  constructor(url, verbose = false){
494
564
  network_define_property(this, "url", void 0);
495
565
  network_define_property(this, "ws", void 0);
496
- network_define_property(this, "backoff", 50);
566
+ network_define_property(this, "backoff", 100);
497
567
  network_define_property(this, "max_timeout", 10000);
498
568
  network_define_property(this, "should_reconnect", true);
499
569
  network_define_property(this, "is_connected", false);
500
570
  network_define_property(this, "recursion_level", 0);
571
+ network_define_property(this, "reconnect_timer", null);
501
572
  network_define_property(this, "log", void 0);
502
573
  network_define_property(this, "event_listeners", {});
503
574
  this.url = url;
@@ -525,10 +596,31 @@ class refresh {
525
596
  this.url = url;
526
597
  }
527
598
  }
528
- function get(key) {
529
- return localStorage.getItem(key);
599
+ function get(key, _default) {
600
+ let ret = localStorage.getItem(key);
601
+ if (!ret && _default) {
602
+ ret = _default;
603
+ if ('function' == typeof _default) ret = _default();
604
+ set(key, ret);
605
+ }
606
+ return ret;
607
+ }
608
+ function local_storage_update(key, update1, broadcast = false) {
609
+ const prev = get(key);
610
+ const value = update1(prev);
611
+ if (prev !== value || broadcast) {
612
+ const event = new CustomEvent('@corvid/ls-update', {
613
+ detail: {
614
+ key,
615
+ value
616
+ }
617
+ });
618
+ document.dispatchEvent(event);
619
+ }
620
+ localStorage.setItem(key, value);
530
621
  }
531
622
  function set(key, value, broadcast = false) {
623
+ if ('object' == typeof key) return void setObj(key, value, broadcast);
532
624
  const prev = get(key);
533
625
  if (prev !== value || broadcast) {
534
626
  const event = new CustomEvent('@corvid/ls-update', {
@@ -541,6 +633,21 @@ function set(key, value, broadcast = false) {
541
633
  }
542
634
  localStorage.setItem(key, value);
543
635
  }
636
+ function setObj(update, prefix, broadcast = false) {
637
+ const flatten = (ob)=>{
638
+ const ret = {};
639
+ for(let i in ob)if (ob.hasOwnProperty(i)) if ('object' == typeof ob[i] && null !== ob[i]) {
640
+ const flat = flatten(ob[i]);
641
+ for(let x in flat)if (flat.hasOwnProperty(x)) ret[`${i}.${x}`] = flat[x];
642
+ } else ret[i] = ob[i];
643
+ return ret;
644
+ };
645
+ for (let [k, v] of Object.entries(flatten(update))){
646
+ let key = k;
647
+ if (prefix) key = `${prefix}.${k}`;
648
+ set(key, v, broadcast);
649
+ }
650
+ }
544
651
  function listen(key, cb) {
545
652
  document.addEventListener('@corvid/ls-update', (ev)=>{
546
653
  if (ev.detail.key === key || '*' === key) {
@@ -555,4 +662,7 @@ function listen(key, cb) {
555
662
  }
556
663
  });
557
664
  }
665
+ function clear(key) {
666
+ localStorage.removeItem(key);
667
+ }
558
668
  export { clipboard, dom_namespaceObject as dom, genID, utils_logLevel as logLevel, logger, local_storage_namespaceObject as ls, network_namespaceObject as network, strings_namespaceObject as strings, style_namespaceObject as style };
@@ -1,7 +1,10 @@
1
1
  import { el } from './dom';
2
- export declare function get(key: string): any;
3
- export declare function set(key: string, value: any, broadcast?: boolean): void;
2
+ export declare function get(key: string, _default?: any): any;
3
+ export declare function update(key: string, update: (current: any) => any, broadcast?: boolean): void;
4
+ export declare function set(key: string | object, value: any, broadcast?: boolean): void;
5
+ export declare function setObj(update: object, prefix?: string, broadcast?: boolean): void;
4
6
  export declare function listen(key: string, cb: (update: {
5
7
  key: string;
6
8
  value: any;
7
9
  }) => void | el): void;
10
+ export declare function clear(key: string): void;
package/dist/network.d.ts CHANGED
@@ -44,12 +44,14 @@ export declare class ws {
44
44
  should_reconnect: boolean;
45
45
  is_connected: boolean;
46
46
  recursion_level: number;
47
+ reconnect_timer: number | null;
47
48
  log: logger;
48
49
  event_listeners: Record<string, Array<(data: any) => void>>;
49
50
  constructor(url: string, verbose?: boolean);
50
51
  setup(): void;
51
52
  send(data: any): void;
52
53
  onMessage(cb: (data: any) => void): void;
54
+ onJSON(cb: (data: any) => void): void;
53
55
  on(event: string, cb: (data: any) => void): void;
54
56
  close(): void;
55
57
  }
package/dist/qr.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ interface QRCodeConfig {
2
+ text: string;
3
+ size?: number;
4
+ ecLevel?: 'L' | 'M' | 'Q' | 'H';
5
+ minVersion?: number;
6
+ maxVersion?: number;
7
+ quiet?: number;
8
+ radius?: number;
9
+ background?: string | null;
10
+ fill?: string | GradientFill;
11
+ left?: number;
12
+ top?: number;
13
+ }
14
+ interface GradientFill {
15
+ type: 'linear-gradient' | 'radial-gradient';
16
+ position: number[];
17
+ colorStops: Array<[number, string]>;
18
+ }
19
+ export default class QrCreator {
20
+ static render(config: QRCodeConfig, element: HTMLElement | HTMLCanvasElement): void;
21
+ }
22
+ export {};
File without changes
package/dist/style.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  * Style *
3
3
  **************/
4
4
  export declare function cssVar(name: string): string;
5
+ export declare function render(style: Object): string;
5
6
  /**
6
7
  * Check if the current theme is dark
7
8
  */
@@ -16,6 +17,10 @@ export declare function onDarkMode(cb: (isDark: boolean) => void): void;
16
17
  * @param theme - 'light' or 'dark'
17
18
  */
18
19
  export declare function switchTheme(theme: string): void;
20
+ /**
21
+ * Listen for changes in the dark mode preference
22
+ */
23
+ export declare function handleThemeSwitch(): void;
19
24
  /**
20
25
  * Calculate a color gradient
21
26
  * @param start - The starting color
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taybart/corvid",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
@@ -15,7 +15,12 @@
15
15
  "dist"
16
16
  ],
17
17
  "devDependencies": {
18
+ "@happy-dom/global-registrator": "^17.4.7",
18
19
  "@rslib/core": "^0.6.2",
20
+ "@testing-library/dom": "^10.4.0",
21
+ "@testing-library/jest-dom": "^6.6.3",
22
+ "@types/bun": "^1.2.13",
23
+ "@types/jsdom": "^21.1.7",
19
24
  "@types/node": "^22.8.1",
20
25
  "typescript": "^5.8.3"
21
26
  },