@taybart/corvid 0.1.16 → 0.1.18

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) {
@@ -543,10 +549,15 @@ class request {
543
549
  const res = await fetch(url, options);
544
550
  const expect = override.expect || this.opts.expect;
545
551
  if (res.status !== expect) {
546
- const body = await res.json();
547
- throw new Error(`bad response ${res.status} !== ${expect}, body: ${body}`);
552
+ const body = await res.text();
553
+ if (401 === res.status && this.opts.onUnauthorized) {
554
+ this.log.warn("unauthorized");
555
+ this.opts.onUnauthorized(body);
556
+ } else throw new Error(`bad response ${res.status} !== ${expect}, body: ${body}`);
548
557
  }
549
- return await res.json();
558
+ this.log.debug(`content type: ${res.headers.get('content-type')}`);
559
+ if ('application/json' === res.headers.get('content-type')) return await res.json();
560
+ return await res.text();
550
561
  }
551
562
  constructor(opts = {}, verbose = false){
552
563
  network_define_property(this, "opts", void 0);
@@ -563,6 +574,7 @@ class request {
563
574
  this.log.debug("converting object params to class");
564
575
  this.opts.params = new network_params(this.opts.params);
565
576
  }
577
+ if (!this.opts.fetch) this.opts.fetch = window.fetch;
566
578
  this.log.debug(`with options: ${JSON.stringify(this.opts)}`);
567
579
  }
568
580
  }
@@ -576,12 +588,12 @@ class ws {
576
588
  this.backoff = 100;
577
589
  this.ws.addEventListener('open', ()=>{
578
590
  const rl = this.recursion_level;
579
- this.log.debug(`on open: reconnected (${rl})`);
591
+ this.log.debug(`on open: reconnected(${rl})`);
580
592
  this.is_connected = true;
581
593
  if (!this.ws) return;
582
594
  for(let key in this.event_listeners)this.event_listeners[key].forEach((cb)=>{
583
595
  if (this.ws) {
584
- this.log.debug(`adding listener (${rl}): ${key}`);
596
+ this.log.debug(`adding listener(${rl}): ${key} `);
585
597
  this.ws.addEventListener(key, cb);
586
598
  }
587
599
  });
@@ -590,7 +602,7 @@ class ws {
590
602
  this.log.debug('connection closed');
591
603
  this.is_connected = false;
592
604
  this.backoff = Math.min(2 * this.backoff, this.max_timeout);
593
- this.log.debug(`backoff: ${this.backoff}`);
605
+ this.log.debug(`backoff: ${this.backoff} `);
594
606
  this.reconnect_timer = window.setTimeout(()=>{
595
607
  if (this.should_reconnect) {
596
608
  this.ws = null;
@@ -609,7 +621,7 @@ class ws {
609
621
  if (!this.event_listeners.message) this.event_listeners.message = [];
610
622
  const handler = (e)=>{
611
623
  const rl = this.recursion_level;
612
- this.log.debug(`message(${rl}): ${e.data}`);
624
+ this.log.debug(`message(${rl}): ${e.data} `);
613
625
  cb(e.data);
614
626
  };
615
627
  this.event_listeners.message.push(handler);
@@ -681,6 +693,11 @@ function get(key, _default) {
681
693
  }
682
694
  return ret;
683
695
  }
696
+ function getJSON(key, _default) {
697
+ const val = get(key, _default);
698
+ if (null === val) return null;
699
+ return JSON.parse(val);
700
+ }
684
701
  function local_storage_update(key, update1, broadcast = false) {
685
702
  const prev = get(key);
686
703
  const value = update1(prev);
@@ -706,6 +723,7 @@ function set(key, value, broadcast = false) {
706
723
  });
707
724
  document.dispatchEvent(event);
708
725
  }
726
+ if ('object' == typeof value) value = JSON.stringify(value);
709
727
  localStorage.setItem(key, value);
710
728
  }
711
729
  function setObj(update, prefix, broadcast = false) {
@@ -723,8 +741,9 @@ function setObj(update, prefix, broadcast = false) {
723
741
  set(key, v, broadcast);
724
742
  }
725
743
  }
744
+ const listeners = new Map();
726
745
  function listen(key, cb) {
727
- document.addEventListener('@corvid/ls-update', (ev)=>{
746
+ const listener = (ev)=>{
728
747
  if (ev.detail.key === key || '*' === key) {
729
748
  if (cb instanceof dom_el) {
730
749
  if (ev.detail.key === key) cb.content(ev.detail.value);
@@ -735,7 +754,19 @@ function listen(key, cb) {
735
754
  value: ev.detail.value
736
755
  });
737
756
  }
738
- });
757
+ };
758
+ if (!listeners.has(key)) listeners.set(key, new Map());
759
+ listeners.get(key).set(cb, listener);
760
+ document.addEventListener('@corvid/ls-update', listener);
761
+ }
762
+ function unlisten(key, cb) {
763
+ const keyListeners = listeners.get(key);
764
+ if (!keyListeners) return;
765
+ const listener = keyListeners.get(cb);
766
+ if (!listener) return;
767
+ document.removeEventListener('@corvid/ls-update', listener);
768
+ keyListeners.delete(cb);
769
+ if (0 === keyListeners.size) listeners.delete(key);
739
770
  }
740
771
  function clear(key) {
741
772
  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,6 +22,8 @@ export type requestOpts = {
22
22
  expect?: number;
23
23
  credentials?: RequestCredentials;
24
24
  insecureNoVerify?: boolean;
25
+ onUnauthorized?: (body: any) => void;
26
+ fetch?: (url: string, init: RequestInit) => Promise<any>;
25
27
  };
26
28
  export declare class request {
27
29
  opts: requestOpts;
package/dist/network.js CHANGED
@@ -140,10 +140,15 @@ class request {
140
140
  const res = await fetch(url, options);
141
141
  const expect = override.expect || this.opts.expect;
142
142
  if (res.status !== expect) {
143
- const body = await res.json();
144
- throw new Error(`bad response ${res.status} !== ${expect}, body: ${body}`);
143
+ const body = await res.text();
144
+ if (401 === res.status && this.opts.onUnauthorized) {
145
+ this.log.warn("unauthorized");
146
+ this.opts.onUnauthorized(body);
147
+ } else throw new Error(`bad response ${res.status} !== ${expect}, body: ${body}`);
145
148
  }
146
- return await res.json();
149
+ this.log.debug(`content type: ${res.headers.get('content-type')}`);
150
+ if ('application/json' === res.headers.get('content-type')) return await res.json();
151
+ return await res.text();
147
152
  }
148
153
  constructor(opts = {}, verbose = false){
149
154
  network_define_property(this, "opts", void 0);
@@ -160,6 +165,7 @@ class request {
160
165
  this.log.debug("converting object params to class");
161
166
  this.opts.params = new network_params(this.opts.params);
162
167
  }
168
+ if (!this.opts.fetch) this.opts.fetch = window.fetch;
163
169
  this.log.debug(`with options: ${JSON.stringify(this.opts)}`);
164
170
  }
165
171
  }
@@ -173,12 +179,12 @@ class ws {
173
179
  this.backoff = 100;
174
180
  this.ws.addEventListener('open', ()=>{
175
181
  const rl = this.recursion_level;
176
- this.log.debug(`on open: reconnected (${rl})`);
182
+ this.log.debug(`on open: reconnected(${rl})`);
177
183
  this.is_connected = true;
178
184
  if (!this.ws) return;
179
185
  for(let key in this.event_listeners)this.event_listeners[key].forEach((cb)=>{
180
186
  if (this.ws) {
181
- this.log.debug(`adding listener (${rl}): ${key}`);
187
+ this.log.debug(`adding listener(${rl}): ${key} `);
182
188
  this.ws.addEventListener(key, cb);
183
189
  }
184
190
  });
@@ -187,7 +193,7 @@ class ws {
187
193
  this.log.debug('connection closed');
188
194
  this.is_connected = false;
189
195
  this.backoff = Math.min(2 * this.backoff, this.max_timeout);
190
- this.log.debug(`backoff: ${this.backoff}`);
196
+ this.log.debug(`backoff: ${this.backoff} `);
191
197
  this.reconnect_timer = window.setTimeout(()=>{
192
198
  if (this.should_reconnect) {
193
199
  this.ws = null;
@@ -206,7 +212,7 @@ class ws {
206
212
  if (!this.event_listeners.message) this.event_listeners.message = [];
207
213
  const handler = (e)=>{
208
214
  const rl = this.recursion_level;
209
- this.log.debug(`message(${rl}): ${e.data}`);
215
+ this.log.debug(`message(${rl}): ${e.data} `);
210
216
  cb(e.data);
211
217
  };
212
218
  this.event_listeners.message.push(handler);
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.16",
3
+ "version": "0.1.18",
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
+ }