@jackens/nnn 2026.2.27 → 2026.4.12

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.
Files changed (4) hide show
  1. package/nnn.d.ts +18 -18
  2. package/nnn.js +32 -33
  3. package/package.json +1 -1
  4. package/readme.md +238 -55
package/nnn.d.ts CHANGED
@@ -128,6 +128,24 @@ export declare const s: {
128
128
  <N extends Node>(node: N, ...args1: HArgs1[]): N;
129
129
  (tagOrNode: string | Node, ...args1: HArgs1[]): Node;
130
130
  };
131
+ /**
132
+ * Shorthand for creating an SVG element with a `<use>` child referencing an icon by ID.
133
+ *
134
+ * Equivalent to: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
135
+ *
136
+ * @param id
137
+ *
138
+ * The ID of the symbol to reference (without the `#` prefix).
139
+ *
140
+ * @param args
141
+ *
142
+ * Additional arguments passed to the outer `<svg>` element.
143
+ *
144
+ * @returns
145
+ *
146
+ * An `SVGSVGElement` containing a `<use>` element.
147
+ */
148
+ export declare const svgUse: (id: string, ...args: HArgs1[]) => SVGSVGElement;
131
149
  /**
132
150
  * Checks whether an object has the specified key as its own property.
133
151
  *
@@ -381,24 +399,6 @@ export declare const pick: <T, K extends keyof T>(ref: T, keys: K[]) => Pick<T,
381
399
  * - `height` (optional, default `1`): number of vertical cells the element spans.
382
400
  */
383
401
  export declare const rwd: (root: CRoot, selector: string, cellWidthPx: number, cellHeightPx: number, ...specs: [number, number?, number?][]) => void;
384
- /**
385
- * Shorthand for creating an SVG element with a `<use>` child referencing an icon by ID.
386
- *
387
- * Equivalent to: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
388
- *
389
- * @param id
390
- *
391
- * The ID of the symbol to reference (without the `#` prefix).
392
- *
393
- * @param args
394
- *
395
- * Additional arguments passed to the outer `<svg>` element.
396
- *
397
- * @returns
398
- *
399
- * An `SVGSVGElement` containing a `<use>` element.
400
- */
401
- export declare const svgUse: (id: string, ...args: HArgs1[]) => SVGSVGElement;
402
402
  /**
403
403
  * Generates a UUID v1 (time-based) identifier.
404
404
  *
package/nnn.js CHANGED
@@ -66,7 +66,8 @@ var csvParse = (csv, separator = ",") => {
66
66
  var isRecord = (arg) => typeof arg === "object" && arg != null && !isArray(arg);
67
67
 
68
68
  // src/nnn/h.ts
69
- var _h = (namespaceUri) => {
69
+ var XLINK_NS = "http://www.w3.org/1999/xlink";
70
+ var newH = (namespaceUri) => {
70
71
  const createElement = namespaceUri == null ? (tag) => document.createElement(tag) : (tag) => document.createElementNS(namespaceUri, tag);
71
72
  const h = (tagOrNode, ...args) => {
72
73
  const node = isString(tagOrNode) ? createElement(tagOrNode) : tagOrNode;
@@ -92,14 +93,13 @@ var _h = (namespaceUri) => {
92
93
  if (indexOfColon >= 0) {
93
94
  const nsKey = name.slice(0, indexOfColon);
94
95
  if (nsKey === "xlink") {
95
- const ns = "http://www.w3.org/1999/xlink";
96
96
  const basename = name.slice(indexOfColon + 1);
97
97
  if (value === true) {
98
- node.setAttributeNS(ns, basename, "");
98
+ node.setAttributeNS(XLINK_NS, basename, "");
99
99
  } else if (value === false) {
100
- node.removeAttributeNS(ns, basename);
100
+ node.removeAttributeNS(XLINK_NS, basename);
101
101
  } else {
102
- node.setAttributeNS(ns, basename, "" + value);
102
+ node.setAttributeNS(XLINK_NS, basename, "" + value);
103
103
  }
104
104
  }
105
105
  } else {
@@ -124,8 +124,9 @@ var _h = (namespaceUri) => {
124
124
  };
125
125
  return h;
126
126
  };
127
- var h = /* @__PURE__ */ _h();
128
- var s = /* @__PURE__ */ _h("http://www.w3.org/2000/svg");
127
+ var h = newH(null);
128
+ var s = newH("http://www.w3.org/2000/svg");
129
+ var svgUse = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args);
129
130
 
130
131
  // src/nnn/fixPlTypography.ts
131
132
  var TAGS_TO_SKIP = ["IFRAME", "NOSCRIPT", "PRE", "SCRIPT", "STYLE", "TEXTAREA"];
@@ -306,31 +307,9 @@ var newNounForm = (locale, forms) => (value) => forms[(PLURAL_RULES[locale] ??=
306
307
  var omit = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => !keys.includes(key)));
307
308
  // src/nnn/pick.ts
308
309
  var pick = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => keys.includes(key)));
309
- // src/nnn/vivify.ts
310
- var ARRAY_INDEX_REGEXP = /^(0|[1-9]\d*)$/;
311
- var isObject = (ref) => typeof ref === "object";
312
- var getTarget = (parent, parentKey, key) => parent[parentKey] ??= isString(key) && ARRAY_INDEX_REGEXP.test(key) ? [] : {};
313
- var _vivify = (parent, parentKey) => new Proxy(parent, {
314
- get(_, key) {
315
- const target = getTarget(parent, parentKey, key);
316
- const value = target[key];
317
- return isString(key) && isObject(target) && (value == null || isObject(value)) ? _vivify(target, key) : value;
318
- },
319
- set(_, key, value) {
320
- const target = getTarget(parent, parentKey, key);
321
- target[key] = value;
322
- return true;
323
- },
324
- deleteProperty(_, key) {
325
- const target = getTarget(parent, parentKey, key);
326
- return delete target[key];
327
- }
328
- });
329
- var vivify = (ref) => _vivify({ _: ref }, "_");
330
-
331
310
  // src/nnn/rwd.ts
332
311
  var rwd = (root, selector, cellWidthPx, cellHeightPx, ...specs) => {
333
- const main = vivify(root)[selector];
312
+ const main = root[selector] ??= {};
334
313
  main.boxSizing = "border-box";
335
314
  main.display = "block";
336
315
  main.float = "left";
@@ -338,7 +317,8 @@ var rwd = (root, selector, cellWidthPx, cellHeightPx, ...specs) => {
338
317
  main.height = `${cellHeightPx}px`;
339
318
  specs.sort(([a], [b]) => a - b);
340
319
  for (let [maxWidth, width, height] of specs) {
341
- const node = maxWidth === 1 ? main : vivify(root)[`@media(min-width:${cellWidthPx * maxWidth}px)`][selector];
320
+ const mediaSelector = `@media(min-width:${cellWidthPx * maxWidth}px)`;
321
+ const node = maxWidth === 1 ? main : (root[mediaSelector] ??= {})[selector] ??= {};
342
322
  width ??= 1;
343
323
  height ??= 1;
344
324
  let gcd = 100 * width;
@@ -351,8 +331,6 @@ var rwd = (root, selector, cellWidthPx, cellHeightPx, ...specs) => {
351
331
  node.height = `${cellHeightPx * height}px`;
352
332
  }
353
333
  };
354
- // src/nnn/svgUse.ts
355
- var svgUse = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args);
356
334
  // src/nnn/uuidV1.ts
357
335
  var ZEROS = /* @__PURE__ */ "0".repeat(16);
358
336
  var counter = 0;
@@ -361,6 +339,27 @@ var uuidV1 = (date = new Date, node = Math.random().toString(16).slice(2)) => {
361
339
  counter = counter + 1 & 16383;
362
340
  return time.slice(-8).concat("-", time.slice(-12, -8), -1, time.slice(-15, -12), "-", (8 | counter >> 12).toString(16), (ZEROS + (counter & 4095).toString(16)).slice(-3), "-", (ZEROS + node).slice(-12));
363
341
  };
342
+ // src/nnn/vivify.ts
343
+ var ARRAY_INDEX_REGEXP = /^(0|[1-9]\d*)$/;
344
+ var isObject = (ref) => typeof ref === "object";
345
+ var getTarget = (parent, parentKey, key) => parent[parentKey] ??= isString(key) && ARRAY_INDEX_REGEXP.test(key) ? [] : {};
346
+ var _vivify = (parent, parentKey) => new Proxy(parent, {
347
+ get(_, key) {
348
+ const target = getTarget(parent, parentKey, key);
349
+ const value = target[key];
350
+ return isString(key) && isObject(target) && (value == null || isObject(value)) ? _vivify(target, key) : value;
351
+ },
352
+ set(_, key, value) {
353
+ const target = getTarget(parent, parentKey, key);
354
+ target[key] = value;
355
+ return true;
356
+ },
357
+ deleteProperty(_, key) {
358
+ const target = getTarget(parent, parentKey, key);
359
+ return delete target[key];
360
+ }
361
+ });
362
+ var vivify = (ref) => _vivify({ _: ref }, "_");
364
363
  export {
365
364
  vivify,
366
365
  uuidV1,
package/package.json CHANGED
@@ -44,5 +44,5 @@
44
44
  "name": "@jackens/nnn",
45
45
  "type": "module",
46
46
  "types": "nnn.d.ts",
47
- "version": "2026.2.27"
47
+ "version": "2026.4.12"
48
48
  }
package/readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # nnn
2
2
 
3
- A collection of Jackens’ JavaScript helper utilities (version: `2026.2.27`).
3
+ A collection of Jackens’ JavaScript helper utilities (version: `2026.4.12`).
4
4
 
5
5
  ## Installation
6
6
 
@@ -149,8 +149,8 @@ const actual1 = c({
149
149
  color: 'red',
150
150
  margin: 1,
151
151
  '.c': { margin: 2, padding: 2 },
152
- padding: 1
153
- }
152
+ padding: 1,
153
+ },
154
154
  })
155
155
 
156
156
  const expected1 = `
@@ -174,9 +174,9 @@ const actual2 = c({
174
174
  color: 'red',
175
175
  margin: 1,
176
176
  '.c': { margin: 2, padding: 2 },
177
- padding: 1
178
- }
179
- }
177
+ padding: 1,
178
+ },
179
+ },
180
180
  })
181
181
 
182
182
  const expected2 = `
@@ -201,26 +201,26 @@ const actual3 = c({
201
201
  src$$2: "url(otf/jackens.otf) format('opentype')," +
202
202
  "url(svg/jackens.svg) format('svg')",
203
203
  font_weight: 'normal',
204
- 'font-style': 'normal'
204
+ 'font-style': 'normal',
205
205
  },
206
206
  '@font-face$$2': {
207
207
  font_family: 'C64',
208
- src: 'url(fonts/C64_Pro_Mono-STYLE.woff)'
208
+ src: 'url(fonts/C64_Pro_Mono-STYLE.woff)',
209
209
  },
210
210
  '@keyframes spin': {
211
211
  '0%': { transform: 'rotate(0deg)' },
212
- '100%': { transform: 'rotate(360deg)' }
212
+ '100%': { transform: 'rotate(360deg)' },
213
213
  },
214
214
  div: {
215
215
  border: 'solid red 1px',
216
216
  '.c1': { 'background-color': '#000' },
217
217
  ' .c1': { background_color: 'black' },
218
- '.c2': { backgroundColor: 'rgb(0,0,0)' }
218
+ '.c2': { backgroundColor: 'rgb(0,0,0)' },
219
219
  },
220
220
  '@media(min-width:200px)': {
221
221
  div: { margin: 0, padding: 0 },
222
- span: { color: '#000' }
223
- }
222
+ span: { color: '#000' },
223
+ },
224
224
  })
225
225
 
226
226
  const expected3 = `
@@ -272,10 +272,10 @@ const actual4 = c({
272
272
  '.b,.c': {
273
273
  margin: 1,
274
274
  '.d': {
275
- margin: 2
276
- }
277
- }
278
- }
275
+ margin: 2,
276
+ },
277
+ },
278
+ },
279
279
  })
280
280
 
281
281
  const expected4 = `
@@ -292,9 +292,9 @@ const actual5 = c({
292
292
  '.b,.c': {
293
293
  margin: 1,
294
294
  '.d': {
295
- margin: 2
296
- }
297
- }
295
+ margin: 2,
296
+ },
297
+ },
298
298
  })
299
299
 
300
300
  const expected5 = `
@@ -311,9 +311,9 @@ const actual6 = c({
311
311
  '.a,.b': {
312
312
  margin: 1,
313
313
  '.c,.d': {
314
- margin: 2
315
- }
316
- }
314
+ margin: 2,
315
+ },
316
+ },
317
317
  })
318
318
 
319
319
  const expected6 = `
@@ -364,7 +364,7 @@ yyy",zzz
364
364
  expect(csvParse(text)).to.deep.equal([
365
365
  ['aaa\n"aaa"\naaa', 'bbb', 'ccc,ccc'],
366
366
  ['xxx,xxx', 'yyy\nyyy', 'zzz'],
367
- [' 42 ', '42', ' 17']
367
+ [' 42 ', '42', ' 17'],
368
368
  ])
369
369
  ```
370
370
 
@@ -391,7 +391,7 @@ except those inside `IFRAME`, `NOSCRIPT`, `PRE`, `SCRIPT`, `STYLE`, or `TEXTAREA
391
391
  const p = h('p',
392
392
  'Pchnąć w tę łódź jeża lub ośm skrzyń fig (zob. https://pl.wikipedia.org/wiki/Pangram).',
393
393
  ['br'],
394
- ['b', 'Zażółć gęślą jaźń.']
394
+ ['b', 'Zażółć gęślą jaźń.'],
395
395
  )
396
396
 
397
397
  fixPlTypography(p)
@@ -494,6 +494,19 @@ expect(div.key).to.deep.equal({ one: 1 })
494
494
  h(div, { $key: { two: 2 } })
495
495
 
496
496
  expect(div.key).to.deep.equal({ one: 1, two: 2 })
497
+
498
+ const elemWithClass = h('div', { class: 'test' })
499
+
500
+ expect(elemWithClass.getAttribute('class')).to.equal('test')
501
+
502
+ const elemWithText = h('div', 'initial')
503
+
504
+ h(elemWithText, ' more')
505
+ expect(elemWithText.outerHTML).to.equal('<div>initial more</div>')
506
+
507
+ const elemWithNested = h('div', ['span', 'hello'], ['b', 'world'])
508
+
509
+ expect(elemWithNested.outerHTML).to.equal('<div><span>hello</span><b>world</b></div>')
497
510
  ```
498
511
 
499
512
  ### hasOwn
@@ -740,10 +753,10 @@ The parsed value with handler substitutions applied.
740
753
  const handlers = {
741
754
  $add: (a: number, b: number) => a + b,
742
755
  $hello: (name: string) => `Hello ${name}!`,
743
- $foo: () => 'bar'
756
+ $foo: () => 'bar',
744
757
  }
745
758
 
746
- const actual = jsOnParse(handlers, `[
759
+ const actual1 = jsOnParse(handlers, `[
747
760
  {
748
761
  "$add": [1, 2]
749
762
  },
@@ -767,23 +780,33 @@ const actual = jsOnParse(handlers, `[
767
780
  }
768
781
  ]`)
769
782
 
770
- const expected = [
783
+ expect(actual1).to.deep.equal([
771
784
  3,
772
785
  'Hello World!',
773
786
  {
774
787
  nested: 'Hello nested World!',
775
788
  one: 1,
776
- two: 2
789
+ two: 2,
777
790
  },
778
791
  'bar',
779
792
  {
780
793
  $foo: ['The parent object does not have exactly one property!'],
781
794
  one: 1,
782
- two: 2
783
- }
784
- ]
795
+ two: 2,
796
+ },
797
+ ])
798
+
799
+ const actual2 = jsOnParse({ $notFunc: 'handler not being a function' } as any, '{"$notFunc": [1, 2]}')
800
+
801
+ expect(actual2).to.deep.equal({ $notFunc: [1, 2] })
802
+
803
+ const actual3 = jsOnParse(handlers, '{"$unknown_handler_key": [1, 2]}')
785
804
 
786
- expect(actual).to.deep.equal(expected)
805
+ expect(actual3).to.deep.equal({ $unknown_handler_key: [1, 2] })
806
+
807
+ const actual4 = jsOnParse(handlers, '{"$add": {"not": "array"}}')
808
+
809
+ expect(actual4).to.deep.equal({ $add: { not: 'array' } })
787
810
  ```
788
811
 
789
812
  ### monokai
@@ -834,7 +857,7 @@ expect(nanolightTs(codeJs)).to.deep.equal([
834
857
  ['span', { class: 'string' }, "'42'"],
835
858
  ['span', { class: 'punctuation' }, ']'],
836
859
  ' ',
837
- ['span', { class: 'comment' }, '/* 42 */']
860
+ ['span', { class: 'comment' }, '/* 42 */'],
838
861
  ])
839
862
  ```
840
863
 
@@ -971,6 +994,99 @@ A tokenizer function that accepts a code string and returns an array of decorate
971
994
  2. Among matches at the same position, the longer one wins.
972
995
  3. Among matches of the same position and length, the one defined earlier wins.
973
996
 
997
+ #### Usage Examples
998
+
999
+ ```ts
1000
+ const tokenizer1 = newTokenizer(
1001
+ (chunk, metadata) => ({ chunk, metadata }),
1002
+ ['keyword', /\b(if|else|for)\b/],
1003
+ ['string', /"[^"]*"/],
1004
+ )
1005
+ const result1 = tokenizer1('if "hello" else "world"')
1006
+
1007
+ expect(result1).to.deep.equal([
1008
+ { chunk: 'if', metadata: 'keyword' },
1009
+ { chunk: ' ', metadata: undefined },
1010
+ { chunk: '"hello"', metadata: 'string' },
1011
+ { chunk: ' ', metadata: undefined },
1012
+ { chunk: 'else', metadata: 'keyword' },
1013
+ { chunk: ' ', metadata: undefined },
1014
+ { chunk: '"world"', metadata: 'string' },
1015
+ ])
1016
+
1017
+ const tokenizer2 = newTokenizer(
1018
+ (chunk, metadata) => `${metadata}:${chunk}`,
1019
+ ['tag', 'BEGIN'],
1020
+ ['end', 'END'],
1021
+ )
1022
+ const result2 = tokenizer2('aBEGINbENDc')
1023
+
1024
+ expect(result2).to.deep.equal(['undefined:a', 'tag:BEGIN', 'undefined:b', 'end:END', 'undefined:c'])
1025
+
1026
+ const tokenizer3 = newTokenizer(
1027
+ (chunk) => chunk,
1028
+ ['test', /test/],
1029
+ )
1030
+ const result3 = tokenizer3('')
1031
+
1032
+ expect(result3).to.deep.equal([])
1033
+
1034
+ const tokenizer4 = newTokenizer(
1035
+ (chunk, metadata) => ({ chunk, metadata }),
1036
+ ['start', /^test/],
1037
+ )
1038
+ const result4 = tokenizer4('test here')
1039
+
1040
+ expect(result4).to.deep.equal([
1041
+ { chunk: 'test', metadata: 'start' },
1042
+ { chunk: ' here', metadata: undefined },
1043
+ ])
1044
+
1045
+ const tokenizer5 = newTokenizer(
1046
+ (chunk, metadata) => metadata,
1047
+ ['later', /x/],
1048
+ ['earlier', /y/],
1049
+ )
1050
+ const result5 = tokenizer5('yx')
1051
+
1052
+ expect(result5).to.deep.equal(['earlier', 'later'])
1053
+
1054
+ const tokenizer6 = newTokenizer(
1055
+ (chunk) => chunk,
1056
+ ['short', 'a'],
1057
+ ['long', 'abc'],
1058
+ )
1059
+ const result6 = tokenizer6('abc')
1060
+
1061
+ expect(result6).to.deep.equal(['abc'])
1062
+
1063
+ const tokenizer7 = newTokenizer(
1064
+ (chunk) => chunk,
1065
+ ['empty', ''],
1066
+ ['word', /\w+/],
1067
+ )
1068
+ const result7 = tokenizer7('hello')
1069
+
1070
+ expect(result7).to.deep.equal(['hello'])
1071
+
1072
+ const tokenizer8 = newTokenizer(
1073
+ (chunk) => chunk,
1074
+ ['test', /xyz/],
1075
+ )
1076
+ const result8 = tokenizer8('abc')
1077
+
1078
+ expect(result8).to.deep.equal(['abc'])
1079
+
1080
+ const tokenizer9 = newTokenizer(
1081
+ (chunk, metadata) => metadata,
1082
+ ['a', 'a'],
1083
+ ['b', 'b'],
1084
+ )
1085
+ const result9 = tokenizer9('aabb')
1086
+
1087
+ expect(result9).to.deep.equal(['a', 'a', 'b', 'b'])
1088
+ ```
1089
+
974
1090
  ### omit
975
1091
 
976
1092
  ```ts
@@ -1067,45 +1183,45 @@ An array of breakpoint specifications, each a tuple of:
1067
1183
  ```ts
1068
1184
  const style: CRoot = {
1069
1185
  body: {
1070
- margin: 0
1186
+ margin: 0,
1071
1187
  },
1072
1188
  '.r6': {
1073
1189
  border: 'solid red 1px',
1074
1190
  '.no-border': {
1075
- border: 'none'
1076
- }
1077
- }
1191
+ border: 'none',
1192
+ },
1193
+ },
1078
1194
  }
1079
1195
 
1080
1196
  rwd(style, '.r6', 200, 50, [6], [3], [1, 1, 2])
1081
1197
 
1082
1198
  expect(style).to.deep.equal({
1083
1199
  body: {
1084
- margin: 0
1200
+ margin: 0,
1085
1201
  },
1086
1202
  '.r6': {
1087
1203
  border: 'solid red 1px',
1088
1204
  '.no-border': {
1089
- border: 'none'
1205
+ border: 'none',
1090
1206
  },
1091
1207
  boxSizing: 'border-box',
1092
1208
  display: 'block',
1093
1209
  float: 'left',
1094
1210
  width: '100%',
1095
- height: '100px'
1211
+ height: '100px',
1096
1212
  },
1097
1213
  '@media(min-width:600px)': {
1098
1214
  '.r6': {
1099
1215
  width: 'calc(100% / 3)',
1100
- height: '50px'
1101
- }
1216
+ height: '50px',
1217
+ },
1102
1218
  },
1103
1219
  '@media(min-width:1200px)': {
1104
1220
  '.r6': {
1105
1221
  width: 'calc(50% / 3)',
1106
- height: '50px'
1107
- }
1108
- }
1222
+ height: '50px',
1223
+ },
1224
+ },
1109
1225
  })
1110
1226
  ```
1111
1227
 
@@ -1140,6 +1256,30 @@ Additional arguments processed as follows:
1140
1256
 
1141
1257
  The created or modified `SVGElement`.
1142
1258
 
1259
+ #### Usage Examples
1260
+
1261
+ ```ts
1262
+ const svg = s('svg')
1263
+
1264
+ s(svg, { 'xlink:href': true })
1265
+ expect(svg.getAttributeNS('http://www.w3.org/1999/xlink', 'href')).to.equal('')
1266
+
1267
+ const svg2 = s('svg')
1268
+
1269
+ s(svg2, { 'xlink:href': false })
1270
+ expect(svg2.getAttributeNS('http://www.w3.org/1999/xlink', 'href')).to.be.null
1271
+
1272
+ const svg3 = s('svg')
1273
+
1274
+ s(svg3, { 'xlink:href': 'http://example.com' })
1275
+ expect(svg3.getAttributeNS('http://www.w3.org/1999/xlink', 'href')).to.equal('http://example.com')
1276
+
1277
+ const svg4 = s('svg')
1278
+
1279
+ s(svg4, { 'xlink:title': 42 })
1280
+ expect(svg4.getAttributeNS('http://www.w3.org/1999/xlink', 'title')).to.equal('42')
1281
+ ```
1282
+
1143
1283
  ### svgUse
1144
1284
 
1145
1285
  ```ts
@@ -1162,6 +1302,49 @@ Additional arguments passed to the outer `<svg>` element.
1162
1302
 
1163
1303
  An `SVGSVGElement` containing a `<use>` element.
1164
1304
 
1305
+ #### Usage Examples
1306
+
1307
+ ```ts
1308
+ const XLINK_NS = 'http://www.w3.org/1999/xlink'
1309
+
1310
+ const svg = svgUse('icon-home')
1311
+
1312
+ expect(svg.tagName).to.equal('SVG')
1313
+ expect(svg.children.length).to.equal(1)
1314
+
1315
+ const useElement = svg.children[0]
1316
+
1317
+ expect(useElement.tagName).to.equal('USE')
1318
+ expect(useElement.getAttributeNS(XLINK_NS, 'href')).to.equal('#icon-home')
1319
+
1320
+ const svgWithViewBox = svgUse('icon-star', { viewBox: '0 0 24 24' })
1321
+
1322
+ expect(svgWithViewBox.getAttribute('viewBox')).to.equal('0 0 24 24')
1323
+
1324
+ const useViewBox = svgWithViewBox.children[0]
1325
+
1326
+ expect(useViewBox.getAttributeNS(XLINK_NS, 'href')).to.equal('#icon-star')
1327
+
1328
+ const svgWithClass = svgUse('icon-menu', { class: 'icon-btn' })
1329
+
1330
+ expect(svgWithClass.getAttribute('class')).to.equal('icon-btn')
1331
+ expect(svgWithClass.children.length).to.equal(1)
1332
+
1333
+ const useClass = svgWithClass.children[0]
1334
+
1335
+ expect(useClass.getAttributeNS(XLINK_NS, 'href')).to.equal('#icon-menu')
1336
+
1337
+ const svgWithMultipleAttrs = svgUse('icon-settings', { width: 24, height: 24, class: 'icon' })
1338
+
1339
+ expect(svgWithMultipleAttrs.getAttribute('width')).to.equal('24')
1340
+ expect(svgWithMultipleAttrs.getAttribute('height')).to.equal('24')
1341
+ expect(svgWithMultipleAttrs.getAttribute('class')).to.equal('icon')
1342
+
1343
+ const useMultiple = svgWithMultipleAttrs.children[0]
1344
+
1345
+ expect(useMultiple.getAttributeNS(XLINK_NS, 'href')).to.equal('#icon-settings')
1346
+ ```
1347
+
1165
1348
  ### uuidV1
1166
1349
 
1167
1350
  ```ts
@@ -1264,40 +1447,40 @@ vivify(ref).one.two[3][4]
1264
1447
 
1265
1448
  expect(ref).to.deep.equal({
1266
1449
  one: {
1267
- two: [undefined, undefined, undefined, []]
1268
- }
1450
+ two: [undefined, undefined, undefined, []],
1451
+ },
1269
1452
  })
1270
1453
 
1271
1454
  vivify(ref).one.two[3][4] = 5
1272
1455
 
1273
1456
  expect(ref).to.deep.equal({
1274
1457
  one: {
1275
- two: [undefined, undefined, undefined, [undefined, undefined, undefined, undefined, 5]]
1276
- }
1458
+ two: [undefined, undefined, undefined, [undefined, undefined, undefined, undefined, 5]],
1459
+ },
1277
1460
  })
1278
1461
 
1279
1462
  vivify(ref).one.two[3].length = 1
1280
1463
 
1281
1464
  expect(ref).to.deep.equal({
1282
1465
  one: {
1283
- two: [undefined, undefined, undefined, [undefined]]
1284
- }
1466
+ two: [undefined, undefined, undefined, [undefined]],
1467
+ },
1285
1468
  })
1286
1469
 
1287
1470
  vivify(ref).one.two[3] = 4
1288
1471
 
1289
1472
  expect(ref).to.deep.equal({
1290
1473
  one: {
1291
- two: [undefined, undefined, undefined, 4]
1292
- }
1474
+ two: [undefined, undefined, undefined, 4],
1475
+ },
1293
1476
  })
1294
1477
 
1295
1478
  expect(vivify(ref).one.two.length).to.equal(4)
1296
1479
 
1297
1480
  expect(ref).to.deep.equal({
1298
1481
  one: {
1299
- two: [undefined, undefined, undefined, 4]
1300
- }
1482
+ two: [undefined, undefined, undefined, 4],
1483
+ },
1301
1484
  })
1302
1485
 
1303
1486
  vivify(ref).one.two = 3