@jackens/nnn 2023.8.19 → 2023.8.25
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/nnn.d.ts +52 -50
- package/nnn.js +101 -93
- package/package.json +1 -1
package/nnn.d.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The type of arguments of the
|
|
2
|
+
* The type of arguments of the `css` helper.
|
|
3
3
|
*/
|
|
4
|
-
export type
|
|
5
|
-
[attributeOrSelector: string]: string | number |
|
|
4
|
+
export type CNode = {
|
|
5
|
+
[attributeOrSelector: string]: string | number | CNode;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* The type of arguments of the
|
|
9
|
+
* The type of arguments of the `css` helper.
|
|
10
10
|
*/
|
|
11
|
-
export type
|
|
11
|
+
export type CRoot = Record<string, CNode>;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* The type of arguments of the
|
|
14
|
+
* The type of arguments of the `escapeValues` and `escape` helpers.
|
|
15
15
|
*/
|
|
16
|
-
export type
|
|
16
|
+
export type EscapeMap = Map<any, (value?: any) => string>;
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* The type of arguments of the
|
|
19
|
+
* The type of arguments of the `h` and `s` helpers.
|
|
20
20
|
*/
|
|
21
|
-
export type
|
|
21
|
+
export type HArgs = [
|
|
22
22
|
string | Node,
|
|
23
|
-
...(Record<string, any> | null | undefined | Node | string | number |
|
|
23
|
+
...(Record<string, any> | null | undefined | Node | string | number | HArgs)[]
|
|
24
24
|
];
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -34,42 +34,44 @@ export type $HArgs = [
|
|
|
34
34
|
* - 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}`).
|
|
35
35
|
* - Top-level keys that begin with `@` are not concatenated with sub-object keys.
|
|
36
36
|
*/
|
|
37
|
-
export function
|
|
37
|
+
export function css(root: CRoot, splitter?: string): string;
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
|
|
41
41
|
*
|
|
42
42
|
* Options:
|
|
43
43
|
* - `bottom`: bottom padding (for X axis labels)
|
|
44
|
+
* - `gapX`: X axis spacing
|
|
45
|
+
* - `gapY`: Y axis spacing
|
|
44
46
|
* - `headerColumn`: flag indicating that `table` has a header column (with X axis labels)
|
|
45
47
|
* - `headerRow`: flag indicating that `table` has a header row (with data series labels)
|
|
48
|
+
* - `id`: chart id
|
|
46
49
|
* - `left`: left padding (for data series labels)
|
|
50
|
+
* - `maxY`: number of Y axis lines
|
|
47
51
|
* - `right`: right padding (for data series labels)
|
|
48
52
|
* - `singleScale`: flag to force single scale
|
|
49
53
|
* - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
|
|
50
54
|
* - `title`: chart title
|
|
51
55
|
* - `top`: top padding (for the title)
|
|
52
|
-
* - `xGap`: X axis spacing
|
|
53
56
|
* - `xLabels`: X axis labels
|
|
54
|
-
* - `yGap`: Y axis spacing
|
|
55
|
-
* - `yMax`: number of Y axis lines
|
|
56
57
|
* - `zLabels`: data series labels
|
|
57
58
|
* - `zxY`: chart data
|
|
58
59
|
*/
|
|
59
|
-
export function
|
|
60
|
+
export function chartable(options?: {
|
|
60
61
|
bottom?: number;
|
|
62
|
+
gapX?: number;
|
|
63
|
+
gapY?: number;
|
|
61
64
|
headerColumn?: boolean;
|
|
62
65
|
headerRow?: boolean;
|
|
66
|
+
id?: string;
|
|
63
67
|
left?: number;
|
|
68
|
+
maxY?: number;
|
|
64
69
|
right?: number;
|
|
65
70
|
singleScale?: boolean;
|
|
66
71
|
table?: HTMLTableElement;
|
|
67
72
|
title?: string;
|
|
68
73
|
top?: number;
|
|
69
|
-
xGap?: number;
|
|
70
74
|
xLabels?: string[];
|
|
71
|
-
yGap?: number;
|
|
72
|
-
yMax?: number;
|
|
73
75
|
zLabels?: string[];
|
|
74
76
|
zxY?: number[][];
|
|
75
77
|
}): SVGSVGElement;
|
|
@@ -77,30 +79,30 @@ export function $chartable(options?: {
|
|
|
77
79
|
/**
|
|
78
80
|
* A helper that checks equality of the given arguments.
|
|
79
81
|
*/
|
|
80
|
-
export function
|
|
82
|
+
export function eq(x: any, y: any): boolean;
|
|
81
83
|
|
|
82
84
|
/**
|
|
83
85
|
* A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
|
|
84
86
|
*/
|
|
85
|
-
export function
|
|
87
|
+
export function escape(escapeMap: EscapeMap, template: TemplateStringsArray, ...values: any[]): string;
|
|
86
88
|
|
|
87
89
|
/**
|
|
88
90
|
* A generic helper for escaping `values` by given `escapeMap`.
|
|
89
91
|
*/
|
|
90
|
-
export function
|
|
92
|
+
export function escapeValues(escapeMap: EscapeMap, values: any[]): string[];
|
|
91
93
|
|
|
92
94
|
/**
|
|
93
95
|
* A helper that implements typographic corrections specific to Polish typography.
|
|
94
96
|
*/
|
|
95
|
-
export function
|
|
97
|
+
export function fixTypography(node: Node): void;
|
|
96
98
|
|
|
97
99
|
/**
|
|
98
100
|
* A convenient helper for getting values of nested objects.
|
|
99
101
|
*/
|
|
100
|
-
export function
|
|
102
|
+
export function get(defaultValue: any, ref: any, ...keys: (string | number | symbol)[]): any;
|
|
101
103
|
|
|
102
104
|
/**
|
|
103
|
-
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also
|
|
105
|
+
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
|
|
104
106
|
*
|
|
105
107
|
* - The first argument of type `string` specifies the tag of the element to be created.
|
|
106
108
|
* - The first argument of type `Node` specifies the element to be modified.
|
|
@@ -112,58 +114,58 @@ export function $get(defaultValue: any, ref: any, ...keys: (string | number | sy
|
|
|
112
114
|
* - All other arguments of type `null` or `undefined` are simply ignored.
|
|
113
115
|
* - All other arguments of type `Node` are appended to the element being created or modified.
|
|
114
116
|
* - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
|
|
115
|
-
* - All other arguments of type
|
|
117
|
+
* - All other arguments of type `HArgs` are passed to `h` and the results are appended to the element being created or modified.
|
|
116
118
|
*/
|
|
117
|
-
export function
|
|
118
|
-
export function
|
|
119
|
-
export function
|
|
119
|
+
export function h<T extends keyof HTMLElementTagNameMap>(tag: T, ...args: HArgs[1][]): HTMLElementTagNameMap[T];
|
|
120
|
+
export function h<N extends Node>(node: N, ...args: HArgs[1][]): N;
|
|
121
|
+
export function h(...args: HArgs): Node;
|
|
120
122
|
|
|
121
123
|
/**
|
|
122
124
|
* A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
|
|
123
125
|
*/
|
|
124
|
-
export function
|
|
126
|
+
export function has(key: any, ref: any): boolean;
|
|
125
127
|
|
|
126
128
|
/**
|
|
127
129
|
* A helper that checks if the given argument is of a certain type.
|
|
128
130
|
*/
|
|
129
|
-
export function
|
|
130
|
-
export function
|
|
131
|
-
export function
|
|
132
|
-
export function
|
|
133
|
-
export function
|
|
134
|
-
export function
|
|
135
|
-
export function
|
|
131
|
+
export function is(type: BigIntConstructor, arg: any): arg is bigint;
|
|
132
|
+
export function is(type: BooleanConstructor, arg: any): arg is boolean;
|
|
133
|
+
export function is(type: NumberConstructor, arg: any): arg is number;
|
|
134
|
+
export function is(type: StringConstructor, arg: any): arg is string;
|
|
135
|
+
export function is(type: SymbolConstructor, arg: any): arg is symbol;
|
|
136
|
+
export function is(type: undefined, arg: any): arg is null | undefined;
|
|
137
|
+
export function is<T extends abstract new (...args: any[]) => any>(type: T, arg: any): arg is InstanceType<T>;
|
|
136
138
|
|
|
137
139
|
/**
|
|
138
140
|
* Language translations helper.
|
|
139
141
|
*/
|
|
140
|
-
export function
|
|
142
|
+
export function locale(
|
|
141
143
|
locales: Record<string, Record<string, string | Record<string, string>>>,
|
|
142
144
|
defaultLanguage: string,
|
|
143
145
|
languages?: readonly string[]
|
|
144
146
|
): (text?: string, version?: string) => string;
|
|
145
147
|
|
|
146
148
|
/**
|
|
147
|
-
* A generic helper for syntax highlighting (see also
|
|
149
|
+
* A generic helper for syntax highlighting (see also `nanolightJs`).
|
|
148
150
|
*/
|
|
149
|
-
export function
|
|
151
|
+
export function nanolight(
|
|
150
152
|
pattern: RegExp,
|
|
151
|
-
highlighters: ((chunk: string, index: number) =>
|
|
153
|
+
highlighters: ((chunk: string, index: number) => HArgs[1])[],
|
|
152
154
|
code: string
|
|
153
|
-
):
|
|
155
|
+
): HArgs[1][];
|
|
154
156
|
|
|
155
157
|
/**
|
|
156
158
|
* A helper for highlighting JavaScript.
|
|
157
159
|
*/
|
|
158
|
-
export function
|
|
160
|
+
export function nanolightJs(codeJs: string): HArgs[1][];
|
|
159
161
|
|
|
160
162
|
/**
|
|
161
163
|
* A helper for choosing the correct singular and plural.
|
|
162
164
|
*/
|
|
163
|
-
export function
|
|
165
|
+
export function plUral(singular: string, plural2: string, plural5: string, value: number): string;
|
|
164
166
|
|
|
165
167
|
/**
|
|
166
|
-
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also
|
|
168
|
+
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
|
|
167
169
|
*
|
|
168
170
|
* - The first argument of type `string` specifies the tag of the element to be created.
|
|
169
171
|
* - The first argument of type `Node` specifies the element to be modified.
|
|
@@ -175,16 +177,16 @@ export function $plUral(singular: string, plural2: string, plural5: string, valu
|
|
|
175
177
|
* - All other arguments of type `null` or `undefined` are simply ignored.
|
|
176
178
|
* - All other arguments of type `Node` are appended to the element being created or modified.
|
|
177
179
|
* - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
|
|
178
|
-
* - All other arguments of type
|
|
180
|
+
* - All other arguments of type `HArgs` are passed to `s` and the results are appended to the element being created or modified.
|
|
179
181
|
*/
|
|
180
|
-
export function
|
|
181
|
-
export function
|
|
182
|
-
export function
|
|
182
|
+
export function s<T extends keyof SVGElementTagNameMap>(tag: T, ...args: HArgs[1][]): SVGElementTagNameMap[T];
|
|
183
|
+
export function s<N extends Node>(node: N, ...args: HArgs[1][]): N;
|
|
184
|
+
export function s(...args: HArgs): Node;
|
|
183
185
|
|
|
184
186
|
/**
|
|
185
187
|
* A convenient helper for setting values of nested objects.
|
|
186
188
|
*/
|
|
187
|
-
export function
|
|
189
|
+
export function set(value: any, ref: any, ...keys: (string | number | symbol)[]): void;
|
|
188
190
|
|
|
189
191
|
/**
|
|
190
192
|
* A helper that generates a UUID v1 identifier (with a creation timestamp).
|
|
@@ -192,7 +194,7 @@ export function $set(value: any, ref: any, ...keys: (string | number | symbol)[]
|
|
|
192
194
|
* - The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`.
|
|
193
195
|
* Its value will be trimmed to last 12 characters and left padded with zeros.
|
|
194
196
|
*/
|
|
195
|
-
export function
|
|
197
|
+
export function uuid1(options?: {
|
|
196
198
|
date?: Date;
|
|
197
199
|
node?: string;
|
|
198
200
|
}): string;
|
package/nnn.js
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {[
|
|
3
3
|
* string | Node,
|
|
4
|
-
* ...(Record<string, any> | null | undefined | Node | string | number |
|
|
5
|
-
* ]}
|
|
4
|
+
* ...(Record<string, any> | null | undefined | Node | string | number | HArgs)[]
|
|
5
|
+
* ]} HArgs
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @typedef {{
|
|
10
|
-
* [attributeOrSelector: string]: string | number |
|
|
11
|
-
* }}
|
|
10
|
+
* [attributeOrSelector: string]: string | number | CNode;
|
|
11
|
+
* }} CNode
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @typedef {Record<string,
|
|
15
|
+
* @typedef {Record<string, CNode>} CRoot
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* @typedef {Map<any, (value?: any) => string>}
|
|
19
|
+
* @typedef {Map<any, (value?: any) => string>} EscapeMap
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
/** @type {
|
|
22
|
+
const _css = (
|
|
23
|
+
/** @type {CNode} */ node,
|
|
24
24
|
/** @type {string} */ prefix,
|
|
25
25
|
/** @type {string[]} */ result,
|
|
26
26
|
/** @type {(text: string) => string} */ split
|
|
27
27
|
) => {
|
|
28
|
-
const /** @type {[
|
|
28
|
+
const /** @type {[CNode | string[], string][]} */ queue = [[node, prefix]]
|
|
29
29
|
|
|
30
30
|
while (queue.length) {
|
|
31
31
|
const [style2, prefix2] = queue.shift() ?? []
|
|
@@ -34,17 +34,17 @@ const _c = (
|
|
|
34
34
|
continue
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
if (
|
|
37
|
+
if (is(Array, style2)) {
|
|
38
38
|
result.push(prefix2, prefix2 !== '' ? '{' : '', style2.join(';'), prefix2 !== '' ? '}' : '')
|
|
39
39
|
} else {
|
|
40
|
-
const /** @type {[
|
|
40
|
+
const /** @type {[CNode | string[], string][]} */ todo = []
|
|
41
41
|
let /** @type {string[]} */ attributes = []
|
|
42
42
|
let attributesPushed = false
|
|
43
43
|
|
|
44
44
|
for (const key in style2) {
|
|
45
45
|
const value = style2[key]
|
|
46
46
|
|
|
47
|
-
if (
|
|
47
|
+
if (is(String, value) || is(Number, value)) {
|
|
48
48
|
if (!attributesPushed) {
|
|
49
49
|
attributesPushed = true
|
|
50
50
|
attributes = []
|
|
@@ -73,7 +73,7 @@ const _c = (
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
export const
|
|
76
|
+
export const css = (/** @type {CRoot} */ root, splitter = '$$') => {
|
|
77
77
|
const split = (/** @type {string} */ text) => text.split(splitter)[0]
|
|
78
78
|
const /** @type {string[]} */ result = []
|
|
79
79
|
|
|
@@ -82,10 +82,10 @@ export const $c = (/** @type {$CRoot} */ root, splitter = '$$') => {
|
|
|
82
82
|
|
|
83
83
|
if (key[0] === '@') {
|
|
84
84
|
result.push(split(key) + '{')
|
|
85
|
-
|
|
85
|
+
_css(value, '', result, split)
|
|
86
86
|
result.push('}')
|
|
87
87
|
} else {
|
|
88
|
-
|
|
88
|
+
_css(value, split(key), result, split)
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -97,54 +97,57 @@ const _COLORS = ['#e22', '#e73', '#fc3', '#ad4', '#4d9', '#3be', '#45d', '#c3e']
|
|
|
97
97
|
/**
|
|
98
98
|
* @param {{
|
|
99
99
|
* bottom?: number;
|
|
100
|
+
* gapX?: number;
|
|
101
|
+
* gapY?: number;
|
|
100
102
|
* headerColumn?: boolean;
|
|
101
103
|
* headerRow?: boolean;
|
|
104
|
+
* id?: string;
|
|
102
105
|
* left?: number;
|
|
106
|
+
* maxY?: number;
|
|
103
107
|
* right?: number;
|
|
104
108
|
* singleScale?: boolean;
|
|
105
109
|
* table?: HTMLTableElement;
|
|
106
110
|
* title?: string;
|
|
107
111
|
* top?: number;
|
|
108
|
-
* xGap?: number;
|
|
109
112
|
* xLabels?: string[];
|
|
110
|
-
* yGap?: number;
|
|
111
|
-
* yMax?: number;
|
|
112
113
|
* zLabels?: string[];
|
|
113
114
|
* zxY?: number[][];
|
|
114
115
|
* }} options
|
|
115
116
|
*/
|
|
116
|
-
export const
|
|
117
|
+
export const chartable = ({
|
|
117
118
|
bottom = 50,
|
|
119
|
+
gapX = 70,
|
|
120
|
+
gapY = 30,
|
|
118
121
|
headerColumn = false,
|
|
119
122
|
headerRow = true,
|
|
123
|
+
id,
|
|
120
124
|
left = 200,
|
|
125
|
+
maxY = 10,
|
|
121
126
|
right = 200,
|
|
122
127
|
singleScale = false,
|
|
123
128
|
table,
|
|
124
129
|
title,
|
|
125
130
|
top = 70,
|
|
126
|
-
xGap = 70,
|
|
127
131
|
xLabels = [],
|
|
128
|
-
yGap = 30,
|
|
129
|
-
yMax = 10,
|
|
130
132
|
zLabels = [],
|
|
131
133
|
zxY = []
|
|
132
134
|
} = {}) => {
|
|
133
135
|
if (table != null) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
const zxYNotPassed = !zxY.length
|
|
137
|
+
const xLabelsNotPassed = !xLabels.length
|
|
138
|
+
const zLabelsNotPassed = !zLabels.length
|
|
139
|
+
|
|
137
140
|
table.querySelectorAll('tr').forEach((row, r) => row.querySelectorAll('td,th').forEach((col, c) => {
|
|
138
141
|
const x = r - +headerRow
|
|
139
142
|
const z = c - +headerColumn
|
|
140
143
|
// @ts-expect-error
|
|
141
144
|
const value = col.innerText
|
|
142
145
|
|
|
143
|
-
if (x >= 0 && z >= 0) {
|
|
144
|
-
|
|
145
|
-
} else if (x >= 0 && z < 0) {
|
|
146
|
+
if (x >= 0 && z >= 0 && zxYNotPassed) {
|
|
147
|
+
set(parseFloat(value), zxY, z, x)
|
|
148
|
+
} else if (x >= 0 && z < 0 && xLabelsNotPassed) {
|
|
146
149
|
xLabels[x] = value
|
|
147
|
-
} else if (x < 0 && z >= 0) {
|
|
150
|
+
} else if (x < 0 && z >= 0 && zLabelsNotPassed) {
|
|
148
151
|
zLabels[z] = value
|
|
149
152
|
}
|
|
150
153
|
}))
|
|
@@ -177,8 +180,13 @@ export const $chartable = ({
|
|
|
177
180
|
}
|
|
178
181
|
})
|
|
179
182
|
|
|
180
|
-
|
|
181
|
-
|
|
183
|
+
let cost = 0
|
|
184
|
+
|
|
185
|
+
ranges.forEach(([min, max]) => {
|
|
186
|
+
if (min < max) {
|
|
187
|
+
cost += 1 - (max - min) / (min1 <= min && max <= max1 ? max1 - min1 : max2 - min2)
|
|
188
|
+
}
|
|
189
|
+
})
|
|
182
190
|
|
|
183
191
|
if (bestScales[4] > cost) {
|
|
184
192
|
bestScales = [min1, max1, min2, max2, cost]
|
|
@@ -188,22 +196,22 @@ export const $chartable = ({
|
|
|
188
196
|
}
|
|
189
197
|
|
|
190
198
|
const [min1, max1, min2, max2] = bestScales
|
|
191
|
-
const
|
|
192
|
-
const xi = Array.from({ length:
|
|
193
|
-
const yi = Array.from({ length:
|
|
194
|
-
const w =
|
|
195
|
-
const h =
|
|
199
|
+
const maxX = zxY[0].length
|
|
200
|
+
const xi = Array.from({ length: maxX }, (_, x) => x * gapX)
|
|
201
|
+
const yi = Array.from({ length: maxY }, (_, y) => y * gapY)
|
|
202
|
+
const w = gapX * (maxX - 1)
|
|
203
|
+
const h = gapY * (maxY - 1)
|
|
196
204
|
const svgW = left + w + right
|
|
197
205
|
const svgH = top + h + bottom
|
|
198
|
-
const /** @type {
|
|
206
|
+
const /** @type {HArgs} */ graph = ['g', { transform: `translate(${left} ${top})` },
|
|
199
207
|
...yi.map(y => ['line', { x1: 0, x2: w, y1: y, y2: y, stroke: '#8888' }]),
|
|
200
208
|
...xi.map(x => ['line', { x1: x, x2: x, y1: 0, y2: h, stroke: '#8888' }])]
|
|
201
|
-
const /** @type {
|
|
202
|
-
const /** @type {
|
|
203
|
-
const /** @type {
|
|
204
|
-
const /** @type {
|
|
209
|
+
const /** @type {HArgs} */ lColors = ['g', { class: 'chartable-z-colors', transform: 'translate(-80 0)' }]
|
|
210
|
+
const /** @type {HArgs} */ lLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(-95 0)' }]
|
|
211
|
+
const /** @type {HArgs} */ rColors = ['g', { class: 'chartable-z-colors', transform: 'translate(80 0)' }]
|
|
212
|
+
const /** @type {HArgs} */ rLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(95 0)' }]
|
|
205
213
|
const yLabel = (/** @type {number} */ min, /** @type {number} */ max, /** @type {number} */ y) =>
|
|
206
|
-
(min + (max - min) * (
|
|
214
|
+
(min + (max - min) * (maxY - 1 - y) / (maxY - 1)).toFixed(2).replace(/\.?0+$/, '')
|
|
207
215
|
|
|
208
216
|
zxY.forEach((xa, z) => {
|
|
209
217
|
const cls = `chartable-z-${z + 1}`
|
|
@@ -213,16 +221,16 @@ export const $chartable = ({
|
|
|
213
221
|
if (min1 <= min && max <= max1) {
|
|
214
222
|
min = min1
|
|
215
223
|
max = max1
|
|
216
|
-
lColors.push(['circle', { class: cls, cx: 0, cy:
|
|
224
|
+
lColors.push(['circle', { class: cls, cx: 0, cy: gapY * (lColors.length - 2), r: 5, fill }])
|
|
217
225
|
lLabels.push(['text',
|
|
218
|
-
{ x: 0, y:
|
|
226
|
+
{ x: 0, y: gapY * (lLabels.length - 2), 'text-anchor': 'end', 'alignment-baseline': 'middle' },
|
|
219
227
|
zLabels[z]])
|
|
220
228
|
} else {
|
|
221
229
|
min = min2
|
|
222
230
|
max = max2
|
|
223
|
-
rColors.push(['circle', { class: cls, cx: 0, cy:
|
|
231
|
+
rColors.push(['circle', { class: cls, cx: 0, cy: gapY * (rColors.length - 2), r: 5, fill }])
|
|
224
232
|
rLabels.push(['text',
|
|
225
|
-
{ x: 0, y:
|
|
233
|
+
{ x: 0, y: gapY * (rLabels.length - 2), 'text-anchor': 'start', 'alignment-baseline': 'middle' },
|
|
226
234
|
zLabels[z]])
|
|
227
235
|
}
|
|
228
236
|
|
|
@@ -239,12 +247,12 @@ export const $chartable = ({
|
|
|
239
247
|
})
|
|
240
248
|
})
|
|
241
249
|
|
|
242
|
-
return
|
|
250
|
+
return s('svg', {
|
|
243
251
|
viewBox: `0 0 ${svgW} ${svgH}`,
|
|
244
252
|
width: `${svgW}px`,
|
|
245
253
|
height: `${svgH}px`,
|
|
246
254
|
class: 'chartable'
|
|
247
|
-
}, title != null
|
|
255
|
+
}, id != null ? { id } : null, title != null
|
|
248
256
|
? ['text',
|
|
249
257
|
{ class: 'chartable-title', x: svgW / 2, y: top / 2, 'text-anchor': 'middle', 'alignment-baseline': 'middle' },
|
|
250
258
|
title]
|
|
@@ -276,7 +284,7 @@ export const $chartable = ({
|
|
|
276
284
|
)
|
|
277
285
|
}
|
|
278
286
|
|
|
279
|
-
export const
|
|
287
|
+
export const eq = /** @returns {boolean} */ (/** @type {any} */ x, /** @type {any} */ y) => {
|
|
280
288
|
if (x === y) {
|
|
281
289
|
return true
|
|
282
290
|
}
|
|
@@ -297,12 +305,12 @@ export const $eq = /** @returns {boolean} */ (/** @type {any} */ x, /** @type {a
|
|
|
297
305
|
}
|
|
298
306
|
|
|
299
307
|
if (xConstructor === Array) {
|
|
300
|
-
return x.length === y.length && x.every((/** @type {any} */ item, /** @type {number} */ index) =>
|
|
308
|
+
return x.length === y.length && x.every((/** @type {any} */ item, /** @type {number} */ index) => eq(item, y[index]))
|
|
301
309
|
}
|
|
302
310
|
|
|
303
311
|
if (xConstructor === Object) {
|
|
304
312
|
const keysOfX = Object.keys(x)
|
|
305
|
-
return keysOfX.length === Object.keys(y).length && keysOfX.every(key =>
|
|
313
|
+
return keysOfX.length === Object.keys(y).length && keysOfX.every(key => eq(x[key], y[key]))
|
|
306
314
|
}
|
|
307
315
|
|
|
308
316
|
if (xConstructor === Set || xConstructor === Map) {
|
|
@@ -311,27 +319,27 @@ export const $eq = /** @returns {boolean} */ (/** @type {any} */ x, /** @type {a
|
|
|
311
319
|
}
|
|
312
320
|
const xa = [...x]
|
|
313
321
|
const ya = [...y]
|
|
314
|
-
return xa.every(xv => ya.find(yv =>
|
|
322
|
+
return xa.every(xv => ya.find(yv => eq(xv, yv)))
|
|
315
323
|
}
|
|
316
324
|
}
|
|
317
325
|
|
|
318
326
|
return false
|
|
319
327
|
}
|
|
320
328
|
|
|
321
|
-
export const
|
|
322
|
-
/** @type {
|
|
329
|
+
export const escape = (
|
|
330
|
+
/** @type {EscapeMap} */ escapeMap,
|
|
323
331
|
/** @type {TemplateStringsArray} */ template,
|
|
324
332
|
/** @type {any[]} */ ...values
|
|
325
|
-
) => String.raw(template,
|
|
333
|
+
) => String.raw(template, ...escapeValues(escapeMap, values))
|
|
326
334
|
|
|
327
|
-
export const
|
|
328
|
-
/** @type {
|
|
335
|
+
export const escapeValues = (
|
|
336
|
+
/** @type {EscapeMap} */ escapeMap,
|
|
329
337
|
/** @type {any[]} */ values
|
|
330
338
|
) => values.map(value => (escapeMap.get(value?.constructor) ?? escapeMap.get(undefined))?.(value) ?? '')
|
|
331
339
|
|
|
332
340
|
const TAGS_TO_SKIP = { IFRAME: 1, NOSCRIPT: 1, PRE: 1, SCRIPT: 1, STYLE: 1, TEXTAREA: 1 }
|
|
333
341
|
|
|
334
|
-
export const
|
|
342
|
+
export const fixTypography = (/** @type {Node} */ node) => {
|
|
335
343
|
const /** @type {Node[]} */ queue = [node]
|
|
336
344
|
|
|
337
345
|
while (queue.length > 0) {
|
|
@@ -343,7 +351,7 @@ export const $fixTypography = (/** @type {Node} */ node) => {
|
|
|
343
351
|
|
|
344
352
|
if (childNode instanceof Text) {
|
|
345
353
|
queue.push(childNode)
|
|
346
|
-
} else if (childNode instanceof Element &&
|
|
354
|
+
} else if (childNode instanceof Element && !has(childNode.tagName, TAGS_TO_SKIP)) {
|
|
347
355
|
queue.push(childNode)
|
|
348
356
|
}
|
|
349
357
|
}
|
|
@@ -354,7 +362,7 @@ export const $fixTypography = (/** @type {Node} */ node) => {
|
|
|
354
362
|
i %= 3
|
|
355
363
|
|
|
356
364
|
const currentNode = i === 2
|
|
357
|
-
?
|
|
365
|
+
? h('span', { style: 'white-space:nowrap' }, chunk)
|
|
358
366
|
: i === 1
|
|
359
367
|
? document.createTextNode(chunk)
|
|
360
368
|
: document.createTextNode(chunk.replace(/(\/(?=[^/\s])|\.(?=[^\s]))/g, '$1\u200B'))
|
|
@@ -371,13 +379,13 @@ export const $fixTypography = (/** @type {Node} */ node) => {
|
|
|
371
379
|
}
|
|
372
380
|
}
|
|
373
381
|
|
|
374
|
-
export const
|
|
382
|
+
export const get = (
|
|
375
383
|
/** @type {any} */ defaultValue,
|
|
376
384
|
/** @type {any} */ ref,
|
|
377
385
|
/** @type {(string | number | symbol)[]} */ ...keys
|
|
378
386
|
) => {
|
|
379
387
|
for (const key of keys) {
|
|
380
|
-
if (
|
|
388
|
+
if (!has(key, ref)) {
|
|
381
389
|
return defaultValue
|
|
382
390
|
}
|
|
383
391
|
|
|
@@ -394,14 +402,14 @@ const /** @type {Record<string, string>} */ NS = {
|
|
|
394
402
|
/**
|
|
395
403
|
* @type {{
|
|
396
404
|
* (namespaceURI?: null | undefined): {
|
|
397
|
-
* <T extends keyof HTMLElementTagNameMap>(tag: T, ...args:
|
|
398
|
-
* <N extends Node> (node: N, ...args:
|
|
399
|
-
* (...args:
|
|
405
|
+
* <T extends keyof HTMLElementTagNameMap>(tag: T, ...args: HArgs[1][]): HTMLElementTagNameMap[T];
|
|
406
|
+
* <N extends Node> (node: N, ...args: HArgs[1][]): N;
|
|
407
|
+
* (...args: HArgs): Node;
|
|
400
408
|
* };
|
|
401
409
|
* (namespaceURI: 'http://www.w3.org/2000/svg'): {
|
|
402
|
-
* <T extends keyof SVGElementTagNameMap> (tag: T, ...args:
|
|
403
|
-
* <N extends Node> (node: N, ...args:
|
|
404
|
-
* (...args:
|
|
410
|
+
* <T extends keyof SVGElementTagNameMap> (tag: T, ...args: HArgs[1][]): SVGElementTagNameMap[T];
|
|
411
|
+
* <N extends Node> (node: N, ...args: HArgs[1][]): N;
|
|
412
|
+
* (...args: HArgs): Node;
|
|
405
413
|
* };
|
|
406
414
|
* }}
|
|
407
415
|
*/
|
|
@@ -410,18 +418,18 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
410
418
|
? (/** @type {string } */ tag) => document.createElement(tag)
|
|
411
419
|
: (/** @type {string } */ tag) => document.createElementNS(namespaceURI, tag)
|
|
412
420
|
|
|
413
|
-
const h = (/** @type {
|
|
414
|
-
const node =
|
|
421
|
+
const h = (/** @type {HArgs[0]} */ tagOrNode, /** @type {HArgs[1][]} */ ...args) => {
|
|
422
|
+
const node = is(String, tagOrNode) ? createElement(tagOrNode) : tagOrNode
|
|
415
423
|
|
|
416
424
|
for (const arg of args) {
|
|
417
425
|
let child = null
|
|
418
426
|
|
|
419
427
|
if (arg instanceof Node) {
|
|
420
428
|
child = arg
|
|
421
|
-
} else if (
|
|
429
|
+
} else if (is(String, arg) || is(Number, arg)) {
|
|
422
430
|
// @ts-expect-error
|
|
423
431
|
child = new Text(arg)
|
|
424
|
-
} else if (
|
|
432
|
+
} else if (is(Array, arg)) {
|
|
425
433
|
// @ts-expect-error
|
|
426
434
|
child = h(...arg)
|
|
427
435
|
} else if (arg != null) {
|
|
@@ -431,7 +439,7 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
431
439
|
if (name[0] === '$') {
|
|
432
440
|
const name1 = name.slice(1)
|
|
433
441
|
|
|
434
|
-
if (
|
|
442
|
+
if (is(Object, value)) {
|
|
435
443
|
// @ts-expect-error
|
|
436
444
|
node[name1] = node[name1] ?? {}
|
|
437
445
|
// @ts-expect-error
|
|
@@ -454,7 +462,7 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
454
462
|
} else if (value === false) {
|
|
455
463
|
node.removeAttributeNS(ns, basename)
|
|
456
464
|
} else {
|
|
457
|
-
node.setAttributeNS(ns, basename,
|
|
465
|
+
node.setAttributeNS(ns, basename, is(String, value) ? value : '' + value)
|
|
458
466
|
}
|
|
459
467
|
}
|
|
460
468
|
} else {
|
|
@@ -463,7 +471,7 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
463
471
|
} else if (value === false) {
|
|
464
472
|
node.removeAttribute(name)
|
|
465
473
|
} else {
|
|
466
|
-
node.setAttribute(name,
|
|
474
|
+
node.setAttribute(name, is(String, value) ? value : '' + value)
|
|
467
475
|
}
|
|
468
476
|
}
|
|
469
477
|
}
|
|
@@ -481,10 +489,10 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
481
489
|
return h
|
|
482
490
|
}
|
|
483
491
|
|
|
484
|
-
export const
|
|
492
|
+
export const h = _h()
|
|
485
493
|
|
|
486
|
-
export const
|
|
487
|
-
(
|
|
494
|
+
export const has = (/** @type {any} */ key, /** @type {any} */ ref) =>
|
|
495
|
+
(is(String, key) || is(Number, key) || is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key)
|
|
488
496
|
|
|
489
497
|
/**
|
|
490
498
|
* @template {abstract new (...args: any[]) => any} T
|
|
@@ -501,7 +509,7 @@ export const $in = (/** @type {any} */ key, /** @type {any} */ ref) =>
|
|
|
501
509
|
*
|
|
502
510
|
* @returns {arg is bigint | boolean | number | string | symbol | undefined | null | InstanceType<T>}
|
|
503
511
|
*/
|
|
504
|
-
export const
|
|
512
|
+
export const is = (/** @type {T} */ type, /** @type {any} */ arg) => arg?.constructor === type
|
|
505
513
|
|
|
506
514
|
const _locale = (
|
|
507
515
|
/** @type {Record<string, Record<string, string | Record<string, string>>>} */ locales,
|
|
@@ -512,22 +520,22 @@ const _locale = (
|
|
|
512
520
|
// @ts-expect-error
|
|
513
521
|
const v = locales?.[language]?.[version]?.[text]
|
|
514
522
|
|
|
515
|
-
if (
|
|
523
|
+
if (is(String, v)) {
|
|
516
524
|
return v
|
|
517
525
|
}
|
|
518
526
|
|
|
519
527
|
const t = locales?.[language]?.[text]
|
|
520
528
|
|
|
521
|
-
return
|
|
529
|
+
return is(String, t) ? t : text
|
|
522
530
|
}
|
|
523
531
|
|
|
524
|
-
export const
|
|
532
|
+
export const locale = (
|
|
525
533
|
/** @type {Record<string, Record<string, string | Record<string, string>>>} */ locales,
|
|
526
534
|
/** @type {string} */ defaultLanguage,
|
|
527
535
|
languages = navigator.languages
|
|
528
536
|
) => {
|
|
529
537
|
for (const language of languages) {
|
|
530
|
-
if (
|
|
538
|
+
if (has(language, locales)) {
|
|
531
539
|
// @ts-expect-error
|
|
532
540
|
return _locale.bind(0, locales, language)
|
|
533
541
|
}
|
|
@@ -537,12 +545,12 @@ export const $locale = (
|
|
|
537
545
|
return _locale.bind(0, locales, defaultLanguage)
|
|
538
546
|
}
|
|
539
547
|
|
|
540
|
-
export const
|
|
548
|
+
export const nanolight = (
|
|
541
549
|
/** @type {RegExp} */ pattern,
|
|
542
|
-
/** @type {((chunk: string, index: number) =>
|
|
550
|
+
/** @type {((chunk: string, index: number) => HArgs[1])[]} */ highlighters,
|
|
543
551
|
/** @type {string} */ code
|
|
544
552
|
) => {
|
|
545
|
-
const /** @type {
|
|
553
|
+
const /** @type {HArgs[1][]} */ result = []
|
|
546
554
|
|
|
547
555
|
code.split(pattern).forEach((chunk, index) => {
|
|
548
556
|
index %= highlighters.length
|
|
@@ -555,7 +563,7 @@ export const $nanolight = (
|
|
|
555
563
|
}
|
|
556
564
|
|
|
557
565
|
// @ts-expect-error
|
|
558
|
-
export const
|
|
566
|
+
export const nanolightJs = nanolight.bind(0,
|
|
559
567
|
/('.*?'|".*?"|`[\s\S]*?`)|(\/\/.*?\n|\/\*[\s\S]*?\*\/)|(break|case|catch|const|continue|debugger|default|delete|do|else|eval|export\s+type|export|extends|false|finally|for|from|function|goto|if|import|in|instanceof|is|keyof|let|NaN|new|null|package|return|super|switch|this|throw|true|try|typeof|undefined|var|void|while|with|yield)(?!\w)|([<>=.?:&|!~*/%+-])|(0x[\dabcdef]+|0o[01234567]+|0b[01]+|\d+(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?)|([$\w]+)(?=\()|([$\wąćęłńóśżźĄĆĘŁŃÓŚŻŹ]+)/,
|
|
560
568
|
[
|
|
561
569
|
chunk => chunk, // no match
|
|
@@ -569,7 +577,7 @@ export const $nanolightJs = $nanolight.bind(0,
|
|
|
569
577
|
]
|
|
570
578
|
)
|
|
571
579
|
|
|
572
|
-
export const
|
|
580
|
+
export const plUral = (
|
|
573
581
|
/** @type {string} */ singular,
|
|
574
582
|
/** @type {string} */ plural2,
|
|
575
583
|
/** @type {string} */ plural5,
|
|
@@ -587,9 +595,9 @@ export const $plUral = (
|
|
|
587
595
|
: plural5
|
|
588
596
|
}
|
|
589
597
|
|
|
590
|
-
export const
|
|
598
|
+
export const s = _h('http://www.w3.org/2000/svg')
|
|
591
599
|
|
|
592
|
-
export const
|
|
600
|
+
export const set = (
|
|
593
601
|
/** @type {any} */ value,
|
|
594
602
|
/** @type {any} */ ref,
|
|
595
603
|
/** @type {(string | number | symbol)[]} */ ...keys
|
|
@@ -603,8 +611,8 @@ export const $set = (
|
|
|
603
611
|
for (let k = 0; k < last; ++k) {
|
|
604
612
|
const key = keys[k]
|
|
605
613
|
|
|
606
|
-
if (
|
|
607
|
-
ref[key] =
|
|
614
|
+
if (!has(key, ref)) {
|
|
615
|
+
ref[key] = is(Number, keys[k + 1]) ? [] : {}
|
|
608
616
|
}
|
|
609
617
|
|
|
610
618
|
ref = ref[key]
|
|
@@ -616,7 +624,7 @@ export const $set = (
|
|
|
616
624
|
const _ZEROS = '0'.repeat(16)
|
|
617
625
|
let _counter = 0
|
|
618
626
|
|
|
619
|
-
export const
|
|
627
|
+
export const uuid1 = ({
|
|
620
628
|
date = new Date(),
|
|
621
629
|
node = Math.random().toString(16).slice(2)
|
|
622
630
|
} = {}) => {
|
package/package.json
CHANGED