@jackens/nnn 2026.9.9 → 2026.9.29
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 +1229 -0
- package/nnn.d.ts +180 -204
- package/nnn.js +84 -95
- package/package.json +3 -14
- package/readme.md +0 -1370
package/readme.md
DELETED
|
@@ -1,1370 +0,0 @@
|
|
|
1
|
-
# nnn
|
|
2
|
-
|
|
3
|
-
A collection of Jackens’ JavaScript helper utilities (version: `2026.9.9`).
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
bun i @jackens/nnn
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
or
|
|
12
|
-
|
|
13
|
-
```sh
|
|
14
|
-
npm i @jackens/nnn
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
```js
|
|
20
|
-
import {
|
|
21
|
-
CNode,
|
|
22
|
-
HArgs,
|
|
23
|
-
HArgs1,
|
|
24
|
-
c,
|
|
25
|
-
createEscape,
|
|
26
|
-
createTokenizer,
|
|
27
|
-
csvParse,
|
|
28
|
-
fixPlTypography,
|
|
29
|
-
h,
|
|
30
|
-
monokai,
|
|
31
|
-
nanolightTs,
|
|
32
|
-
rwd,
|
|
33
|
-
s,
|
|
34
|
-
svgUse,
|
|
35
|
-
uuidV1,
|
|
36
|
-
} from '@jackens/nnn' // or './node_modules/@jackens/nnn/nnn.js'
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Exports
|
|
40
|
-
|
|
41
|
-
- [`CNode`](#CNode):
|
|
42
|
-
Represents a CSS rule node for the [`c`](#c) helper. Keys
|
|
43
|
-
are CSS properties or nested selectors.
|
|
44
|
-
- [`HArgs`](#HArgs):
|
|
45
|
-
Tuple argument type for the [`h`](#h) and [`s`](#s)
|
|
46
|
-
helpers.
|
|
47
|
-
- [`HArgs1`](#HArgs1):
|
|
48
|
-
Single argument type for the [`h`](#h) and [`s`](#s)
|
|
49
|
-
helpers.
|
|
50
|
-
- [`c`](#c):
|
|
51
|
-
A minimal CSS-in-JS helper that converts a JavaScript
|
|
52
|
-
object hierarchy into a CSS string.
|
|
53
|
-
- [`createEscape`](#createEscape):
|
|
54
|
-
Creates a tag function for escaping interpolated values
|
|
55
|
-
in template literals.
|
|
56
|
-
- [`createTokenizer`](#createTokenizer):
|
|
57
|
-
A helper for building simple tokenizers (see also
|
|
58
|
-
[`nanolightTs`](#nanolightTs)).
|
|
59
|
-
- [`csvParse`](#csvParse):
|
|
60
|
-
Parses a CSV string into a two-dimensional array of
|
|
61
|
-
strings.
|
|
62
|
-
- [`fixPlTypography`](#fixPlTypography):
|
|
63
|
-
Applies Polish-specific typographic corrections to a DOM
|
|
64
|
-
subtree.
|
|
65
|
-
- [`h`](#h):
|
|
66
|
-
A lightweight _HyperScript_-style helper for creating and
|
|
67
|
-
modifying `HTMLElement`s (see also [`s`](#s)).
|
|
68
|
-
- [`monokai`](#monokai):
|
|
69
|
-
A Monokai-inspired color scheme for use with the [`c`](#c)
|
|
70
|
-
helper and [`nanolightTs`](#nanolightTs) tokenizer.
|
|
71
|
-
- [`nanolightTs`](#nanolightTs):
|
|
72
|
-
A TypeScript/JavaScript syntax highlighting tokenizer
|
|
73
|
-
built using [`createTokenizer`](#createTokenizer).
|
|
74
|
-
- [`rwd`](#rwd):
|
|
75
|
-
A responsive web design helper that generates CSS rules
|
|
76
|
-
for a grid-like layout.
|
|
77
|
-
- [`s`](#s):
|
|
78
|
-
A lightweight _HyperScript_-style helper for creating and
|
|
79
|
-
modifying `SVGElement`s (see also [`h`](#h)).
|
|
80
|
-
- [`svgUse`](#svgUse):
|
|
81
|
-
Shorthand for creating an SVG element with a `<use>`
|
|
82
|
-
child referencing an icon by ID.
|
|
83
|
-
- [`uuidV1`](#uuidV1):
|
|
84
|
-
Generates a UUID v1 (time-based) identifier.
|
|
85
|
-
|
|
86
|
-
### CNode
|
|
87
|
-
|
|
88
|
-
```ts
|
|
89
|
-
type CNode = {
|
|
90
|
-
[attributeOrSelector: string]: string | number | CNode | undefined;
|
|
91
|
-
};
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Represents a CSS rule node for the [`c`](#c) helper. Keys
|
|
95
|
-
are CSS properties or nested selectors.
|
|
96
|
-
|
|
97
|
-
### HArgs
|
|
98
|
-
|
|
99
|
-
```ts
|
|
100
|
-
type HArgs = [string | Node, ...HArgs1[]];
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Tuple argument type for the [`h`](#h) and [`s`](#s)
|
|
104
|
-
helpers.
|
|
105
|
-
|
|
106
|
-
### HArgs1
|
|
107
|
-
|
|
108
|
-
```ts
|
|
109
|
-
type HArgs1 = Record<PropertyKey, unknown> | null | undefined | Node | string | number | HArgs;
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
Single argument type for the [`h`](#h) and [`s`](#s)
|
|
113
|
-
helpers.
|
|
114
|
-
|
|
115
|
-
### c
|
|
116
|
-
|
|
117
|
-
```ts
|
|
118
|
-
const c: (node: CNode, splitter?: string) => string;
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
A minimal CSS-in-JS helper that converts a JavaScript
|
|
122
|
-
object hierarchy into a CSS string.
|
|
123
|
-
|
|
124
|
-
#### node
|
|
125
|
-
|
|
126
|
-
An object describing CSS rules. Keys are
|
|
127
|
-
selectors or at-rules; values are either CSS property
|
|
128
|
-
values or nested rule objects. A selector key may
|
|
129
|
-
contain comma-separated alternatives (e.g. `'.b,.c'`);
|
|
130
|
-
when nested, each alternative is combined with each
|
|
131
|
-
parent alternative (cartesian product), producing a
|
|
132
|
-
comma-joined selector list (e.g. `'a.b,a.c'`).
|
|
133
|
-
|
|
134
|
-
#### splitter
|
|
135
|
-
|
|
136
|
-
A delimiter used to create unique keys
|
|
137
|
-
(default: `'$$'`). The substring from `splitter` to the
|
|
138
|
-
end of a key is ignored (e.g., `src$$1` → `src`).
|
|
139
|
-
|
|
140
|
-
#### Returns
|
|
141
|
-
|
|
142
|
-
A CSS string representing the compiled rules.
|
|
143
|
-
|
|
144
|
-
#### Usage Examples
|
|
145
|
-
|
|
146
|
-
```ts
|
|
147
|
-
const actual = c({
|
|
148
|
-
a: {
|
|
149
|
-
color: 'red',
|
|
150
|
-
margin: 1,
|
|
151
|
-
'.c': { margin: 2, padding: 2 },
|
|
152
|
-
padding: 1,
|
|
153
|
-
},
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
const expected = `
|
|
157
|
-
a{
|
|
158
|
-
color:red;
|
|
159
|
-
margin:1
|
|
160
|
-
}
|
|
161
|
-
a.c{
|
|
162
|
-
margin:2;
|
|
163
|
-
padding:2
|
|
164
|
-
}
|
|
165
|
-
a{
|
|
166
|
-
padding:1
|
|
167
|
-
}
|
|
168
|
-
`.replace(/\n\s*/g, '')
|
|
169
|
-
|
|
170
|
-
expect(actual).toBe(expected)
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
```ts
|
|
174
|
-
const actual = c({
|
|
175
|
-
a: {
|
|
176
|
-
'.b': {
|
|
177
|
-
color: 'red',
|
|
178
|
-
margin: 1,
|
|
179
|
-
'.c': { margin: 2, padding: 2 },
|
|
180
|
-
padding: 1,
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
const expected = `
|
|
186
|
-
a.b{
|
|
187
|
-
color:red;
|
|
188
|
-
margin:1
|
|
189
|
-
}
|
|
190
|
-
a.b.c{
|
|
191
|
-
margin:2;
|
|
192
|
-
padding:2
|
|
193
|
-
}
|
|
194
|
-
a.b{
|
|
195
|
-
padding:1
|
|
196
|
-
}
|
|
197
|
-
`.replace(/\n\s*/g, '')
|
|
198
|
-
|
|
199
|
-
expect(actual).toBe(expected)
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
```ts
|
|
203
|
-
const actual = c({
|
|
204
|
-
'@font-face$$1': {
|
|
205
|
-
'font-family': 'Jackens',
|
|
206
|
-
src$$1: 'url(otf/jackens.otf)',
|
|
207
|
-
src$$2:
|
|
208
|
-
"url(otf/jackens.otf) format('opentype')," +
|
|
209
|
-
"url(svg/jackens.svg) format('svg')",
|
|
210
|
-
'font-weight': 'normal',
|
|
211
|
-
'font-style': 'normal',
|
|
212
|
-
},
|
|
213
|
-
'@font-face$$2': {
|
|
214
|
-
'font-family': 'C64',
|
|
215
|
-
src: 'url(fonts/C64_Pro_Mono-STYLE.woff)',
|
|
216
|
-
},
|
|
217
|
-
'@keyframes spin': {
|
|
218
|
-
'0%': { transform: 'rotate(0deg)' },
|
|
219
|
-
'100%': { transform: 'rotate(360deg)' },
|
|
220
|
-
},
|
|
221
|
-
div: {
|
|
222
|
-
border: 'solid red 1px',
|
|
223
|
-
'.c1': { 'background-color': '#000' },
|
|
224
|
-
' .c1': { 'background-color': 'black' },
|
|
225
|
-
'.c2': { 'background-color': 'rgb(0,0,0)' },
|
|
226
|
-
},
|
|
227
|
-
'@media(min-width:200px)': {
|
|
228
|
-
div: { margin: 0, padding: 0 },
|
|
229
|
-
span: { color: '#000' },
|
|
230
|
-
},
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
const expected = `
|
|
234
|
-
@font-face{
|
|
235
|
-
font-family:Jackens;
|
|
236
|
-
src:url(otf/jackens.otf);
|
|
237
|
-
src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
|
|
238
|
-
font-weight:normal;
|
|
239
|
-
font-style:normal
|
|
240
|
-
}
|
|
241
|
-
@font-face{
|
|
242
|
-
font-family:C64;
|
|
243
|
-
src:url(fonts/C64_Pro_Mono-STYLE.woff)
|
|
244
|
-
}
|
|
245
|
-
@keyframes spin{
|
|
246
|
-
0%{
|
|
247
|
-
transform:rotate(0deg)
|
|
248
|
-
}
|
|
249
|
-
100%{
|
|
250
|
-
transform:rotate(360deg)
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
div{
|
|
254
|
-
border:solid red 1px
|
|
255
|
-
}
|
|
256
|
-
div.c1{
|
|
257
|
-
background-color:#000
|
|
258
|
-
}
|
|
259
|
-
div .c1{
|
|
260
|
-
background-color:black
|
|
261
|
-
}
|
|
262
|
-
div.c2{
|
|
263
|
-
background-color:rgb(0,0,0)
|
|
264
|
-
}
|
|
265
|
-
@media(min-width:200px){
|
|
266
|
-
div{
|
|
267
|
-
margin:0;
|
|
268
|
-
padding:0
|
|
269
|
-
}
|
|
270
|
-
span{
|
|
271
|
-
color:#000
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
`.replace(/\n\s*/g, '')
|
|
275
|
-
|
|
276
|
-
expect(actual).toBe(expected)
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
```ts
|
|
280
|
-
const actual = c({
|
|
281
|
-
a: {
|
|
282
|
-
'.b,.c': {
|
|
283
|
-
margin: 1,
|
|
284
|
-
'.d': {
|
|
285
|
-
margin: 2,
|
|
286
|
-
},
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
const expected = `
|
|
292
|
-
a.b,a.c{
|
|
293
|
-
margin:1
|
|
294
|
-
}
|
|
295
|
-
a.b.d,a.c.d{
|
|
296
|
-
margin:2
|
|
297
|
-
}
|
|
298
|
-
`.replace(/\n\s*/g, '')
|
|
299
|
-
|
|
300
|
-
expect(actual).toBe(expected)
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
```ts
|
|
304
|
-
const actual = c({
|
|
305
|
-
'.b,.c': {
|
|
306
|
-
margin: 1,
|
|
307
|
-
'.d': {
|
|
308
|
-
margin: 2,
|
|
309
|
-
},
|
|
310
|
-
},
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
const expected = `
|
|
314
|
-
.b,.c{
|
|
315
|
-
margin:1
|
|
316
|
-
}
|
|
317
|
-
.b.d,.c.d{
|
|
318
|
-
margin:2
|
|
319
|
-
}
|
|
320
|
-
`.replace(/\n\s*/g, '')
|
|
321
|
-
|
|
322
|
-
expect(actual).toBe(expected)
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
```ts
|
|
326
|
-
const actual = c({
|
|
327
|
-
'.a,.b': {
|
|
328
|
-
margin: 1,
|
|
329
|
-
'.c,.d': {
|
|
330
|
-
margin: 2,
|
|
331
|
-
},
|
|
332
|
-
},
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
const expected = `
|
|
336
|
-
.a,.b{
|
|
337
|
-
margin:1
|
|
338
|
-
}
|
|
339
|
-
.a.c,.a.d,.b.c,.b.d{
|
|
340
|
-
margin:2
|
|
341
|
-
}
|
|
342
|
-
`.replace(/\n\s*/g, '')
|
|
343
|
-
|
|
344
|
-
expect(actual).toBe(expected)
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
```ts
|
|
348
|
-
const actual = c({
|
|
349
|
-
':root$$monokai': {
|
|
350
|
-
'--': {
|
|
351
|
-
bg: '#faf4f2',
|
|
352
|
-
fg: '#29242a',
|
|
353
|
-
comment: '#918c8e',
|
|
354
|
-
identifier: {
|
|
355
|
-
1: '#7058be',
|
|
356
|
-
2: '#269d69',
|
|
357
|
-
3: '#1c8ca8',
|
|
358
|
-
4: '#29242a',
|
|
359
|
-
},
|
|
360
|
-
keyword: {
|
|
361
|
-
1: '#e14775',
|
|
362
|
-
2: '#7058be',
|
|
363
|
-
3: '#1c8ca8',
|
|
364
|
-
},
|
|
365
|
-
number: '#7058be',
|
|
366
|
-
operator: '#e14775',
|
|
367
|
-
punctuation: '#918c8e',
|
|
368
|
-
string: '#cc7a0a',
|
|
369
|
-
},
|
|
370
|
-
},
|
|
371
|
-
'@media only screen and (prefers-color-scheme: dark)$$monokai':
|
|
372
|
-
{
|
|
373
|
-
':root': {
|
|
374
|
-
'--': {
|
|
375
|
-
bg: '#2d2a2e',
|
|
376
|
-
fg: '#fcfcfa',
|
|
377
|
-
comment: '#727072',
|
|
378
|
-
identifier: {
|
|
379
|
-
1: '#ae81ff',
|
|
380
|
-
2: '#a9dc76',
|
|
381
|
-
3: '#66d9ef',
|
|
382
|
-
4: '#fcfcfa',
|
|
383
|
-
},
|
|
384
|
-
keyword: {
|
|
385
|
-
1: '#ff6188',
|
|
386
|
-
2: '#ae81ff',
|
|
387
|
-
3: '#66d9ef',
|
|
388
|
-
},
|
|
389
|
-
number: '#ae81ff',
|
|
390
|
-
operator: '#ff6188',
|
|
391
|
-
punctuation: '#727072',
|
|
392
|
-
string: '#ffd866',
|
|
393
|
-
},
|
|
394
|
-
},
|
|
395
|
-
},
|
|
396
|
-
})
|
|
397
|
-
|
|
398
|
-
const expected = `
|
|
399
|
-
:root{
|
|
400
|
-
--bg:#faf4f2;
|
|
401
|
-
--fg:#29242a;
|
|
402
|
-
--comment:#918c8e;
|
|
403
|
-
--identifier1:#7058be;
|
|
404
|
-
--identifier2:#269d69;
|
|
405
|
-
--identifier3:#1c8ca8;
|
|
406
|
-
--identifier4:#29242a;
|
|
407
|
-
--keyword1:#e14775;
|
|
408
|
-
--keyword2:#7058be;
|
|
409
|
-
--keyword3:#1c8ca8;
|
|
410
|
-
--number:#7058be;
|
|
411
|
-
--operator:#e14775;
|
|
412
|
-
--punctuation:#918c8e;
|
|
413
|
-
--string:#cc7a0a
|
|
414
|
-
}
|
|
415
|
-
@media only screen and (prefers-color-scheme: dark){
|
|
416
|
-
:root{
|
|
417
|
-
--bg:#2d2a2e;
|
|
418
|
-
--fg:#fcfcfa;
|
|
419
|
-
--comment:#727072;
|
|
420
|
-
--identifier1:#ae81ff;
|
|
421
|
-
--identifier2:#a9dc76;
|
|
422
|
-
--identifier3:#66d9ef;
|
|
423
|
-
--identifier4:#fcfcfa;
|
|
424
|
-
--keyword1:#ff6188;
|
|
425
|
-
--keyword2:#ae81ff;
|
|
426
|
-
--keyword3:#66d9ef;
|
|
427
|
-
--number:#ae81ff;
|
|
428
|
-
--operator:#ff6188;
|
|
429
|
-
--punctuation:#727072;
|
|
430
|
-
--string:#ffd866
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
`.replace(/\n\s*/g, '')
|
|
434
|
-
|
|
435
|
-
expect(actual).toBe(expected)
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
### createEscape
|
|
439
|
-
|
|
440
|
-
```ts
|
|
441
|
-
const createEscape: (escapeFn: (value: any) => string) => (template: TemplateStringsArray, ...values: unknown[]) => string;
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
Creates a tag function for escaping interpolated values
|
|
445
|
-
in template literals.
|
|
446
|
-
|
|
447
|
-
#### escapeFn
|
|
448
|
-
|
|
449
|
-
A function that takes a value and returns
|
|
450
|
-
its escaped string representation.
|
|
451
|
-
|
|
452
|
-
#### Returns
|
|
453
|
-
|
|
454
|
-
A tag function that escapes interpolated values
|
|
455
|
-
using the provided escape function.
|
|
456
|
-
|
|
457
|
-
#### Usage Examples
|
|
458
|
-
|
|
459
|
-
```ts
|
|
460
|
-
const escapeFn = (value: any): string =>
|
|
461
|
-
Array.isArray(value)
|
|
462
|
-
? value.map(escapeFn).join(', ')
|
|
463
|
-
: value === true || value === false
|
|
464
|
-
? `b'${+value}'`
|
|
465
|
-
: value instanceof Date
|
|
466
|
-
? `'${value
|
|
467
|
-
.toISOString()
|
|
468
|
-
.replace(/^(.+)T(.+)\..*$/, '$1 $2')}'`
|
|
469
|
-
: Number.isFinite(value)
|
|
470
|
-
? `${value}`
|
|
471
|
-
: typeof value === 'string'
|
|
472
|
-
? `'${value.replace(/'/g, "''")}'`
|
|
473
|
-
: 'NULL'
|
|
474
|
-
|
|
475
|
-
const sql = createEscape(escapeFn)
|
|
476
|
-
|
|
477
|
-
const actual = sql`
|
|
478
|
-
SELECT *
|
|
479
|
-
FROM table_name
|
|
480
|
-
WHERE column_name IN (
|
|
481
|
-
${[
|
|
482
|
-
true,
|
|
483
|
-
null,
|
|
484
|
-
undefined,
|
|
485
|
-
NaN,
|
|
486
|
-
Infinity,
|
|
487
|
-
42,
|
|
488
|
-
'42',
|
|
489
|
-
"4'2",
|
|
490
|
-
/42/,
|
|
491
|
-
new Date(323325000000),
|
|
492
|
-
]}
|
|
493
|
-
)
|
|
494
|
-
`
|
|
495
|
-
|
|
496
|
-
const expected = `
|
|
497
|
-
SELECT *
|
|
498
|
-
FROM table_name
|
|
499
|
-
WHERE column_name IN (
|
|
500
|
-
b'1', NULL, NULL, NULL, NULL, 42, '42', '4''2', NULL, '1980-03-31 04:30:00'
|
|
501
|
-
)
|
|
502
|
-
`
|
|
503
|
-
|
|
504
|
-
expect(actual).toBe(expected)
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
### createTokenizer
|
|
508
|
-
|
|
509
|
-
```ts
|
|
510
|
-
const createTokenizer: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...specs: [M, string | RegExp][]) => (code: string) => T[];
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
A helper for building simple tokenizers (see also
|
|
514
|
-
[`nanolightTs`](#nanolightTs)).
|
|
515
|
-
|
|
516
|
-
#### Remarks
|
|
517
|
-
|
|
518
|
-
1. Matches starting at an earlier position take
|
|
519
|
-
precedence.
|
|
520
|
-
2. Among matches at the same position, the longer one
|
|
521
|
-
wins.
|
|
522
|
-
3. Among matches of the same position and length, the one
|
|
523
|
-
defined earlier wins.
|
|
524
|
-
|
|
525
|
-
#### decorator
|
|
526
|
-
|
|
527
|
-
A function that wraps each matched
|
|
528
|
-
chunk. It receives the matched text (`chunk`) and
|
|
529
|
-
optionally the `metadata` associated with the pattern
|
|
530
|
-
that produced the match. For unmatched text between
|
|
531
|
-
patterns, `metadata` is `undefined`.
|
|
532
|
-
|
|
533
|
-
#### specs
|
|
534
|
-
|
|
535
|
-
An array of tuples `[metadata, pattern]`
|
|
536
|
-
where:
|
|
537
|
-
|
|
538
|
-
- `metadata`: arbitrary data (e.g., a CSS class name)
|
|
539
|
-
passed to `decorator` when the pattern matches.
|
|
540
|
-
- `pattern`: a `string` or `RegExp` to match against the
|
|
541
|
-
input.
|
|
542
|
-
|
|
543
|
-
#### Returns
|
|
544
|
-
|
|
545
|
-
A tokenizer function that accepts a code string
|
|
546
|
-
and returns an array of decorated tokens.
|
|
547
|
-
|
|
548
|
-
#### Usage Examples
|
|
549
|
-
|
|
550
|
-
```ts
|
|
551
|
-
const tokenizer = createTokenizer(
|
|
552
|
-
(chunk, metadata) => ({ chunk, metadata }),
|
|
553
|
-
['keyword', /\b(if|else|for)\b/],
|
|
554
|
-
['string', /"[^"]*"/]
|
|
555
|
-
)
|
|
556
|
-
|
|
557
|
-
const result = tokenizer('if "hello" else "world"')
|
|
558
|
-
|
|
559
|
-
expect(result).toEqual([
|
|
560
|
-
{ chunk: 'if', metadata: 'keyword' },
|
|
561
|
-
{ chunk: ' ', metadata: undefined },
|
|
562
|
-
{ chunk: '"hello"', metadata: 'string' },
|
|
563
|
-
{ chunk: ' ', metadata: undefined },
|
|
564
|
-
{ chunk: 'else', metadata: 'keyword' },
|
|
565
|
-
{ chunk: ' ', metadata: undefined },
|
|
566
|
-
{ chunk: '"world"', metadata: 'string' },
|
|
567
|
-
])
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
```ts
|
|
571
|
-
const tokenizer = createTokenizer(
|
|
572
|
-
(chunk, metadata) => `${metadata}:${chunk}`,
|
|
573
|
-
['tag', 'BEGIN'],
|
|
574
|
-
['end', 'END']
|
|
575
|
-
)
|
|
576
|
-
|
|
577
|
-
const result = tokenizer('aBEGINbENDc')
|
|
578
|
-
|
|
579
|
-
expect(result).toEqual([
|
|
580
|
-
'undefined:a',
|
|
581
|
-
'tag:BEGIN',
|
|
582
|
-
'undefined:b',
|
|
583
|
-
'end:END',
|
|
584
|
-
'undefined:c',
|
|
585
|
-
])
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
```ts
|
|
589
|
-
const tokenizer = createTokenizer(
|
|
590
|
-
chunk => chunk,
|
|
591
|
-
['test', /test/]
|
|
592
|
-
)
|
|
593
|
-
|
|
594
|
-
const result = tokenizer('')
|
|
595
|
-
|
|
596
|
-
expect(result).toEqual([])
|
|
597
|
-
```
|
|
598
|
-
|
|
599
|
-
```ts
|
|
600
|
-
const tokenizer = createTokenizer(
|
|
601
|
-
(chunk, metadata) => ({ chunk, metadata }),
|
|
602
|
-
['start', /^test/]
|
|
603
|
-
)
|
|
604
|
-
|
|
605
|
-
const result = tokenizer('test here')
|
|
606
|
-
|
|
607
|
-
expect(result).toEqual([
|
|
608
|
-
{ chunk: 'test', metadata: 'start' },
|
|
609
|
-
{ chunk: ' here', metadata: undefined },
|
|
610
|
-
])
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
```ts
|
|
614
|
-
const tokenizer = createTokenizer(
|
|
615
|
-
(chunk, metadata) => metadata,
|
|
616
|
-
['later', /x/],
|
|
617
|
-
['earlier', /y/]
|
|
618
|
-
)
|
|
619
|
-
|
|
620
|
-
const result = tokenizer('yx')
|
|
621
|
-
|
|
622
|
-
expect(result).toEqual(['earlier', 'later'])
|
|
623
|
-
```
|
|
624
|
-
|
|
625
|
-
```ts
|
|
626
|
-
const tokenizer = createTokenizer(
|
|
627
|
-
chunk => chunk,
|
|
628
|
-
['short', 'a'],
|
|
629
|
-
['long', 'abc']
|
|
630
|
-
)
|
|
631
|
-
|
|
632
|
-
const result = tokenizer('abc')
|
|
633
|
-
|
|
634
|
-
expect(result).toEqual(['abc'])
|
|
635
|
-
```
|
|
636
|
-
|
|
637
|
-
```ts
|
|
638
|
-
const tokenizer = createTokenizer(
|
|
639
|
-
chunk => chunk,
|
|
640
|
-
['empty', ''],
|
|
641
|
-
['word', /\w+/]
|
|
642
|
-
)
|
|
643
|
-
|
|
644
|
-
const result = tokenizer('hello')
|
|
645
|
-
|
|
646
|
-
expect(result).toEqual(['hello'])
|
|
647
|
-
```
|
|
648
|
-
|
|
649
|
-
```ts
|
|
650
|
-
const tokenizer = createTokenizer(
|
|
651
|
-
chunk => chunk,
|
|
652
|
-
['test', /xyz/]
|
|
653
|
-
)
|
|
654
|
-
|
|
655
|
-
const result = tokenizer('abc')
|
|
656
|
-
|
|
657
|
-
expect(result).toEqual(['abc'])
|
|
658
|
-
```
|
|
659
|
-
|
|
660
|
-
```ts
|
|
661
|
-
const tokenizer = createTokenizer(
|
|
662
|
-
(_chunk, metadata) => metadata,
|
|
663
|
-
['a', 'a'],
|
|
664
|
-
['b', 'b']
|
|
665
|
-
)
|
|
666
|
-
|
|
667
|
-
const result = tokenizer('aabb')
|
|
668
|
-
|
|
669
|
-
expect(result).toEqual(['a', 'a', 'b', 'b'])
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
### csvParse
|
|
673
|
-
|
|
674
|
-
```ts
|
|
675
|
-
const csvParse: (csv: string, separator?: string) => string[][];
|
|
676
|
-
```
|
|
677
|
-
|
|
678
|
-
Parses a CSV string into a two-dimensional array of
|
|
679
|
-
strings.
|
|
680
|
-
|
|
681
|
-
Supports quoted fields with escaped double quotes (`""`).
|
|
682
|
-
Carriage returns are normalized.
|
|
683
|
-
|
|
684
|
-
#### csv
|
|
685
|
-
|
|
686
|
-
The CSV string to parse.
|
|
687
|
-
|
|
688
|
-
#### separator
|
|
689
|
-
|
|
690
|
-
The field delimiter (default: `','`).
|
|
691
|
-
|
|
692
|
-
#### Returns
|
|
693
|
-
|
|
694
|
-
A 2D array where each inner array represents a
|
|
695
|
-
row of fields.
|
|
696
|
-
|
|
697
|
-
#### Usage Examples
|
|
698
|
-
|
|
699
|
-
```ts
|
|
700
|
-
const text = `"aaa
|
|
701
|
-
""aaa""
|
|
702
|
-
aaa",bbb, "ccc,ccc"
|
|
703
|
-
"xxx,xxx", "yyy
|
|
704
|
-
yyy",zzz
|
|
705
|
-
42 , "42" , 17
|
|
706
|
-
|
|
707
|
-
`
|
|
708
|
-
|
|
709
|
-
expect(csvParse(text)).toEqual([
|
|
710
|
-
['aaa\n"aaa"\naaa', 'bbb', 'ccc,ccc'],
|
|
711
|
-
['xxx,xxx', 'yyy\nyyy', 'zzz'],
|
|
712
|
-
[' 42 ', '42', ' 17'],
|
|
713
|
-
])
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
### fixPlTypography
|
|
717
|
-
|
|
718
|
-
```ts
|
|
719
|
-
const fixPlTypography: (node: Node) => void;
|
|
720
|
-
```
|
|
721
|
-
|
|
722
|
-
Applies Polish-specific typographic corrections to a DOM
|
|
723
|
-
subtree.
|
|
724
|
-
|
|
725
|
-
This function prevents orphaned conjunctions
|
|
726
|
-
(single-letter words like “a”, “i”, “o”, “u”, “w”, “z”)
|
|
727
|
-
and the em dash (“—”) from appearing at the end of a
|
|
728
|
-
line. It wraps each such character together with the
|
|
729
|
-
whitespace that follows it in a `white-space:nowrap`
|
|
730
|
-
span, removing the only line-break opportunity between it
|
|
731
|
-
and the next word so the two stay glued together. It also
|
|
732
|
-
inserts zero-width spaces after slashes and dots to allow
|
|
733
|
-
line breaks.
|
|
734
|
-
|
|
735
|
-
#### node
|
|
736
|
-
|
|
737
|
-
The root DOM node to process. All descendant
|
|
738
|
-
text nodes are corrected recursively, except those
|
|
739
|
-
inside `IFRAME`, `NOSCRIPT`, `PRE`, `SCRIPT`, `STYLE`,
|
|
740
|
-
or `TEXTAREA` elements.
|
|
741
|
-
|
|
742
|
-
#### Usage Examples
|
|
743
|
-
|
|
744
|
-
```ts
|
|
745
|
-
const p = h(
|
|
746
|
-
'p',
|
|
747
|
-
'Pchnąć w tę łódź jeża lub ośm skrzyń fig ' +
|
|
748
|
-
'(zob. https://pl.wikipedia.org/wiki/Pangram).',
|
|
749
|
-
['br'],
|
|
750
|
-
['b', 'Zażółć gęślą jaźń.']
|
|
751
|
-
)
|
|
752
|
-
|
|
753
|
-
fixPlTypography(p)
|
|
754
|
-
|
|
755
|
-
expect(p.innerHTML).toEqual(
|
|
756
|
-
'Pchnąć ' +
|
|
757
|
-
'<span style="white-space:nowrap">w </span>' +
|
|
758
|
-
'tę łódź jeża lub ośm skrzyń fig ' +
|
|
759
|
-
'(zob. https://\u200Bpl.\u200Bwikipedia.\u200Borg/' +
|
|
760
|
-
'\u200Bwiki/\u200BPangram).' +
|
|
761
|
-
'<br>' +
|
|
762
|
-
'<b>Zażółć gęślą jaźń.</b>'
|
|
763
|
-
)
|
|
764
|
-
```
|
|
765
|
-
|
|
766
|
-
### h
|
|
767
|
-
|
|
768
|
-
```ts
|
|
769
|
-
const h: {
|
|
770
|
-
<T extends keyof HTMLElementTagNameMap>(tag: T, ...args1: HArgs1[]): HTMLElementTagNameMap[T];
|
|
771
|
-
<N extends Node>(node: N, ...args1: HArgs1[]): N;
|
|
772
|
-
(tagOrNode: string | Node, ...args1: HArgs1[]): Node;
|
|
773
|
-
};
|
|
774
|
-
```
|
|
775
|
-
|
|
776
|
-
A lightweight _HyperScript_-style helper for creating and
|
|
777
|
-
modifying `HTMLElement`s (see also [`s`](#s)).
|
|
778
|
-
|
|
779
|
-
#### tagOrNode
|
|
780
|
-
|
|
781
|
-
If a `string`, it is treated as the tag
|
|
782
|
-
name for a new element. If a `Node`, that node is
|
|
783
|
-
modified in place.
|
|
784
|
-
|
|
785
|
-
#### args
|
|
786
|
-
|
|
787
|
-
Additional arguments processed as follows:
|
|
788
|
-
|
|
789
|
-
- `Object`: maps attributes/properties. Keys starting
|
|
790
|
-
with `$` set element properties (without the `$`
|
|
791
|
-
prefix); if the value is a plain object, it is
|
|
792
|
-
shallow-merged into the existing property instead of
|
|
793
|
-
replacing it (useful e.g. for `$style`). Other keys
|
|
794
|
-
set attributes: a key prefixed with `xlink:` sets the
|
|
795
|
-
attribute via `setAttributeNS` in the XLink
|
|
796
|
-
namespace; any other key (without a colon) sets it
|
|
797
|
-
via `setAttribute`. A value of `false` removes the
|
|
798
|
-
attribute.
|
|
799
|
-
- `null`/`undefined`: ignored.
|
|
800
|
-
- `Node`: appended as a child.
|
|
801
|
-
- `string`/`number`: converted to a `Text` node and
|
|
802
|
-
appended.
|
|
803
|
-
- [`HArgs`](#HArgs) array: processed recursively.
|
|
804
|
-
|
|
805
|
-
#### Returns
|
|
806
|
-
|
|
807
|
-
The created or modified `HTMLElement`.
|
|
808
|
-
|
|
809
|
-
#### Usage Examples
|
|
810
|
-
|
|
811
|
-
```ts
|
|
812
|
-
const b = h('b')
|
|
813
|
-
|
|
814
|
-
expect(b.outerHTML).toBe('<b></b>')
|
|
815
|
-
|
|
816
|
-
const i = h('i', 'text')
|
|
817
|
-
|
|
818
|
-
h(b, i)
|
|
819
|
-
|
|
820
|
-
expect(i.outerHTML).toBe('<i>text</i>')
|
|
821
|
-
|
|
822
|
-
expect(b.outerHTML).toBe('<b><i>text</i></b>')
|
|
823
|
-
|
|
824
|
-
h(i, { $className: 'some class' })
|
|
825
|
-
|
|
826
|
-
expect(i.outerHTML).toBe('<i class="some class">text</i>')
|
|
827
|
-
|
|
828
|
-
expect(b.outerHTML).toBe(
|
|
829
|
-
'<b><i class="some class">text</i></b>'
|
|
830
|
-
)
|
|
831
|
-
```
|
|
832
|
-
|
|
833
|
-
```ts
|
|
834
|
-
expect(h('span', 'text').outerHTML).toBe(
|
|
835
|
-
'<span>text</span>'
|
|
836
|
-
)
|
|
837
|
-
|
|
838
|
-
expect(h('span', { $innerText: 'text' }).outerHTML).toBe(
|
|
839
|
-
'<span>text</span>'
|
|
840
|
-
)
|
|
841
|
-
|
|
842
|
-
expect(h('span', '42').outerHTML).toBe('<span>42</span>')
|
|
843
|
-
|
|
844
|
-
expect(h('span', 42).outerHTML).toBe('<span>42</span>')
|
|
845
|
-
```
|
|
846
|
-
|
|
847
|
-
```ts
|
|
848
|
-
expect(
|
|
849
|
-
h('div', { style: 'margin:0;padding:0' }).outerHTML
|
|
850
|
-
).toBe('<div style="margin:0;padding:0"></div>')
|
|
851
|
-
|
|
852
|
-
expect(
|
|
853
|
-
h('div', { $style: 'margin:0;padding:0' }).outerHTML
|
|
854
|
-
).toBe('<div style="margin: 0px; padding: 0px;"></div>')
|
|
855
|
-
|
|
856
|
-
expect(
|
|
857
|
-
h('div', { $style: { margin: 0, padding: 0 } })
|
|
858
|
-
.outerHTML
|
|
859
|
-
).toBe('<div style="margin: 0px; padding: 0px;"></div>')
|
|
860
|
-
```
|
|
861
|
-
|
|
862
|
-
```ts
|
|
863
|
-
const input1 = h('input', { value: 42 })
|
|
864
|
-
const input2 = h('input', { $value: '42' })
|
|
865
|
-
|
|
866
|
-
expect(input1.value).toBe('42')
|
|
867
|
-
expect(input2.value).toBe('42')
|
|
868
|
-
|
|
869
|
-
expect(input1.outerHTML).toBe('<input value="42">')
|
|
870
|
-
expect(input2.outerHTML).toBe('<input>')
|
|
871
|
-
```
|
|
872
|
-
|
|
873
|
-
```ts
|
|
874
|
-
const checkbox1 = h('input', {
|
|
875
|
-
type: 'checkbox',
|
|
876
|
-
checked: true,
|
|
877
|
-
})
|
|
878
|
-
|
|
879
|
-
const checkbox2 = h('input', {
|
|
880
|
-
type: 'checkbox',
|
|
881
|
-
$checked: true,
|
|
882
|
-
})
|
|
883
|
-
|
|
884
|
-
expect(checkbox1.checked).toBe(true)
|
|
885
|
-
expect(checkbox2.checked).toBe(true)
|
|
886
|
-
|
|
887
|
-
expect(checkbox1.outerHTML).toBe(
|
|
888
|
-
'<input type="checkbox" checked="">'
|
|
889
|
-
)
|
|
890
|
-
|
|
891
|
-
expect(checkbox2.outerHTML).toBe(
|
|
892
|
-
'<input type="checkbox">'
|
|
893
|
-
)
|
|
894
|
-
```
|
|
895
|
-
|
|
896
|
-
```ts
|
|
897
|
-
const div = h('div')
|
|
898
|
-
|
|
899
|
-
expect(div.key).toBeUndefined()
|
|
900
|
-
|
|
901
|
-
h(div, { $key: { one: 1 } })
|
|
902
|
-
|
|
903
|
-
expect(div.key).toEqual({ one: 1 })
|
|
904
|
-
|
|
905
|
-
h(div, { $key: { two: 2 } })
|
|
906
|
-
|
|
907
|
-
expect(div.key).toEqual({ one: 1, two: 2 })
|
|
908
|
-
```
|
|
909
|
-
|
|
910
|
-
```ts
|
|
911
|
-
const elemWithClass = h('div', { class: 'test' })
|
|
912
|
-
|
|
913
|
-
expect(elemWithClass.getAttribute('class')).toBe('test')
|
|
914
|
-
|
|
915
|
-
const elemWithText = h('div', 'initial')
|
|
916
|
-
|
|
917
|
-
h(elemWithText, ' more')
|
|
918
|
-
|
|
919
|
-
expect(elemWithText.outerHTML).toBe(
|
|
920
|
-
'<div>initial more</div>'
|
|
921
|
-
)
|
|
922
|
-
|
|
923
|
-
const elemWithNested = h(
|
|
924
|
-
'div',
|
|
925
|
-
['span', 'hello'],
|
|
926
|
-
['b', 'world']
|
|
927
|
-
)
|
|
928
|
-
|
|
929
|
-
expect(elemWithNested.outerHTML).toBe(
|
|
930
|
-
'<div><span>hello</span><b>world</b></div>'
|
|
931
|
-
)
|
|
932
|
-
```
|
|
933
|
-
|
|
934
|
-
### monokai
|
|
935
|
-
|
|
936
|
-
```ts
|
|
937
|
-
const monokai: CNode;
|
|
938
|
-
```
|
|
939
|
-
|
|
940
|
-
A Monokai-inspired color scheme for use with the [`c`](#c)
|
|
941
|
-
helper and [`nanolightTs`](#nanolightTs) tokenizer.
|
|
942
|
-
|
|
943
|
-
### nanolightTs
|
|
944
|
-
|
|
945
|
-
```ts
|
|
946
|
-
const nanolightTs: (code: string) => HArgs1[];
|
|
947
|
-
```
|
|
948
|
-
|
|
949
|
-
A TypeScript/JavaScript syntax highlighting tokenizer
|
|
950
|
-
built using [`createTokenizer`](#createTokenizer).
|
|
951
|
-
|
|
952
|
-
#### code
|
|
953
|
-
|
|
954
|
-
The source code string to tokenize.
|
|
955
|
-
|
|
956
|
-
#### Returns
|
|
957
|
-
|
|
958
|
-
An array of [`HArgs1`](#HArgs1) elements suitable for
|
|
959
|
-
rendering with [`h`](#h).
|
|
960
|
-
|
|
961
|
-
#### Usage Examples
|
|
962
|
-
|
|
963
|
-
```ts
|
|
964
|
-
const codeJs =
|
|
965
|
-
'const answerToLifeTheUniverseAndEverything = ' +
|
|
966
|
-
"{ 42: 42 }['42'] /* 42 */"
|
|
967
|
-
|
|
968
|
-
expect(nanolightTs(codeJs)).toEqual([
|
|
969
|
-
['span', { class: 'keyword1' }, 'const'],
|
|
970
|
-
' ',
|
|
971
|
-
[
|
|
972
|
-
'span',
|
|
973
|
-
{ class: 'identifier4' },
|
|
974
|
-
'answerToLifeTheUniverseAndEverything',
|
|
975
|
-
],
|
|
976
|
-
' ',
|
|
977
|
-
['span', { class: 'operator' }, '='],
|
|
978
|
-
' ',
|
|
979
|
-
['span', { class: 'punctuation' }, '{'],
|
|
980
|
-
' ',
|
|
981
|
-
['span', { class: 'number' }, '42'],
|
|
982
|
-
['span', { class: 'operator' }, ':'],
|
|
983
|
-
' ',
|
|
984
|
-
['span', { class: 'number' }, '42'],
|
|
985
|
-
' ',
|
|
986
|
-
['span', { class: 'punctuation' }, '}'],
|
|
987
|
-
['span', { class: 'punctuation' }, '['],
|
|
988
|
-
['span', { class: 'string' }, "'42'"],
|
|
989
|
-
['span', { class: 'punctuation' }, ']'],
|
|
990
|
-
' ',
|
|
991
|
-
['span', { class: 'comment' }, '/* 42 */'],
|
|
992
|
-
])
|
|
993
|
-
```
|
|
994
|
-
|
|
995
|
-
### rwd
|
|
996
|
-
|
|
997
|
-
```ts
|
|
998
|
-
const rwd: (root: CNode, selector: string, cellWidthPx: number, cellHeightPx: number, ...specs: [number, number?, number?][]) => void;
|
|
999
|
-
```
|
|
1000
|
-
|
|
1001
|
-
A responsive web design helper that generates CSS rules
|
|
1002
|
-
for a grid-like layout.
|
|
1003
|
-
|
|
1004
|
-
#### root
|
|
1005
|
-
|
|
1006
|
-
The CSS root object to populate (see
|
|
1007
|
-
[`c`](#c)).
|
|
1008
|
-
|
|
1009
|
-
#### selector
|
|
1010
|
-
|
|
1011
|
-
The CSS selector for the grid item.
|
|
1012
|
-
|
|
1013
|
-
#### cellWidthPx
|
|
1014
|
-
|
|
1015
|
-
The base cell width in pixels.
|
|
1016
|
-
|
|
1017
|
-
#### cellHeightPx
|
|
1018
|
-
|
|
1019
|
-
The base cell height in pixels.
|
|
1020
|
-
|
|
1021
|
-
#### specs
|
|
1022
|
-
|
|
1023
|
-
An array of breakpoint specifications, each
|
|
1024
|
-
a tuple of:
|
|
1025
|
-
|
|
1026
|
-
- `maxWidth`: maximum number of cells per row (defines
|
|
1027
|
-
the viewport breakpoint).
|
|
1028
|
-
- `width` (optional, default `1`): number of horizontal
|
|
1029
|
-
cells the element spans.
|
|
1030
|
-
- `height` (optional, default `1`): number of vertical
|
|
1031
|
-
cells the element spans.
|
|
1032
|
-
|
|
1033
|
-
#### Usage Examples
|
|
1034
|
-
|
|
1035
|
-
```ts
|
|
1036
|
-
const style: CNode = {
|
|
1037
|
-
body: {
|
|
1038
|
-
margin: 0,
|
|
1039
|
-
},
|
|
1040
|
-
'.r6': {
|
|
1041
|
-
border: 'solid red 1px',
|
|
1042
|
-
'.no-border': {
|
|
1043
|
-
border: 'none',
|
|
1044
|
-
},
|
|
1045
|
-
},
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
rwd(style, '.r6', 200, 50, [6], [3], [1, 1, 2])
|
|
1049
|
-
|
|
1050
|
-
expect(style).toEqual({
|
|
1051
|
-
body: {
|
|
1052
|
-
margin: 0,
|
|
1053
|
-
},
|
|
1054
|
-
'.r6': {
|
|
1055
|
-
border: 'solid red 1px',
|
|
1056
|
-
'.no-border': {
|
|
1057
|
-
border: 'none',
|
|
1058
|
-
},
|
|
1059
|
-
boxSizing: 'border-box',
|
|
1060
|
-
display: 'block',
|
|
1061
|
-
float: 'left',
|
|
1062
|
-
width: '100%',
|
|
1063
|
-
height: '100px',
|
|
1064
|
-
},
|
|
1065
|
-
'@media(min-width:600px)': {
|
|
1066
|
-
'.r6': {
|
|
1067
|
-
width: 'calc(100% / 3)',
|
|
1068
|
-
height: '50px',
|
|
1069
|
-
},
|
|
1070
|
-
},
|
|
1071
|
-
'@media(min-width:1200px)': {
|
|
1072
|
-
'.r6': {
|
|
1073
|
-
width: 'calc(50% / 3)',
|
|
1074
|
-
height: '50px',
|
|
1075
|
-
},
|
|
1076
|
-
},
|
|
1077
|
-
})
|
|
1078
|
-
```
|
|
1079
|
-
|
|
1080
|
-
### s
|
|
1081
|
-
|
|
1082
|
-
```ts
|
|
1083
|
-
const s: {
|
|
1084
|
-
<T extends keyof SVGElementTagNameMap>(tag: T, ...args1: HArgs1[]): SVGElementTagNameMap[T];
|
|
1085
|
-
<N extends Node>(node: N, ...args1: HArgs1[]): N;
|
|
1086
|
-
(tagOrNode: string | Node, ...args1: HArgs1[]): Node;
|
|
1087
|
-
};
|
|
1088
|
-
```
|
|
1089
|
-
|
|
1090
|
-
A lightweight _HyperScript_-style helper for creating and
|
|
1091
|
-
modifying `SVGElement`s (see also [`h`](#h)).
|
|
1092
|
-
|
|
1093
|
-
#### tagOrNode
|
|
1094
|
-
|
|
1095
|
-
If a `string`, it is treated as the tag
|
|
1096
|
-
name for a new element. If a `Node`, that node is
|
|
1097
|
-
modified in place.
|
|
1098
|
-
|
|
1099
|
-
#### args
|
|
1100
|
-
|
|
1101
|
-
Additional arguments processed as follows:
|
|
1102
|
-
|
|
1103
|
-
- `Object`: maps attributes/properties. Keys starting
|
|
1104
|
-
with `$` set element properties (without the `$`
|
|
1105
|
-
prefix); if the value is a plain object, it is
|
|
1106
|
-
shallow-merged into the existing property instead of
|
|
1107
|
-
replacing it. Other keys set attributes: a key
|
|
1108
|
-
prefixed with `xlink:` sets the attribute via
|
|
1109
|
-
`setAttributeNS` in the XLink namespace; any other
|
|
1110
|
-
key (without a colon) sets it via `setAttribute`. A
|
|
1111
|
-
value of `false` removes the attribute.
|
|
1112
|
-
- `null`/`undefined`: ignored.
|
|
1113
|
-
- `Node`: appended as a child.
|
|
1114
|
-
- `string`/`number`: converted to a `Text` node and
|
|
1115
|
-
appended.
|
|
1116
|
-
- [`HArgs`](#HArgs) array: processed recursively.
|
|
1117
|
-
|
|
1118
|
-
#### Returns
|
|
1119
|
-
|
|
1120
|
-
The created or modified `SVGElement`.
|
|
1121
|
-
|
|
1122
|
-
#### Usage Examples
|
|
1123
|
-
|
|
1124
|
-
```ts
|
|
1125
|
-
const svg = s('svg', { 'xlink:href': true })
|
|
1126
|
-
|
|
1127
|
-
expect(
|
|
1128
|
-
svg.getAttributeNS(
|
|
1129
|
-
'http://www.w3.org/1999/xlink',
|
|
1130
|
-
'href'
|
|
1131
|
-
)
|
|
1132
|
-
).toBe('')
|
|
1133
|
-
```
|
|
1134
|
-
|
|
1135
|
-
```ts
|
|
1136
|
-
const svg = s('svg', { 'xlink:href': false })
|
|
1137
|
-
|
|
1138
|
-
expect(
|
|
1139
|
-
svg.getAttributeNS(
|
|
1140
|
-
'http://www.w3.org/1999/xlink',
|
|
1141
|
-
'href'
|
|
1142
|
-
)
|
|
1143
|
-
).toBeNull()
|
|
1144
|
-
```
|
|
1145
|
-
|
|
1146
|
-
```ts
|
|
1147
|
-
const svg = s('svg', {
|
|
1148
|
-
'xlink:href': 'http://example.com',
|
|
1149
|
-
})
|
|
1150
|
-
|
|
1151
|
-
expect(
|
|
1152
|
-
svg.getAttributeNS(
|
|
1153
|
-
'http://www.w3.org/1999/xlink',
|
|
1154
|
-
'href'
|
|
1155
|
-
)
|
|
1156
|
-
).toBe('http://example.com')
|
|
1157
|
-
```
|
|
1158
|
-
|
|
1159
|
-
```ts
|
|
1160
|
-
const svg = s('svg', { 'xlink:title': 42 })
|
|
1161
|
-
|
|
1162
|
-
expect(
|
|
1163
|
-
svg.getAttributeNS(
|
|
1164
|
-
'http://www.w3.org/1999/xlink',
|
|
1165
|
-
'title'
|
|
1166
|
-
)
|
|
1167
|
-
).toBe('42')
|
|
1168
|
-
```
|
|
1169
|
-
|
|
1170
|
-
### svgUse
|
|
1171
|
-
|
|
1172
|
-
```ts
|
|
1173
|
-
const svgUse: (id: string, ...args: HArgs1[]) => SVGSVGElement;
|
|
1174
|
-
```
|
|
1175
|
-
|
|
1176
|
-
Shorthand for creating an SVG element with a `<use>`
|
|
1177
|
-
child referencing an icon by ID.
|
|
1178
|
-
|
|
1179
|
-
Equivalent to:
|
|
1180
|
-
|
|
1181
|
-
```ts
|
|
1182
|
-
s(
|
|
1183
|
-
'svg',
|
|
1184
|
-
['use', { 'xlink:href': '#' + id }],
|
|
1185
|
-
...args
|
|
1186
|
-
)
|
|
1187
|
-
```
|
|
1188
|
-
|
|
1189
|
-
#### id
|
|
1190
|
-
|
|
1191
|
-
The ID of the symbol to reference (without the
|
|
1192
|
-
`#` prefix).
|
|
1193
|
-
|
|
1194
|
-
#### args
|
|
1195
|
-
|
|
1196
|
-
Additional arguments passed to the outer
|
|
1197
|
-
`<svg>` element.
|
|
1198
|
-
|
|
1199
|
-
#### Returns
|
|
1200
|
-
|
|
1201
|
-
An `SVGSVGElement` containing a `<use>` element.
|
|
1202
|
-
|
|
1203
|
-
#### Usage Examples
|
|
1204
|
-
|
|
1205
|
-
```ts
|
|
1206
|
-
const svg = svgUse('icon-home')
|
|
1207
|
-
|
|
1208
|
-
expect(svg.children.length).toBe(1)
|
|
1209
|
-
|
|
1210
|
-
const useElement = svg.children[0]
|
|
1211
|
-
|
|
1212
|
-
expect(
|
|
1213
|
-
useElement.getAttributeNS(
|
|
1214
|
-
'http://www.w3.org/1999/xlink',
|
|
1215
|
-
'href'
|
|
1216
|
-
)
|
|
1217
|
-
).toBe('#icon-home')
|
|
1218
|
-
|
|
1219
|
-
const svgWithViewBox = svgUse('icon-star', {
|
|
1220
|
-
viewBox: '0 0 24 24',
|
|
1221
|
-
})
|
|
1222
|
-
|
|
1223
|
-
expect(svgWithViewBox.getAttribute('viewBox')).toBe(
|
|
1224
|
-
'0 0 24 24'
|
|
1225
|
-
)
|
|
1226
|
-
|
|
1227
|
-
const useViewBox = svgWithViewBox.children[0]
|
|
1228
|
-
|
|
1229
|
-
expect(
|
|
1230
|
-
useViewBox.getAttributeNS(
|
|
1231
|
-
'http://www.w3.org/1999/xlink',
|
|
1232
|
-
'href'
|
|
1233
|
-
)
|
|
1234
|
-
).toBe('#icon-star')
|
|
1235
|
-
|
|
1236
|
-
const svgWithClass = svgUse('icon-menu', {
|
|
1237
|
-
class: 'icon-btn',
|
|
1238
|
-
})
|
|
1239
|
-
|
|
1240
|
-
expect(svgWithClass.getAttribute('class')).toBe(
|
|
1241
|
-
'icon-btn'
|
|
1242
|
-
)
|
|
1243
|
-
|
|
1244
|
-
expect(svgWithClass.children.length).toBe(1)
|
|
1245
|
-
|
|
1246
|
-
const useClass = svgWithClass.children[0]
|
|
1247
|
-
|
|
1248
|
-
expect(
|
|
1249
|
-
useClass.getAttributeNS(
|
|
1250
|
-
'http://www.w3.org/1999/xlink',
|
|
1251
|
-
'href'
|
|
1252
|
-
)
|
|
1253
|
-
).toBe('#icon-menu')
|
|
1254
|
-
|
|
1255
|
-
const svgWithMultipleAttrs = svgUse('icon-settings', {
|
|
1256
|
-
width: 24,
|
|
1257
|
-
height: 24,
|
|
1258
|
-
class: 'icon',
|
|
1259
|
-
})
|
|
1260
|
-
|
|
1261
|
-
expect(svgWithMultipleAttrs.getAttribute('width')).toBe(
|
|
1262
|
-
'24'
|
|
1263
|
-
)
|
|
1264
|
-
|
|
1265
|
-
expect(svgWithMultipleAttrs.getAttribute('height')).toBe(
|
|
1266
|
-
'24'
|
|
1267
|
-
)
|
|
1268
|
-
|
|
1269
|
-
expect(svgWithMultipleAttrs.getAttribute('class')).toBe(
|
|
1270
|
-
'icon'
|
|
1271
|
-
)
|
|
1272
|
-
|
|
1273
|
-
const useMultiple = svgWithMultipleAttrs.children[0]
|
|
1274
|
-
|
|
1275
|
-
expect(
|
|
1276
|
-
useMultiple.getAttributeNS(
|
|
1277
|
-
'http://www.w3.org/1999/xlink',
|
|
1278
|
-
'href'
|
|
1279
|
-
)
|
|
1280
|
-
).toBe('#icon-settings')
|
|
1281
|
-
```
|
|
1282
|
-
|
|
1283
|
-
### uuidV1
|
|
1284
|
-
|
|
1285
|
-
```ts
|
|
1286
|
-
const uuidV1: (date?: Date, node?: string) => string;
|
|
1287
|
-
```
|
|
1288
|
-
|
|
1289
|
-
Generates a UUID v1 (time-based) identifier.
|
|
1290
|
-
|
|
1291
|
-
#### date
|
|
1292
|
-
|
|
1293
|
-
The date to use for the timestamp portion
|
|
1294
|
-
(default: current date/time).
|
|
1295
|
-
|
|
1296
|
-
#### node
|
|
1297
|
-
|
|
1298
|
-
A hexadecimal `string` for the node portion
|
|
1299
|
-
(default: random). Must match `/^[0-9a-f]*$/`; it is
|
|
1300
|
-
trimmed to the last 12 characters and left-padded with
|
|
1301
|
-
zeros if shorter.
|
|
1302
|
-
|
|
1303
|
-
#### Returns
|
|
1304
|
-
|
|
1305
|
-
A UUID v1 `string` in the standard format
|
|
1306
|
-
`xxxxxxxx-xxxx-1xxx-xxxx-xxxxxxxxxxxx`.
|
|
1307
|
-
|
|
1308
|
-
#### Usage Examples
|
|
1309
|
-
|
|
1310
|
-
```ts
|
|
1311
|
-
for (let i = 1; i <= 22136; ++i) {
|
|
1312
|
-
const uuid = uuidV1()
|
|
1313
|
-
|
|
1314
|
-
if (i === 1) {
|
|
1315
|
-
expect(uuid.split('-')[3]).toBe('8001')
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
if (i === 4095) {
|
|
1319
|
-
expect(uuid.split('-')[3]).toBe('8fff')
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
if (i === 4096) {
|
|
1323
|
-
expect(uuid.split('-')[3]).toBe('9000')
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
if (i === 9029) {
|
|
1327
|
-
expect(uuid.split('-')[3]).toBe('a345')
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
if (i === 13398) {
|
|
1331
|
-
expect(uuid.split('-')[3]).toBe('b456')
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
if (i === 16384) {
|
|
1335
|
-
expect(uuid.split('-')[3]).toBe('8000')
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
if (i === 17767) {
|
|
1339
|
-
expect(uuid.split('-')[3]).toBe('8567')
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
```
|
|
1343
|
-
|
|
1344
|
-
```ts
|
|
1345
|
-
expect(
|
|
1346
|
-
uuidV1(new Date(), '000123456789abc').split('-')[4]
|
|
1347
|
-
).toBe('123456789abc')
|
|
1348
|
-
|
|
1349
|
-
expect(
|
|
1350
|
-
uuidV1(new Date(), '123456789').split('-')[4]
|
|
1351
|
-
).toBe('000123456789')
|
|
1352
|
-
|
|
1353
|
-
expect(
|
|
1354
|
-
uuidV1(new Date(323325000000)).startsWith(
|
|
1355
|
-
'c1399400-9a71-11bd'
|
|
1356
|
-
)
|
|
1357
|
-
).toBe(true)
|
|
1358
|
-
```
|
|
1359
|
-
|
|
1360
|
-
## License
|
|
1361
|
-
|
|
1362
|
-
The MIT License (MIT)
|
|
1363
|
-
|
|
1364
|
-
Copyright (c) 2016+ Jackens
|
|
1365
|
-
|
|
1366
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
1367
|
-
|
|
1368
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
1369
|
-
|
|
1370
|
-
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|