@jackens/nnn 2025.9.7 → 2025.11.4

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 +22 -11
  2. package/nnn.js +27 -2
  3. package/package.json +3 -1
  4. package/readme.md +33 -4
package/nnn.d.ts CHANGED
@@ -4,17 +4,6 @@ export type CNode = {
4
4
  };
5
5
  /** Argument type for the `c` helper. */
6
6
  export type CRoot = Record<PropertyKey, CNode>;
7
- /** Argument type accepted by the `escape_values` and `escape` helpers. */
8
- export type EscapeMap = Map<unknown, (value?: unknown) => string>;
9
- declare const IS_FINITE: unique symbol;
10
- /** `number` type excluding `±Infinity` and `NaN`. */
11
- export type FiniteNumber = number & {
12
- readonly [IS_FINITE]: true;
13
- };
14
- /** Argument type for the `h` and `s` helpers. */
15
- export type HArgs1 = Record<PropertyKey, unknown> | null | undefined | Node | string | number | HArgs;
16
- /** Argument type for the `h` and `s` helpers. */
17
- export type HArgs = [string | Node, ...HArgs1[]];
18
7
  /**
19
8
  * A minimal JS-to-CSS (CSS‑in‑JS) helper.
20
9
  *
@@ -27,14 +16,31 @@ export type HArgs = [string | Node, ...HArgs1[]];
27
16
  * - Top-level keys beginning with `@` (at-rules) are not concatenated with parent keys.
28
17
  */
29
18
  export declare const c: (root: CRoot, splitter?: string) => string;
19
+ /**
20
+ * A responsive‑web‑design helper that generates CSS rules for a grid layout.
21
+ *
22
+ * - `root` and `selector` specify where to apply the generated rules (see `c`).
23
+ * - `cell_width_px` and `cell_height_px` specify the base cell dimensions in pixels.
24
+ * - Each entry in `specs` is a tuple of:
25
+ * - `max_width`: maximum number of cells in a row (viewport width breakpoint).
26
+ * - `width` (optional, default: `1`): number of cells occupied by the element.
27
+ * - `height` (optional): number of cells in height occupied by the element.
28
+ */
29
+ export declare const rwd: (root: CRoot, selector: string, cell_width_px: number, cell_height_px: number, ...specs: [number, number?, number?][]) => void;
30
30
  /** A tiny CSV parsing helper. */
31
31
  export declare const csv_parse: (csv: string, separator?: string) => string[][];
32
+ /** Argument type accepted by the `escape_values` and `escape` helpers. */
33
+ export type EscapeMap = Map<unknown, (value?: unknown) => string>;
32
34
  /** Escapes array `values` using the provided `escape_map`. */
33
35
  export declare const escape_values: (escape_map: EscapeMap, values: unknown[]) => string[];
34
36
  /** Escapes interpolated template `values` using the provided `escape_map`. */
35
37
  export declare const escape: (escape_map: EscapeMap, template: TemplateStringsArray, ...values: unknown[]) => string;
36
38
  /** Applies Polish‑specific typographic corrections. */
37
39
  export declare const fix_typography: (node: Node) => void;
40
+ /** Argument type for the `h` and `s` helpers. */
41
+ export type HArgs1 = Record<PropertyKey, unknown> | null | undefined | Node | string | number | HArgs;
42
+ /** Argument type for the `h` and `s` helpers. */
43
+ export type HArgs = [string | Node, ...HArgs1[]];
38
44
  /**
39
45
  * A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
40
46
  *
@@ -79,6 +85,11 @@ export declare const svg_use: (id: string, ...args: HArgs1[]) => SVGSVGElement;
79
85
  export declare const has_own: (ref: unknown, key: unknown) => boolean;
80
86
  /** Checks whether the argument is an array. */
81
87
  export declare const is_array: (arg: unknown) => arg is unknown[];
88
+ declare const IS_FINITE: unique symbol;
89
+ /** `number` type excluding `±Infinity` and `NaN`. */
90
+ export type FiniteNumber = number & {
91
+ readonly [IS_FINITE]: true;
92
+ };
82
93
  /** Checks whether the argument is a finite number (excluding `±Infinity` and `NaN`). */
83
94
  export declare const is_finite_number: (arg: unknown) => arg is FiniteNumber;
84
95
  /** Checks whether the argument is a number. */
package/nnn.js CHANGED
@@ -2,7 +2,7 @@
2
2
  var _c = (node, prefix, result, splitter) => {
3
3
  const queue = [[node, prefix]];
4
4
  while (queue.length > 0) {
5
- const [style_0, prefix_0] = queue.shift() ?? [];
5
+ const [style_0, prefix_0] = queue.shift();
6
6
  if (style_0 == null || prefix_0 == null) {
7
7
  continue;
8
8
  }
@@ -50,6 +50,30 @@ var c = (root, splitter = "$$") => {
50
50
  }
51
51
  return chunks.join("");
52
52
  };
53
+ var rwd = (root, selector, cell_width_px, cell_height_px, ...specs) => {
54
+ const main = pro(root)[selector];
55
+ main.boxSizing = "border-box";
56
+ main.display = "block";
57
+ main.float = "left";
58
+ main.width = "100%";
59
+ main.height = `${cell_height_px}px`;
60
+ specs.sort(([a], [b]) => a - b);
61
+ for (let [max_width, width, height] of specs) {
62
+ const node = max_width === 1 ? main : pro(root)[`@media(min-width:${cell_width_px * max_width}px)`][selector];
63
+ width ??= 1;
64
+ let gcd = 100 * width;
65
+ let tmp = max_width;
66
+ while (tmp) {
67
+ [gcd, tmp] = [tmp, gcd % tmp];
68
+ }
69
+ const w_100_per_gcd = 100 * width / gcd;
70
+ node.width = max_width === gcd ? `${w_100_per_gcd}%` : `calc(${w_100_per_gcd}% / ${max_width / gcd})`;
71
+ if (height != null) {
72
+ node.height = `${cell_height_px * height}px`;
73
+ }
74
+ }
75
+ console.log(root);
76
+ };
53
77
  var csv_parse = (csv, separator = ",") => {
54
78
  const main_pattern = /\n|(?<!")("(?:[^"]|"")*")(?!")/g;
55
79
  const line_pattern = new RegExp(`${separator}|(?<!")\\s*"((?:[^"]|"")*)"\\s*(?!")`, "g");
@@ -134,7 +158,7 @@ var _h = (namespace_uri) => {
134
158
  }
135
159
  }
136
160
  }
137
- } else if (is_string(arg)) {
161
+ } else if (is_string(arg) || is_number(arg)) {
138
162
  child = document.createTextNode(arg);
139
163
  }
140
164
  if (child != null) {
@@ -214,6 +238,7 @@ export {
214
238
  uuid_v1,
215
239
  svg_use,
216
240
  s,
241
+ rwd,
217
242
  pro,
218
243
  pl_ural,
219
244
  pick,
package/package.json CHANGED
@@ -26,6 +26,8 @@
26
26
  "nnn",
27
27
  "omit",
28
28
  "pick",
29
+ "RWD",
30
+ "Responsive Web Design",
29
31
  "SVG",
30
32
  "typography",
31
33
  "uuid",
@@ -36,5 +38,5 @@
36
38
  "name": "@jackens/nnn",
37
39
  "type": "module",
38
40
  "types": "nnn.d.ts",
39
- "version": "2025.9.7"
41
+ "version": "2025.11.4"
40
42
  }
package/readme.md CHANGED
@@ -53,6 +53,7 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
53
53
  - [`pick`](#pick): Runtime implementation of TypeScript’s `Pick` (see also `omit`).
54
54
  - [`pl_ural`](#pl_ural): Chooses the appropriate Polish noun form based on a numeric value.
55
55
  - [`pro`](#pro): A `Proxy`-based helper that safely creates nested structures on access and allows deep assignment without guards.
56
+ - [`rwd`](#rwd): A responsive‑web‑design helper that generates CSS rules for a grid layout.
56
57
  - [`s`](#s): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
57
58
  - [`svg_use`](#svg_use): Shorthand for: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
58
59
  - [`uuid_v1`](#uuid_v1): Generates a UUID v1 (time-based) identifier.
@@ -458,6 +459,11 @@ expect(h('span', 'text').outerHTML).to.deep.equal('<span>text</span>')
458
459
  expect(h('span', { $innerText: 'text' }).outerHTML).to.deep.equal('<span>text</span>')
459
460
  ```
460
461
 
462
+ ```ts
463
+ expect(h('span', '42').outerHTML).to.deep.equal('<span>42</span>')
464
+ expect(h('span', 42).outerHTML).to.deep.equal('<span>42</span>')
465
+ ```
466
+
461
467
  ```ts
462
468
  expect(h('div', { style: 'margin:0;padding:0' }).outerHTML)
463
469
  .to.deep.equal('<div style="margin:0;padding:0"></div>')
@@ -668,16 +674,25 @@ JavaScript syntax highlighting helper (built on `nanolight`).
668
674
  #### Usage Examples
669
675
 
670
676
  ```ts
671
- const code_js = 'const answerToLifeTheUniverseAndEverything = 42'
677
+ const code_js = "const answer_to_life_the_universe_and_everything = { 42: 42 }['42'] /* 42 */"
678
+
679
+ console.log(nanolight_js(code_js))
672
680
 
673
681
  expect(nanolight_js(code_js)).to.deep.equal([
674
682
  ['span', { class: 'keyword' }, 'const'],
675
683
  ' ',
676
- ['span', { class: 'literal' }, 'answerToLifeTheUniverseAndEverything'],
684
+ ['span', { class: 'literal' }, 'answer_to_life_the_universe_and_everything'],
677
685
  ' ',
678
686
  ['span', { class: 'operator' }, '='],
687
+ ' { ',
688
+ ['span', { class: 'number' }, '42'],
689
+ ['span', { class: 'operator' }, ':'],
679
690
  ' ',
680
- ['span', { class: 'number' }, '42']
691
+ ['span', { class: 'number' }, '42'],
692
+ ' }[',
693
+ ['span', { class: 'string' }, "'42'"],
694
+ '] ',
695
+ ['span', { class: 'comment' }, '/* 42 */']
681
696
  ])
682
697
  ```
683
698
 
@@ -777,6 +792,21 @@ pro(ref).one.two.three.four = 1234
777
792
  expect(ref).to.deep.equal({ one: { two: { three: { four: 1234 } } } })
778
793
  ```
779
794
 
795
+ ### rwd
796
+
797
+ ```ts
798
+ const rwd: (root: CRoot, selector: string, cell_width_px: number, cell_height_px: number, ...specs: [number, number?, number?][]) => void;
799
+ ```
800
+
801
+ A responsive‑web‑design helper that generates CSS rules for a grid layout.
802
+
803
+ - `root` and `selector` specify where to apply the generated rules (see `c`).
804
+ - `cell_width_px` and `cell_height_px` specify the base cell dimensions in pixels.
805
+ - Each entry in `specs` is a tuple of:
806
+ - `max_width`: maximum number of cells in a row (viewport width breakpoint).
807
+ - `width` (optional, default: `1`): number of cells occupied by the element.
808
+ - `height` (optional): number of cells in height occupied by the element.
809
+
780
810
  ### s
781
811
 
782
812
  ```ts
@@ -812,7 +842,6 @@ Shorthand for: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
812
842
 
813
843
  ```ts
814
844
  const uuid_v1: (date?: Date, node?: string) => string;
815
- export {};
816
845
  ```
817
846
 
818
847
  Generates a UUID v1 (time-based) identifier.