@jackens/nnn 2024.3.2 → 2024.3.3

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 +25 -25
  2. package/nnn.js +57 -57
  3. package/package.json +3 -2
  4. package/readme.md +239 -232
package/nnn.d.ts CHANGED
@@ -1,28 +1,3 @@
1
- /**
2
- * The type of arguments of the `c` helper.
3
- */
4
- export type CNode = {
5
- [attributeOrSelector: string]: string | number | CNode | undefined;
6
- };
7
-
8
- /**
9
- * The type of arguments of the `c` helper.
10
- */
11
- export type CRoot = Partial<Record<PropertyKey, CNode>>;
12
-
13
- /**
14
- * A simple CSS-in-JS helper.
15
- *
16
- * The `root` parameter provides a hierarchical description of CSS rules.
17
- *
18
- * - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
19
- * - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
20
- * - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
21
- * - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
22
- * - Top-level keys that begin with `@` are not concatenated with sub-object keys.
23
- */
24
- export declare const c: (root: CRoot, splitter?: string) => string;
25
-
26
1
  /**
27
2
  * A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
28
3
  *
@@ -151,6 +126,31 @@ export declare const is: {
151
126
  <T extends abstract new (...args: any[]) => any>(type: T, arg: any): arg is InstanceType<T>;
152
127
  };
153
128
 
129
+ /**
130
+ * The type of arguments of the `jc` helper.
131
+ */
132
+ export type JcNode = {
133
+ [attributeOrSelector: string]: string | number | JcNode | undefined;
134
+ };
135
+
136
+ /**
137
+ * The type of arguments of the `jc` helper.
138
+ */
139
+ export type JcRoot = Partial<Record<PropertyKey, JcNode>>;
140
+
141
+ /**
142
+ * A simple CSS-in-JS helper.
143
+ *
144
+ * The `root` parameter provides a hierarchical description of CSS rules.
145
+ *
146
+ * - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
147
+ * - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
148
+ * - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
149
+ * - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
150
+ * - Top-level keys that begin with `@` are not concatenated with sub-object keys.
151
+ */
152
+ export declare const jc: (root: JcRoot, splitter?: string) => string;
153
+
154
154
  /**
155
155
  * `JSON.parse` with “JavaScript turned on”.
156
156
  *
package/nnn.js CHANGED
@@ -1,59 +1,6 @@
1
1
  // src/nnn/is.ts
2
2
  var is = (type, arg) => arg?.constructor === type;
3
3
 
4
- // src/nnn/c.ts
5
- var _c = (node, prefix, result, split) => {
6
- const queue = [[node, prefix]];
7
- while (queue.length > 0) {
8
- const [style0, prefix0] = queue.shift() ?? [];
9
- if (style0 == null || prefix0 == null) {
10
- continue;
11
- }
12
- if (is(Array, style0)) {
13
- result.push(prefix0, prefix0 !== "" ? "{" : "", style0.join(";"), prefix0 !== "" ? "}" : "");
14
- } else {
15
- const todo = [];
16
- let attributes = [];
17
- let attributesPushed = false;
18
- for (const key in style0) {
19
- const value = style0[key];
20
- if (is(String, value) || is(Number, value)) {
21
- if (!attributesPushed) {
22
- attributesPushed = true;
23
- attributes = [];
24
- todo.push([attributes, prefix0]);
25
- }
26
- attributes.push(`${split(key).replace(/([A-Z])/g, (_, letter) => "-" + letter.toLowerCase())}:${value}`);
27
- } else if (value != null) {
28
- attributesPushed = false;
29
- const prefixN = [];
30
- const keyChunks = key.split(",");
31
- prefix0.split(",").forEach((prefixChunk) => keyChunks.forEach((keyChunk) => prefixN.push(prefixChunk + keyChunk)));
32
- todo.push([value, prefixN.join(",")]);
33
- }
34
- }
35
- queue.unshift(...todo);
36
- }
37
- }
38
- };
39
- var c = (root, splitter = "$$") => {
40
- const split = (text) => text.split(splitter)[0];
41
- const chunks = [];
42
- for (const key in root) {
43
- const value = root[key];
44
- if (value != null) {
45
- if (key[0] === "@") {
46
- chunks.push(split(key) + "{");
47
- _c(value, "", chunks, split);
48
- chunks.push("}");
49
- } else {
50
- _c(value, split(key), chunks, split);
51
- }
52
- }
53
- }
54
- return chunks.join("");
55
- };
56
-
57
4
  // src/nnn/h.ts
58
5
  var NS = {
59
6
  xlink: "http://www.w3.org/1999/xlink"
@@ -141,9 +88,9 @@ var chartable = ({
141
88
  const zxValues = [];
142
89
  const xLabels = [];
143
90
  const zLabels = [];
144
- table.querySelectorAll("tr").forEach((row, r) => row.querySelectorAll("td,th").forEach((col, c2) => {
91
+ table.querySelectorAll("tr").forEach((row, r) => row.querySelectorAll("td,th").forEach((col, c) => {
145
92
  const x = r - 1;
146
- const z = c2 - +headerColumn;
93
+ const z = c - +headerColumn;
147
94
  const value = col.innerText;
148
95
  if (x >= 0 && z >= 0) {
149
96
  zxValues[z] = zxValues[z] ?? [];
@@ -303,6 +250,59 @@ var fixTypography = (node) => {
303
250
  // src/nnn/has.ts
304
251
  var has = (key, ref) => (is(String, key) || is(Number, key) || is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key);
305
252
 
253
+ // src/nnn/jc.ts
254
+ var _jc = (node, prefix, result, split) => {
255
+ const queue = [[node, prefix]];
256
+ while (queue.length > 0) {
257
+ const [style0, prefix0] = queue.shift() ?? [];
258
+ if (style0 == null || prefix0 == null) {
259
+ continue;
260
+ }
261
+ if (is(Array, style0)) {
262
+ result.push(prefix0, prefix0 !== "" ? "{" : "", style0.join(";"), prefix0 !== "" ? "}" : "");
263
+ } else {
264
+ const todo = [];
265
+ let attributes = [];
266
+ let attributesPushed = false;
267
+ for (const key in style0) {
268
+ const value = style0[key];
269
+ if (is(String, value) || is(Number, value)) {
270
+ if (!attributesPushed) {
271
+ attributesPushed = true;
272
+ attributes = [];
273
+ todo.push([attributes, prefix0]);
274
+ }
275
+ attributes.push(`${split(key).replace(/([A-Z])/g, (_, letter) => "-" + letter.toLowerCase())}:${value}`);
276
+ } else if (value != null) {
277
+ attributesPushed = false;
278
+ const prefixN = [];
279
+ const keyChunks = key.split(",");
280
+ prefix0.split(",").forEach((prefixChunk) => keyChunks.forEach((keyChunk) => prefixN.push(prefixChunk + keyChunk)));
281
+ todo.push([value, prefixN.join(",")]);
282
+ }
283
+ }
284
+ queue.unshift(...todo);
285
+ }
286
+ }
287
+ };
288
+ var jc = (root, splitter = "$$") => {
289
+ const split = (text) => text.split(splitter)[0];
290
+ const chunks = [];
291
+ for (const key in root) {
292
+ const value = root[key];
293
+ if (value != null) {
294
+ if (key[0] === "@") {
295
+ chunks.push(split(key) + "{");
296
+ _jc(value, "", chunks, split);
297
+ chunks.push("}");
298
+ } else {
299
+ _jc(value, split(key), chunks, split);
300
+ }
301
+ }
302
+ }
303
+ return chunks.join("");
304
+ };
305
+
306
306
  // src/nnn/jsOnParse.ts
307
307
  var jsOnParse = (handlers, text) => JSON.parse(text, (key, value) => {
308
308
  if (is(Object, value)) {
@@ -408,6 +408,7 @@ export {
408
408
  nanolight,
409
409
  locale,
410
410
  jsOnParse,
411
+ jc,
411
412
  is,
412
413
  has,
413
414
  h,
@@ -415,6 +416,5 @@ export {
415
416
  escapeValues,
416
417
  escape,
417
418
  eq,
418
- chartable,
419
- c
419
+ chartable
420
420
  };
package/package.json CHANGED
@@ -20,7 +20,8 @@
20
20
  "HyperScript",
21
21
  "in",
22
22
  "is",
23
- "jcss",
23
+ "jc",
24
+ "JS-to-CSS",
24
25
  "JSON",
25
26
  "jsOnParse",
26
27
  "locale",
@@ -42,5 +43,5 @@
42
43
  "types": "nnn.d.ts",
43
44
  "name": "@jackens/nnn",
44
45
  "type": "module",
45
- "version": "2024.3.2"
46
+ "version": "2024.3.3"
46
47
  }
package/readme.md CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Jackens’ JavaScript helpers.
4
4
 
5
- <sub>Version: <code class="version">2024.3.2</code></sub>
5
+ <sub>Version: <code class="version">2024.3.3</code></sub>
6
6
 
7
7
  ## Examples
8
8
 
9
- - [Chartable Demo](/nnn/chartable/)
10
- - [Chessboard Demo](/nnn/chessboard/)
11
- - [Documentation](/nnn/doc/)
12
- - [Gant Chart Demo](/nnn/gantt/)
13
- - [Responsive Web Design Demo](/nnn/rwd/)
9
+ - [Chartable Demo](https://jackens.github.io/nnn/chartable/)
10
+ - [Chessboard Demo](https://jackens.github.io/nnn/chessboard/)
11
+ - [Documentation](https://jackens.github.io/nnn/doc/)
12
+ - [Gant Chart Demo](https://jackens.github.io/nnn/gantt/)
13
+ - [Responsive Web Design Demo](https://jackens.github.io/nnn/rwd/)
14
14
 
15
15
  ## Installation
16
16
 
@@ -40,12 +40,11 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
40
40
 
41
41
  ## Exports
42
42
 
43
- - `CNode`: The type of arguments of the `c` helper.
44
- - `CRoot`: The type of arguments of the `c` helper.
45
43
  - `EscapeMap`: The type of arguments of the `escapeValues` and `escape` helpers.
46
44
  - `HArgs`: The type of arguments of the `h` and `s` helpers.
47
45
  - `HArgs1`: The type of arguments of the `h` and `s` helpers.
48
- - `c`: A simple CSS-in-JS helper.
46
+ - `JcNode`: The type of arguments of the `jc` helper.
47
+ - `JcRoot`: The type of arguments of the `jc` helper.
49
48
  - `chartable`: A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
50
49
  - `eq`: A helper that checks equality of the given arguments.
51
50
  - `escape`: A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
@@ -54,6 +53,7 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
54
53
  - `h`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
55
54
  - `has`: A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
56
55
  - `is`: A helper that checks if the given argument is of a certain type.
56
+ - `jc`: A simple CSS-in-JS helper.
57
57
  - `jsOnParse`: `JSON.parse` with “JavaScript turned on”.
58
58
  - `locale`: Language translations helper.
59
59
  - `nanolight`: A generic helper for syntax highlighting (see also `nanolightJs`).
@@ -66,24 +66,6 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
66
66
  - `s`: A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
67
67
  - `uuid1`: A helper that generates a UUID v1 identifier (with a creation timestamp).
68
68
 
69
- ### CNode
70
-
71
- ```ts
72
- type CNode = {
73
- [attributeOrSelector: string]: string | number | CNode | undefined;
74
- };
75
- ```
76
-
77
- The type of arguments of the `c` helper.
78
-
79
- ### CRoot
80
-
81
- ```ts
82
- type CRoot = Partial<Record<PropertyKey, CNode>>;
83
- ```
84
-
85
- The type of arguments of the `c` helper.
86
-
87
69
  ### EscapeMap
88
70
 
89
71
  ```ts
@@ -108,217 +90,23 @@ type HArgs1 = Partial<Record<PropertyKey, any>> | null | undefined | Node | stri
108
90
 
109
91
  The type of arguments of the `h` and `s` helpers.
110
92
 
111
- ### c
93
+ ### JcNode
112
94
 
113
95
  ```ts
114
- const c: (root: CRoot, splitter?: string) => string;
115
- ```
116
-
117
- A simple CSS-in-JS helper.
118
-
119
- The `root` parameter provides a hierarchical description of CSS rules.
120
-
121
- - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
122
- - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
123
- - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
124
- - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
125
- - Top-level keys that begin with `@` are not concatenated with sub-object keys.
126
-
127
- #### Usage Examples
128
-
129
- ```js
130
- const actual = c({
131
- a: {
132
- color: 'red',
133
- margin: 1,
134
- '.c': { margin: 2, padding: 2 },
135
- padding: 1
136
- }
137
- })
138
-
139
- const expected = `
140
- a{
141
- color:red;
142
- margin:1
143
- }
144
- a.c{
145
- margin:2;
146
- padding:2
147
- }
148
- a{
149
- padding:1
150
- }`.replace(/\n\s*/g, '')
151
-
152
- expect(actual).toStrictEqual(expected)
153
- ```
154
-
155
- ```js
156
- const actual = c({
157
- a: {
158
- '.b': {
159
- color: 'red',
160
- margin: 1,
161
- '.c': { margin: 2, padding: 2 },
162
- padding: 1
163
- }
164
- }
165
- })
166
-
167
- const expected = `
168
- a.b{
169
- color:red;
170
- margin:1
171
- }
172
- a.b.c{
173
- margin:2;
174
- padding:2
175
- }
176
- a.b{
177
- padding:1
178
- }`.replace(/\n\s*/g, '')
179
-
180
- expect(actual).toStrictEqual(expected)
181
- ```
182
-
183
- ```js
184
- const actual = c({
185
- '@font-face$$1': {
186
- fontFamily: 'Jackens',
187
- src$$1: 'url(otf/jackens.otf)',
188
- src$$2: "url(otf/jackens.otf) format('opentype')," +
189
- "url(svg/jackens.svg) format('svg')",
190
- fontWeight: 'normal',
191
- fontStyle: 'normal'
192
- },
193
- '@font-face$$2': {
194
- fontFamily: 'C64',
195
- src: 'url(fonts/C64_Pro_Mono-STYLE.woff)'
196
- },
197
- '@keyframes spin': {
198
- '0%': { transform: 'rotate(0deg)' },
199
- '100%': { transform: 'rotate(360deg)' }
200
- },
201
- div: {
202
- border: 'solid red 1px',
203
- '.c1': { 'background-color': '#000' },
204
- ' .c1': { backgroundColor: 'black' },
205
- '.c2': { backgroundColor: 'rgb(0,0,0)' }
206
- },
207
- '@media(min-width:200px)': {
208
- div: { margin: 0, padding: 0 },
209
- span: { color: '#000' }
210
- }
211
- })
212
-
213
- const expected = `
214
- @font-face{
215
- font-family:Jackens;
216
- src:url(otf/jackens.otf);
217
- src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
218
- font-weight:normal;
219
- font-style:normal
220
- }
221
- @font-face{
222
- font-family:C64;
223
- src:url(fonts/C64_Pro_Mono-STYLE.woff)
224
- }
225
- @keyframes spin{
226
- 0%{
227
- transform:rotate(0deg)
228
- }
229
- 100%{
230
- transform:rotate(360deg)
231
- }
232
- }
233
- div{
234
- border:solid red 1px
235
- }
236
- div.c1{
237
- background-color:#000
238
- }
239
- div .c1{
240
- background-color:black
241
- }
242
- div.c2{
243
- background-color:rgb(0,0,0)
244
- }
245
- @media(min-width:200px){
246
- div{
247
- margin:0;
248
- padding:0
249
- }
250
- span{
251
- color:#000
252
- }
253
- }`.replace(/\n\s*/g, '')
254
-
255
- expect(actual).toStrictEqual(expected)
256
- ```
257
-
258
- ```js
259
- const actual = c({
260
- a: {
261
- '.b,.c': {
262
- margin: 1,
263
- '.d': {
264
- margin: 2
265
- }
266
- }
267
- }
268
- })
269
-
270
- const expected = `
271
- a.b,a.c{
272
- margin:1
273
- }
274
- a.b.d,a.c.d{
275
- margin:2
276
- }`.replace(/\n\s*/g, '')
277
-
278
- expect(actual).toStrictEqual(expected)
96
+ type JcNode = {
97
+ [attributeOrSelector: string]: string | number | JcNode | undefined;
98
+ };
279
99
  ```
280
100
 
281
- ```js
282
- const actual = c({
283
- '.b,.c': {
284
- margin: 1,
285
- '.d': {
286
- margin: 2
287
- }
288
- }
289
- })
101
+ The type of arguments of the `jc` helper.
290
102
 
291
- const expected = `
292
- .b,.c{
293
- margin:1
294
- }
295
- .b.d,.c.d{
296
- margin:2
297
- }`.replace(/\n\s*/g, '')
103
+ ### JcRoot
298
104
 
299
- expect(actual).toStrictEqual(expected)
105
+ ```ts
106
+ type JcRoot = Partial<Record<PropertyKey, JcNode>>;
300
107
  ```
301
108
 
302
- ```js
303
- const actual = c({
304
- '.a,.b': {
305
- margin: 1,
306
- '.c,.d': {
307
- margin: 2
308
- }
309
- }
310
- })
311
-
312
- const expected = `
313
- .a,.b{
314
- margin:1
315
- }
316
- .a.c,.a.d,.b.c,.b.d{
317
- margin:2
318
- }`.replace(/\n\s*/g, '')
319
-
320
- expect(actual).toStrictEqual(expected)
321
- ```
109
+ The type of arguments of the `jc` helper.
322
110
 
323
111
  ### chartable
324
112
 
@@ -665,6 +453,218 @@ try {
665
453
  expect(is(Number, num)).toBeTrue()
666
454
  ```
667
455
 
456
+ ### jc
457
+
458
+ ```ts
459
+ const jc: (root: JcRoot, splitter?: string) => string;
460
+ ```
461
+
462
+ A simple CSS-in-JS helper.
463
+
464
+ The `root` parameter provides a hierarchical description of CSS rules.
465
+
466
+ - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
467
+ - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
468
+ - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
469
+ - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
470
+ - Top-level keys that begin with `@` are not concatenated with sub-object keys.
471
+
472
+ #### Usage Examples
473
+
474
+ ```js
475
+ const actual = jc({
476
+ a: {
477
+ color: 'red',
478
+ margin: 1,
479
+ '.c': { margin: 2, padding: 2 },
480
+ padding: 1
481
+ }
482
+ })
483
+
484
+ const expected = `
485
+ a{
486
+ color:red;
487
+ margin:1
488
+ }
489
+ a.c{
490
+ margin:2;
491
+ padding:2
492
+ }
493
+ a{
494
+ padding:1
495
+ }`.replace(/\n\s*/g, '')
496
+
497
+ expect(actual).toStrictEqual(expected)
498
+ ```
499
+
500
+ ```js
501
+ const actual = jc({
502
+ a: {
503
+ '.b': {
504
+ color: 'red',
505
+ margin: 1,
506
+ '.c': { margin: 2, padding: 2 },
507
+ padding: 1
508
+ }
509
+ }
510
+ })
511
+
512
+ const expected = `
513
+ a.b{
514
+ color:red;
515
+ margin:1
516
+ }
517
+ a.b.c{
518
+ margin:2;
519
+ padding:2
520
+ }
521
+ a.b{
522
+ padding:1
523
+ }`.replace(/\n\s*/g, '')
524
+
525
+ expect(actual).toStrictEqual(expected)
526
+ ```
527
+
528
+ ```js
529
+ const actual = jc({
530
+ '@font-face$$1': {
531
+ fontFamily: 'Jackens',
532
+ src$$1: 'url(otf/jackens.otf)',
533
+ src$$2: "url(otf/jackens.otf) format('opentype')," +
534
+ "url(svg/jackens.svg) format('svg')",
535
+ fontWeight: 'normal',
536
+ fontStyle: 'normal'
537
+ },
538
+ '@font-face$$2': {
539
+ fontFamily: 'C64',
540
+ src: 'url(fonts/C64_Pro_Mono-STYLE.woff)'
541
+ },
542
+ '@keyframes spin': {
543
+ '0%': { transform: 'rotate(0deg)' },
544
+ '100%': { transform: 'rotate(360deg)' }
545
+ },
546
+ div: {
547
+ border: 'solid red 1px',
548
+ '.c1': { 'background-color': '#000' },
549
+ ' .c1': { backgroundColor: 'black' },
550
+ '.c2': { backgroundColor: 'rgb(0,0,0)' }
551
+ },
552
+ '@media(min-width:200px)': {
553
+ div: { margin: 0, padding: 0 },
554
+ span: { color: '#000' }
555
+ }
556
+ })
557
+
558
+ const expected = `
559
+ @font-face{
560
+ font-family:Jackens;
561
+ src:url(otf/jackens.otf);
562
+ src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
563
+ font-weight:normal;
564
+ font-style:normal
565
+ }
566
+ @font-face{
567
+ font-family:C64;
568
+ src:url(fonts/C64_Pro_Mono-STYLE.woff)
569
+ }
570
+ @keyframes spin{
571
+ 0%{
572
+ transform:rotate(0deg)
573
+ }
574
+ 100%{
575
+ transform:rotate(360deg)
576
+ }
577
+ }
578
+ div{
579
+ border:solid red 1px
580
+ }
581
+ div.c1{
582
+ background-color:#000
583
+ }
584
+ div .c1{
585
+ background-color:black
586
+ }
587
+ div.c2{
588
+ background-color:rgb(0,0,0)
589
+ }
590
+ @media(min-width:200px){
591
+ div{
592
+ margin:0;
593
+ padding:0
594
+ }
595
+ span{
596
+ color:#000
597
+ }
598
+ }`.replace(/\n\s*/g, '')
599
+
600
+ expect(actual).toStrictEqual(expected)
601
+ ```
602
+
603
+ ```js
604
+ const actual = jc({
605
+ a: {
606
+ '.b,.c': {
607
+ margin: 1,
608
+ '.d': {
609
+ margin: 2
610
+ }
611
+ }
612
+ }
613
+ })
614
+
615
+ const expected = `
616
+ a.b,a.c{
617
+ margin:1
618
+ }
619
+ a.b.d,a.c.d{
620
+ margin:2
621
+ }`.replace(/\n\s*/g, '')
622
+
623
+ expect(actual).toStrictEqual(expected)
624
+ ```
625
+
626
+ ```js
627
+ const actual = jc({
628
+ '.b,.c': {
629
+ margin: 1,
630
+ '.d': {
631
+ margin: 2
632
+ }
633
+ }
634
+ })
635
+
636
+ const expected = `
637
+ .b,.c{
638
+ margin:1
639
+ }
640
+ .b.d,.c.d{
641
+ margin:2
642
+ }`.replace(/\n\s*/g, '')
643
+
644
+ expect(actual).toStrictEqual(expected)
645
+ ```
646
+
647
+ ```js
648
+ const actual = jc({
649
+ '.a,.b': {
650
+ margin: 1,
651
+ '.c,.d': {
652
+ margin: 2
653
+ }
654
+ }
655
+ })
656
+
657
+ const expected = `
658
+ .a,.b{
659
+ margin:1
660
+ }
661
+ .a.c,.a.d,.b.c,.b.d{
662
+ margin:2
663
+ }`.replace(/\n\s*/g, '')
664
+
665
+ expect(actual).toStrictEqual(expected)
666
+ ```
667
+
668
668
  ### jsOnParse
669
669
 
670
670
  ```ts
@@ -783,8 +783,15 @@ A helper for highlighting JavaScript.
783
783
  ```js
784
784
  const codeJs = 'const answerToLifeTheUniverseAndEverything = 42'
785
785
 
786
- expect(h('pre', ['code', ...nanolightJs(codeJs)]).outerHTML).toStrictEqual(
787
- '<pre><code><span class="keyword">const</span> <span class="literal">answerToLifeTheUniverseAndEverything</span> <span class="operator">=</span> <span class="number">42</span></code></pre>')
786
+ expect(nanolightJs(codeJs)).toStrictEqual([
787
+ ['span', { class: 'keyword' }, 'const'],
788
+ ' ',
789
+ ['span', { class: 'literal' }, 'answerToLifeTheUniverseAndEverything'],
790
+ ' ',
791
+ ['span', { class: 'operator' }, '='],
792
+ ' ',
793
+ ['span', { class: 'number' }, '42']
794
+ ])
788
795
  ```
789
796
 
790
797
  ### omit