@taybart/corvid 0.1.17 → 0.1.19

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
@@ -1,8 +1,11 @@
1
1
  # Corvid
2
2
 
3
- fear the crow
3
+ <p align="center"><img src="https://github.com/user-attachments/assets/b3bbf267-d7b0-4116-80a5-b932b409a111" width="100" height="100"></p>
4
4
 
5
- ![crowtein](https://github.com/user-attachments/assets/b3bbf267-d7b0-4116-80a5-b932b409a111)
5
+ <p align="center">fear the crow</p>
6
+
7
+
8
+ <!-- ![crowtein](https://github.com/user-attachments/assets/b3bbf267-d7b0-4116-80a5-b932b409a111) -->
6
9
 
7
10
  ## Usage
8
11
 
@@ -83,7 +86,7 @@ import { network } '@taybart/corvid'
83
86
  const api = network.create({
84
87
  url: 'https://api.example.com',
85
88
  credentials: 'include',
86
- success: 250, // odd success code
89
+ success: 250, // check for non-200 success code
87
90
  // corvid params, string, or custom object that has .toString() and renders url safe params
88
91
  params: new network.params({hello: 'corvid'})
89
92
  })
@@ -115,15 +118,27 @@ style.onDarkMode((isDark) => {
115
118
  // get css variables
116
119
  console.log(`is dark mode: ${isDark} and background is ${style.cssVar('--color-bg')`)
117
120
  })
121
+
122
+ ```
123
+
124
+ Just handle switching automatically
125
+
126
+ ```html
127
+ <script type='module'>
128
+ import { handleThemeSwitch } from '@taybart/corvid/style'
129
+ handleThemeSwitch()
130
+ </script>
118
131
  ```
119
132
 
120
133
  ### QR
121
134
 
122
135
  ```js
136
+ import { dom } from '@taybart/corvid'
123
137
  import { QR } '@taybart/corvid/qr'
124
138
 
139
+ const el = new dom.el('#qr')
125
140
  QR.render({
126
141
  text: 'https://example.com',
127
142
  size: 200,
128
- }, document.getElementById('qr'))
143
+ }, el) // can also be regular element query -> document.getElementById('qr')
129
144
  ```
package/dist/dom.d.ts CHANGED
@@ -25,6 +25,7 @@ type elOpts = {
25
25
  style?: Object;
26
26
  id?: string;
27
27
  parent?: HTMLElement | el;
28
+ attrs?: Object;
28
29
  };
29
30
  export declare class el {
30
31
  el: HTMLElement | null;
package/dist/dom.js CHANGED
@@ -233,7 +233,7 @@ class dom_el {
233
233
  this.el = opts;
234
234
  return;
235
235
  }
236
- const { query, element, type, class: styleClass, style, id, content, parent } = opts;
236
+ const { query, element, type, class: styleClass, style, id, content, parent, attrs } = opts;
237
237
  if (query) {
238
238
  this.log.debug(`using query: ${query}`);
239
239
  this.query = query;
@@ -264,6 +264,10 @@ class dom_el {
264
264
  parent.appendChild(this.el);
265
265
  }
266
266
  }
267
+ if (attrs) for (const [key, val] of Object.entries(attrs)){
268
+ this.log.debug(`setting prop: ${key} to ${val}`);
269
+ this.el.setAttribute(key, val);
270
+ }
267
271
  }
268
272
  }
269
273
  function interpolate(str, params) {
package/dist/index.js CHANGED
@@ -62,9 +62,11 @@ __webpack_require__.r(local_storage_namespaceObject);
62
62
  __webpack_require__.d(local_storage_namespaceObject, {
63
63
  clear: ()=>clear,
64
64
  get: ()=>get,
65
+ getJSON: ()=>getJSON,
65
66
  listen: ()=>listen,
66
67
  set: ()=>set,
67
68
  setObj: ()=>setObj,
69
+ unlisten: ()=>unlisten,
68
70
  update: ()=>local_storage_update
69
71
  });
70
72
  function bytesToHuman(bytes, options = {}) {
@@ -411,7 +413,7 @@ class dom_el {
411
413
  this.el = opts;
412
414
  return;
413
415
  }
414
- const { query, element, type, class: styleClass, style, id, content, parent } = opts;
416
+ const { query, element, type, class: styleClass, style, id, content, parent, attrs } = opts;
415
417
  if (query) {
416
418
  this.log.debug(`using query: ${query}`);
417
419
  this.query = query;
@@ -442,6 +444,10 @@ class dom_el {
442
444
  parent.appendChild(this.el);
443
445
  }
444
446
  }
447
+ if (attrs) for (const [key, val] of Object.entries(attrs)){
448
+ this.log.debug(`setting prop: ${key} to ${val}`);
449
+ this.el.setAttribute(key, val);
450
+ }
445
451
  }
446
452
  }
447
453
  function interpolate(str, params) {
@@ -487,10 +493,8 @@ class network_params {
487
493
  }
488
494
  }
489
495
  class request {
490
- auth(token) {
491
- const header = `Bearer ${token}`;
492
- this.log.debug(`adding auth token header ${header}`);
493
- this.opts.headers.Authorization = header;
496
+ auth(a) {
497
+ this.opts.auth = a;
494
498
  return this;
495
499
  }
496
500
  basicAuth(username, password) {
@@ -504,7 +508,7 @@ class request {
504
508
  return this;
505
509
  }
506
510
  build({ path, params: passedParams, override } = {}) {
507
- if (this.opts.auth && !this.opts.headers.Authorization) if ('string' == typeof this.opts.auth) this.opts.headers.Authorization = `Bearer ${this.opts.auth}`;
511
+ if (this.opts.auth) if ('string' == typeof this.opts.auth) this.opts.headers.Authorization = `Bearer ${this.opts.auth}`;
508
512
  else this.opts.headers.Authorization = `Basic ${btoa(`${this.opts.auth.username}:${this.opts.auth.password}`)}`;
509
513
  if (!override) override = {};
510
514
  const body = override.body || this.opts.body;
@@ -533,7 +537,7 @@ class request {
533
537
  }
534
538
  };
535
539
  }
536
- async do({ path, params: passedParams, override = {} } = {}) {
540
+ async do({ path, params: passedParams, override = {}, _recurselevel = 0 } = {}) {
537
541
  const { url, options } = this.build({
538
542
  path,
539
543
  params: passedParams,
@@ -544,7 +548,15 @@ class request {
544
548
  const expect = override.expect || this.opts.expect;
545
549
  if (res.status !== expect) {
546
550
  const body = await res.text();
547
- throw new Error(`bad response ${res.status} !== ${expect}, body: ${body}`);
551
+ if (401 === res.status && this.opts.onUnauthorized && _recurselevel < 1) {
552
+ this.log.warn("unauthorized");
553
+ if (await this.opts.onUnauthorized.call(this, this, body)) return this.do({
554
+ path,
555
+ params: passedParams,
556
+ override,
557
+ _recurselevel: _recurselevel + 1
558
+ });
559
+ } else throw new Error(`bad response ${res.status} !== ${expect}, body: ${body}`);
548
560
  }
549
561
  this.log.debug(`content type: ${res.headers.get('content-type')}`);
550
562
  if ('application/json' === res.headers.get('content-type')) return await res.json();
@@ -565,6 +577,7 @@ class request {
565
577
  this.log.debug("converting object params to class");
566
578
  this.opts.params = new network_params(this.opts.params);
567
579
  }
580
+ if (!this.opts.fetch) this.opts.fetch = window.fetch;
568
581
  this.log.debug(`with options: ${JSON.stringify(this.opts)}`);
569
582
  }
570
583
  }
@@ -683,6 +696,11 @@ function get(key, _default) {
683
696
  }
684
697
  return ret;
685
698
  }
699
+ function getJSON(key, _default) {
700
+ const val = get(key, _default);
701
+ if (null === val) return null;
702
+ return JSON.parse(val);
703
+ }
686
704
  function local_storage_update(key, update1, broadcast = false) {
687
705
  const prev = get(key);
688
706
  const value = update1(prev);
@@ -708,6 +726,7 @@ function set(key, value, broadcast = false) {
708
726
  });
709
727
  document.dispatchEvent(event);
710
728
  }
729
+ if ('object' == typeof value) value = JSON.stringify(value);
711
730
  localStorage.setItem(key, value);
712
731
  }
713
732
  function setObj(update, prefix, broadcast = false) {
@@ -725,8 +744,9 @@ function setObj(update, prefix, broadcast = false) {
725
744
  set(key, v, broadcast);
726
745
  }
727
746
  }
747
+ const listeners = new Map();
728
748
  function listen(key, cb) {
729
- document.addEventListener('@corvid/ls-update', (ev)=>{
749
+ const listener = (ev)=>{
730
750
  if (ev.detail.key === key || '*' === key) {
731
751
  if (cb instanceof dom_el) {
732
752
  if (ev.detail.key === key) cb.content(ev.detail.value);
@@ -737,7 +757,19 @@ function listen(key, cb) {
737
757
  value: ev.detail.value
738
758
  });
739
759
  }
740
- });
760
+ };
761
+ if (!listeners.has(key)) listeners.set(key, new Map());
762
+ listeners.get(key).set(cb, listener);
763
+ document.addEventListener('@corvid/ls-update', listener);
764
+ }
765
+ function unlisten(key, cb) {
766
+ const keyListeners = listeners.get(key);
767
+ if (!keyListeners) return;
768
+ const listener = keyListeners.get(cb);
769
+ if (!listener) return;
770
+ document.removeEventListener('@corvid/ls-update', listener);
771
+ keyListeners.delete(cb);
772
+ if (0 === keyListeners.size) listeners.delete(key);
741
773
  }
742
774
  function clear(key) {
743
775
  localStorage.removeItem(key);
@@ -1,5 +1,6 @@
1
1
  import { el } from './dom';
2
2
  export declare function get(key: string, _default?: any): any;
3
+ export declare function getJSON(key: string, _default?: any): any;
3
4
  export declare function update(key: string, update: (current: any) => any, broadcast?: boolean): void;
4
5
  export declare function set(key: string, value: any, broadcast?: boolean): void;
5
6
  export declare function setObj(update: object, prefix?: string, broadcast?: boolean): void;
@@ -7,4 +8,8 @@ export declare function listen(key: string, cb: (update: {
7
8
  key: string;
8
9
  value: any;
9
10
  }) => void | el): void;
11
+ export declare function unlisten(key: string, cb: (update: {
12
+ key: string;
13
+ value: any;
14
+ }) => void | el): void;
10
15
  export declare function clear(key: string): void;
package/dist/ls.js CHANGED
@@ -204,7 +204,7 @@ class dom_el {
204
204
  this.el = opts;
205
205
  return;
206
206
  }
207
- const { query, element, type, class: styleClass, style, id, content, parent } = opts;
207
+ const { query, element, type, class: styleClass, style, id, content, parent, attrs } = opts;
208
208
  if (query) {
209
209
  this.log.debug(`using query: ${query}`);
210
210
  this.query = query;
@@ -235,6 +235,10 @@ class dom_el {
235
235
  parent.appendChild(this.el);
236
236
  }
237
237
  }
238
+ if (attrs) for (const [key, val] of Object.entries(attrs)){
239
+ this.log.debug(`setting prop: ${key} to ${val}`);
240
+ this.el.setAttribute(key, val);
241
+ }
238
242
  }
239
243
  }
240
244
  function interpolate(str, params) {
@@ -251,6 +255,11 @@ function get(key, _default) {
251
255
  }
252
256
  return ret;
253
257
  }
258
+ function getJSON(key, _default) {
259
+ const val = get(key, _default);
260
+ if (null === val) return null;
261
+ return JSON.parse(val);
262
+ }
254
263
  function local_storage_update(key, update1, broadcast = false) {
255
264
  const prev = get(key);
256
265
  const value = update1(prev);
@@ -276,6 +285,7 @@ function set(key, value, broadcast = false) {
276
285
  });
277
286
  document.dispatchEvent(event);
278
287
  }
288
+ if ('object' == typeof value) value = JSON.stringify(value);
279
289
  localStorage.setItem(key, value);
280
290
  }
281
291
  function setObj(update, prefix, broadcast = false) {
@@ -293,8 +303,9 @@ function setObj(update, prefix, broadcast = false) {
293
303
  set(key, v, broadcast);
294
304
  }
295
305
  }
306
+ const listeners = new Map();
296
307
  function listen(key, cb) {
297
- document.addEventListener('@corvid/ls-update', (ev)=>{
308
+ const listener = (ev)=>{
298
309
  if (ev.detail.key === key || '*' === key) {
299
310
  if (cb instanceof dom_el) {
300
311
  if (ev.detail.key === key) cb.content(ev.detail.value);
@@ -305,9 +316,21 @@ function listen(key, cb) {
305
316
  value: ev.detail.value
306
317
  });
307
318
  }
308
- });
319
+ };
320
+ if (!listeners.has(key)) listeners.set(key, new Map());
321
+ listeners.get(key).set(cb, listener);
322
+ document.addEventListener('@corvid/ls-update', listener);
323
+ }
324
+ function unlisten(key, cb) {
325
+ const keyListeners = listeners.get(key);
326
+ if (!keyListeners) return;
327
+ const listener = keyListeners.get(cb);
328
+ if (!listener) return;
329
+ document.removeEventListener('@corvid/ls-update', listener);
330
+ keyListeners.delete(cb);
331
+ if (0 === keyListeners.size) listeners.delete(key);
309
332
  }
310
333
  function clear(key) {
311
334
  localStorage.removeItem(key);
312
335
  }
313
- export { clear, get, listen, set, setObj, local_storage_update as update };
336
+ export { clear, get, getJSON, listen, set, setObj, unlisten, local_storage_update as update };
package/dist/network.d.ts CHANGED
@@ -22,12 +22,14 @@ export type requestOpts = {
22
22
  expect?: number;
23
23
  credentials?: RequestCredentials;
24
24
  insecureNoVerify?: boolean;
25
+ onUnauthorized?: (client: request, body: any) => Promise<boolean>;
26
+ fetch?: (url: string, init: RequestInit) => Promise<any>;
25
27
  };
26
28
  export declare class request {
27
29
  opts: requestOpts;
28
30
  log: logger;
29
31
  constructor(opts?: requestOpts, verbose?: boolean);
30
- auth(token: string | {
32
+ auth(a: string | {
31
33
  username: string;
32
34
  password: string;
33
35
  }): this;
@@ -60,7 +62,7 @@ export declare class request {
60
62
  body: string;
61
63
  };
62
64
  };
63
- do({ path, params: passedParams, override, }?: {
65
+ do({ path, params: passedParams, override, _recurselevel, }?: {
64
66
  path?: string;
65
67
  params?: Object;
66
68
  method?: string;
@@ -71,6 +73,7 @@ export declare class request {
71
73
  body?: Object;
72
74
  expect?: number;
73
75
  };
76
+ _recurselevel?: number;
74
77
  }): Promise<any>;
75
78
  }
76
79
  /*** websocket ***/
package/dist/network.js CHANGED
@@ -84,10 +84,8 @@ class network_params {
84
84
  }
85
85
  }
86
86
  class request {
87
- auth(token) {
88
- const header = `Bearer ${token}`;
89
- this.log.debug(`adding auth token header ${header}`);
90
- this.opts.headers.Authorization = header;
87
+ auth(a) {
88
+ this.opts.auth = a;
91
89
  return this;
92
90
  }
93
91
  basicAuth(username, password) {
@@ -101,7 +99,7 @@ class request {
101
99
  return this;
102
100
  }
103
101
  build({ path, params: passedParams, override } = {}) {
104
- if (this.opts.auth && !this.opts.headers.Authorization) if ('string' == typeof this.opts.auth) this.opts.headers.Authorization = `Bearer ${this.opts.auth}`;
102
+ if (this.opts.auth) if ('string' == typeof this.opts.auth) this.opts.headers.Authorization = `Bearer ${this.opts.auth}`;
105
103
  else this.opts.headers.Authorization = `Basic ${btoa(`${this.opts.auth.username}:${this.opts.auth.password}`)}`;
106
104
  if (!override) override = {};
107
105
  const body = override.body || this.opts.body;
@@ -130,7 +128,7 @@ class request {
130
128
  }
131
129
  };
132
130
  }
133
- async do({ path, params: passedParams, override = {} } = {}) {
131
+ async do({ path, params: passedParams, override = {}, _recurselevel = 0 } = {}) {
134
132
  const { url, options } = this.build({
135
133
  path,
136
134
  params: passedParams,
@@ -141,7 +139,15 @@ class request {
141
139
  const expect = override.expect || this.opts.expect;
142
140
  if (res.status !== expect) {
143
141
  const body = await res.text();
144
- throw new Error(`bad response ${res.status} !== ${expect}, body: ${body}`);
142
+ if (401 === res.status && this.opts.onUnauthorized && _recurselevel < 1) {
143
+ this.log.warn("unauthorized");
144
+ if (await this.opts.onUnauthorized.call(this, this, body)) return this.do({
145
+ path,
146
+ params: passedParams,
147
+ override,
148
+ _recurselevel: _recurselevel + 1
149
+ });
150
+ } else throw new Error(`bad response ${res.status} !== ${expect}, body: ${body}`);
145
151
  }
146
152
  this.log.debug(`content type: ${res.headers.get('content-type')}`);
147
153
  if ('application/json' === res.headers.get('content-type')) return await res.json();
@@ -162,6 +168,7 @@ class request {
162
168
  this.log.debug("converting object params to class");
163
169
  this.opts.params = new network_params(this.opts.params);
164
170
  }
171
+ if (!this.opts.fetch) this.opts.fetch = window.fetch;
165
172
  this.log.debug(`with options: ${JSON.stringify(this.opts)}`);
166
173
  }
167
174
  }
package/dist/qr.js CHANGED
@@ -2110,7 +2110,7 @@ class dom_el {
2110
2110
  this.el = opts;
2111
2111
  return;
2112
2112
  }
2113
- const { query, element, type, class: styleClass, style, id, content, parent } = opts;
2113
+ const { query, element, type, class: styleClass, style, id, content, parent, attrs } = opts;
2114
2114
  if (query) {
2115
2115
  this.log.debug(`using query: ${query}`);
2116
2116
  this.query = query;
@@ -2141,6 +2141,10 @@ class dom_el {
2141
2141
  parent.appendChild(this.el);
2142
2142
  }
2143
2143
  }
2144
+ if (attrs) for (const [key, val] of Object.entries(attrs)){
2145
+ this.log.debug(`setting prop: ${key} to ${val}`);
2146
+ this.el.setAttribute(key, val);
2147
+ }
2144
2148
  }
2145
2149
  }
2146
2150
  function interpolate(str, params) {
package/dist/style.js ADDED
@@ -0,0 +1,37 @@
1
+ function toKebab(str) {
2
+ return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, ofs)=>(ofs ? '-' : '') + s.toLowerCase());
3
+ }
4
+ function cssVar(name) {
5
+ const style = window.getComputedStyle(document.body);
6
+ return style.getPropertyValue(name);
7
+ }
8
+ function render(style) {
9
+ let s = '';
10
+ Object.entries(style).forEach(([k, v])=>s += `${toKebab(k)}:${v};`);
11
+ return s;
12
+ }
13
+ function isDarkMode() {
14
+ return window.matchMedia('(prefers-color-scheme: dark)').matches;
15
+ }
16
+ function onDarkMode(cb) {
17
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (ev)=>{
18
+ cb(ev.matches);
19
+ });
20
+ }
21
+ function switchTheme(theme) {
22
+ document.documentElement.setAttribute('data-theme', theme);
23
+ }
24
+ function handleThemeSwitch() {
25
+ switchTheme(isDarkMode() ? 'dark' : 'light');
26
+ onDarkMode((dark)=>{
27
+ switchTheme(dark ? 'dark' : 'light');
28
+ });
29
+ }
30
+ function gradient(start, end, value) {
31
+ value = Math.max(0, Math.min(100, value));
32
+ const red = Math.round(start.red + (end.red - start.red) * value / 100);
33
+ const green = Math.round(start.green + (end.green - start.green) * value / 100);
34
+ const blue = Math.round(start.blue + (end.blue - start.blue) * value / 100);
35
+ return `rgb(${red}, ${green}, ${blue})`;
36
+ }
37
+ export { cssVar, gradient, handleThemeSwitch, isDarkMode, onDarkMode, render, switchTheme };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taybart/corvid",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
@@ -12,6 +12,10 @@
12
12
  "types": "./dist/dom.d.ts",
13
13
  "import": "./dist/dom.js"
14
14
  },
15
+ "./style": {
16
+ "types": "./dist/style.d.ts",
17
+ "import": "./dist/style.js"
18
+ },
15
19
  "./local_storage": {
16
20
  "types": "./dist/ls.d.ts",
17
21
  "import": "./dist/ls.js"
@@ -30,6 +34,10 @@
30
34
  "files": [
31
35
  "dist"
32
36
  ],
37
+ "scripts": {
38
+ "build": "rslib build",
39
+ "dev": "rslib build --watch"
40
+ },
33
41
  "devDependencies": {
34
42
  "@happy-dom/global-registrator": "^17.4.7",
35
43
  "@rslib/core": "^0.6.2",
@@ -39,9 +47,5 @@
39
47
  "@types/jsdom": "^21.1.7",
40
48
  "@types/node": "^22.8.1",
41
49
  "typescript": "^5.8.3"
42
- },
43
- "scripts": {
44
- "build": "rslib build",
45
- "dev": "rslib build --watch"
46
50
  }
47
- }
51
+ }