@vettvangur/vanilla 0.0.59 → 0.0.60

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/data.esm.js CHANGED
@@ -134,9 +134,12 @@ const regexr = {
134
134
  * flatten(obj, prefix)
135
135
  */
136
136
  const flatten = (obj, prefix = '') => {
137
- if (!obj || typeof obj !== 'object') {
137
+ if (obj == null) {
138
138
  return {};
139
139
  }
140
+ if (typeof obj !== 'object') {
141
+ throw new TypeError(`flatten: expected an object, got ${typeof obj}`);
142
+ }
140
143
  return Object.keys(obj).reduce((acc, key) => {
141
144
  const fullKey = key === 'DEFAULT' ? prefix : prefix ? `${prefix}-${key}` : key;
142
145
  if (typeof obj[key] === 'object' && key !== 'DEFAULT') {
package/dist/dom.esm.js CHANGED
@@ -22,15 +22,22 @@
22
22
  * preloadTimeout()
23
23
  */
24
24
  function preloadTimeout() {
25
+ if (typeof document === 'undefined') {
26
+ return () => {};
27
+ }
25
28
  const body = document.querySelector('.body');
26
29
  if (!body) {
27
- return;
30
+ return () => {};
28
31
  }
29
- setTimeout(() => body.classList.add('loaded'), 100);
30
- setTimeout(() => {
32
+ const t1 = setTimeout(() => body.classList.add('loaded'), 100);
33
+ const t2 = setTimeout(() => {
31
34
  body.classList.add('preload--hidden');
32
35
  body.classList.remove('preload--transitions');
33
36
  }, 400);
37
+ return () => {
38
+ clearTimeout(t1);
39
+ clearTimeout(t2);
40
+ };
34
41
  }
35
42
 
36
43
  /**
@@ -46,46 +53,42 @@ function preloadTimeout() {
46
53
  * clickOutside(callback)
47
54
  */
48
55
  function clickOutside(callback) {
49
- // Clicks
50
- document.addEventListener('click', e => {
56
+ if (typeof document === 'undefined') {
57
+ return () => {};
58
+ }
59
+ const onClick = e => {
51
60
  const target = e.target;
52
61
  const classTargets = document.querySelectorAll('.co-el');
53
62
 
54
- // Check if the click target is inside an element with class `.co-trigger`
55
63
  // @ts-ignore
56
64
  if (target.closest('.co-trigger')) {
57
65
  return;
58
66
  }
59
-
60
- // Execute the callback function
61
67
  callback(e);
62
-
63
- // Close open elements
64
68
  Array.prototype.forEach.call(classTargets, item => {
65
69
  if (item.classList.contains('open')) {
66
70
  item.classList.remove('open');
67
71
  }
68
72
  });
69
- }, false);
70
-
71
- // ESC key
72
- document.addEventListener('keyup', e => {
73
+ };
74
+ const onKeyUp = e => {
73
75
  const openElements = document.querySelectorAll('.open');
74
76
  const keys = e.keyCode || e.which;
75
-
76
- // If ESC key (key code 27) is pressed
77
77
  if (keys === 27) {
78
- // Execute the callback function
79
78
  callback(e);
80
-
81
- // Close open elements
82
79
  Array.prototype.forEach.call(openElements, item => {
83
80
  if (item.classList.contains('open')) {
84
81
  item.classList.remove('open');
85
82
  }
86
83
  });
87
84
  }
88
- });
85
+ };
86
+ document.addEventListener('click', onClick, false);
87
+ document.addEventListener('keyup', onKeyUp);
88
+ return () => {
89
+ document.removeEventListener('click', onClick, false);
90
+ document.removeEventListener('keyup', onKeyUp);
91
+ };
89
92
  }
90
93
 
91
94
  export { clickOutside, preloadTimeout };
package/dist/index.esm.js CHANGED
@@ -49,19 +49,31 @@ function capitalize(value, lowerRest = false) {
49
49
  *
50
50
  * dictionary(key, data, culture)
51
51
  */
52
+ // WeakMap keyed by the input `data` array gives us O(1) memo lookups while
53
+ // still letting unreachable translation arrays be garbage-collected.
54
+ const dictionaryIndex = new WeakMap();
52
55
  function dictionary(key, data, culture = 'is-IS') {
56
+ var _item$values$find;
53
57
  const notFound = '[Translation not found]';
54
58
  if (data === null || data === undefined) {
55
59
  return notFound;
56
60
  }
57
- for (const item of data) {
58
- if (item.itemKey === key) {
59
- var _item$values$find;
60
- const translation = (_item$values$find = item.values.find(b => b.language === culture)) === null || _item$values$find === void 0 ? void 0 : _item$values$find.value;
61
- return translation || notFound;
61
+ let byKey = dictionaryIndex.get(data);
62
+ if (!byKey) {
63
+ byKey = new Map();
64
+ for (const _item of data) {
65
+ if (_item && _item.itemKey) {
66
+ byKey.set(_item.itemKey, _item);
67
+ }
62
68
  }
69
+ dictionaryIndex.set(data, byKey);
70
+ }
71
+ const item = byKey.get(key);
72
+ if (!item) {
73
+ return notFound;
63
74
  }
64
- return notFound;
75
+ const translation = (_item$values$find = item.values.find(b => b.language === culture)) === null || _item$values$find === void 0 ? void 0 : _item$values$find.value;
76
+ return translation || notFound;
65
77
  }
66
78
 
67
79
  /**
@@ -188,9 +200,12 @@ const regexr = {
188
200
  * flatten(obj, prefix)
189
201
  */
190
202
  const flatten = (obj, prefix = '') => {
191
- if (!obj || typeof obj !== 'object') {
203
+ if (obj == null) {
192
204
  return {};
193
205
  }
206
+ if (typeof obj !== 'object') {
207
+ throw new TypeError(`flatten: expected an object, got ${typeof obj}`);
208
+ }
194
209
  return Object.keys(obj).reduce((acc, key) => {
195
210
  const fullKey = key === 'DEFAULT' ? prefix : prefix ? `${prefix}-${key}` : key;
196
211
  if (typeof obj[key] === 'object' && key !== 'DEFAULT') {
@@ -278,15 +293,22 @@ function isEmpty(value) {
278
293
  * preloadTimeout()
279
294
  */
280
295
  function preloadTimeout() {
296
+ if (typeof document === 'undefined') {
297
+ return () => {};
298
+ }
281
299
  const body = document.querySelector('.body');
282
300
  if (!body) {
283
- return;
301
+ return () => {};
284
302
  }
285
- setTimeout(() => body.classList.add('loaded'), 100);
286
- setTimeout(() => {
303
+ const t1 = setTimeout(() => body.classList.add('loaded'), 100);
304
+ const t2 = setTimeout(() => {
287
305
  body.classList.add('preload--hidden');
288
306
  body.classList.remove('preload--transitions');
289
307
  }, 400);
308
+ return () => {
309
+ clearTimeout(t1);
310
+ clearTimeout(t2);
311
+ };
290
312
  }
291
313
 
292
314
  /**
@@ -302,46 +324,42 @@ function preloadTimeout() {
302
324
  * clickOutside(callback)
303
325
  */
304
326
  function clickOutside(callback) {
305
- // Clicks
306
- document.addEventListener('click', e => {
327
+ if (typeof document === 'undefined') {
328
+ return () => {};
329
+ }
330
+ const onClick = e => {
307
331
  const target = e.target;
308
332
  const classTargets = document.querySelectorAll('.co-el');
309
333
 
310
- // Check if the click target is inside an element with class `.co-trigger`
311
334
  // @ts-ignore
312
335
  if (target.closest('.co-trigger')) {
313
336
  return;
314
337
  }
315
-
316
- // Execute the callback function
317
338
  callback(e);
318
-
319
- // Close open elements
320
339
  Array.prototype.forEach.call(classTargets, item => {
321
340
  if (item.classList.contains('open')) {
322
341
  item.classList.remove('open');
323
342
  }
324
343
  });
325
- }, false);
326
-
327
- // ESC key
328
- document.addEventListener('keyup', e => {
344
+ };
345
+ const onKeyUp = e => {
329
346
  const openElements = document.querySelectorAll('.open');
330
347
  const keys = e.keyCode || e.which;
331
-
332
- // If ESC key (key code 27) is pressed
333
348
  if (keys === 27) {
334
- // Execute the callback function
335
349
  callback(e);
336
-
337
- // Close open elements
338
350
  Array.prototype.forEach.call(openElements, item => {
339
351
  if (item.classList.contains('open')) {
340
352
  item.classList.remove('open');
341
353
  }
342
354
  });
343
355
  }
344
- });
356
+ };
357
+ document.addEventListener('click', onClick, false);
358
+ document.addEventListener('keyup', onKeyUp);
359
+ return () => {
360
+ document.removeEventListener('click', onClick, false);
361
+ document.removeEventListener('keyup', onKeyUp);
362
+ };
345
363
  }
346
364
 
347
365
  /**
@@ -391,7 +409,9 @@ function getTranslation(key, translations) {
391
409
  * getCulture(path)
392
410
  */
393
411
  function getCulture(path) {
394
- const match = path.match(/^\/([a-z]{2})(\/|$)/i);
412
+ // Match BCP-47-ish prefixes: 2-3 letter language, optionally followed by
413
+ // a region subtag (e.g. `en-US`, `eng-US`, `is`, `pt-BR`).
414
+ const match = path.match(/^\/([a-z]{2,3}(?:-[a-z]{2,4})?)(\/|$)/i);
395
415
  return match ? match[1].toLowerCase() : null;
396
416
  }
397
417
 
@@ -49,19 +49,31 @@ function capitalize(value, lowerRest = false) {
49
49
  *
50
50
  * dictionary(key, data, culture)
51
51
  */
52
+ // WeakMap keyed by the input `data` array gives us O(1) memo lookups while
53
+ // still letting unreachable translation arrays be garbage-collected.
54
+ const dictionaryIndex = new WeakMap();
52
55
  function dictionary(key, data, culture = 'is-IS') {
56
+ var _item$values$find;
53
57
  const notFound = '[Translation not found]';
54
58
  if (data === null || data === undefined) {
55
59
  return notFound;
56
60
  }
57
- for (const item of data) {
58
- if (item.itemKey === key) {
59
- var _item$values$find;
60
- const translation = (_item$values$find = item.values.find(b => b.language === culture)) === null || _item$values$find === void 0 ? void 0 : _item$values$find.value;
61
- return translation || notFound;
61
+ let byKey = dictionaryIndex.get(data);
62
+ if (!byKey) {
63
+ byKey = new Map();
64
+ for (const _item of data) {
65
+ if (_item && _item.itemKey) {
66
+ byKey.set(_item.itemKey, _item);
67
+ }
62
68
  }
69
+ dictionaryIndex.set(data, byKey);
63
70
  }
64
- return notFound;
71
+ const item = byKey.get(key);
72
+ if (!item) {
73
+ return notFound;
74
+ }
75
+ const translation = (_item$values$find = item.values.find(b => b.language === culture)) === null || _item$values$find === void 0 ? void 0 : _item$values$find.value;
76
+ return translation || notFound;
65
77
  }
66
78
 
67
79
  /**
@@ -116,7 +128,9 @@ function getTranslation(key, translations) {
116
128
  * getCulture(path)
117
129
  */
118
130
  function getCulture(path) {
119
- const match = path.match(/^\/([a-z]{2})(\/|$)/i);
131
+ // Match BCP-47-ish prefixes: 2-3 letter language, optionally followed by
132
+ // a region subtag (e.g. `en-US`, `eng-US`, `is`, `pt-BR`).
133
+ const match = path.match(/^\/([a-z]{2,3}(?:-[a-z]{2,4})?)(\/|$)/i);
120
134
  return match ? match[1].toLowerCase() : null;
121
135
  }
122
136
 
@@ -25,20 +25,6 @@
25
25
  * capitalize(value, lowerRest)
26
26
  */
27
27
  export function capitalize(value: any, lowerRest?: boolean): any;
28
- /**
29
- * Dictionary.
30
- *
31
- * @param key - Value.
32
- * @param data - Value.
33
- * @param culture - Value.
34
- * @returns Result of the operation.
35
- *
36
- * @example
37
- * // vanilla (src/tools/javascript/vanilla/index.mjs)
38
- * // import { dictionary } from '@vettvangur/vanilla'
39
- *
40
- * dictionary(key, data, culture)
41
- */
42
28
  export function dictionary(key: any, data: any, culture?: string): any;
43
29
  /**
44
30
  * Fetcher.
@@ -113,7 +99,7 @@ export function isEmpty(value: any): boolean;
113
99
  *
114
100
  * preloadTimeout()
115
101
  */
116
- export function preloadTimeout(): void;
102
+ export function preloadTimeout(): () => void;
117
103
  /**
118
104
  * Click outside.
119
105
  *
@@ -126,7 +112,7 @@ export function preloadTimeout(): void;
126
112
  *
127
113
  * clickOutside(callback)
128
114
  */
129
- export function clickOutside(callback: any): void;
115
+ export function clickOutside(callback: any): () => void;
130
116
  /**
131
117
  * Get translation.
132
118
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vettvangur/vanilla",
3
- "version": "0.0.59",
3
+ "version": "0.0.60",
4
4
  "description": "Vettvangur | Vanilla JS Utility Library",
5
5
  "access": "public",
6
6
  "type": "module",