@nice2dev/icons 1.3.8 → 1.3.10
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/CHANGELOG.md +99 -0
- package/dist/cjs/NiceIconPicker.js +310 -92
- package/dist/cjs/NiceIconStacker.js +137 -120
- package/dist/cjs/NiceIconValue.js +44 -0
- package/dist/cjs/client.js +11 -0
- package/dist/cjs/iconHtml.js +104 -0
- package/dist/cjs/iconStack.js +74 -1
- package/dist/cjs/iconValue.js +473 -0
- package/dist/cjs/icons/actions.js +39 -8
- package/dist/cjs/icons/files.js +23 -2
- package/dist/cjs/icons/fintech.js +12 -5
- package/dist/cjs/icons/index.js +1 -0
- package/dist/cjs/icons/media.js +7 -4
- package/dist/cjs/icons/realestate.js +8 -7
- package/dist/cjs/icons/shapes.js +55 -4
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/nicetodev-icons.css +1 -1
- package/dist/esm/NiceIconPicker.js +313 -95
- package/dist/esm/NiceIconStacker.js +140 -123
- package/dist/esm/NiceIconValue.js +41 -0
- package/dist/esm/client.js +4 -1
- package/dist/esm/iconHtml.js +100 -0
- package/dist/esm/iconStack.js +72 -2
- package/dist/esm/iconValue.js +470 -0
- package/dist/esm/icons/actions.js +39 -9
- package/dist/esm/icons/files.js +23 -2
- package/dist/esm/icons/fintech.js +12 -5
- package/dist/esm/icons/index.js +1 -1
- package/dist/esm/icons/media.js +8 -5
- package/dist/esm/icons/realestate.js +8 -7
- package/dist/esm/icons/shapes.js +55 -4
- package/dist/esm/index.js +5 -2
- package/dist/esm/nicetodev-icons.css +1 -1
- package/dist/types/NiceIconPicker.d.ts +72 -20
- package/dist/types/NiceIconStacker.d.ts +30 -9
- package/dist/types/NiceIconValue.d.ts +40 -0
- package/dist/types/client.d.ts +8 -2
- package/dist/types/iconHtml.d.ts +22 -0
- package/dist/types/iconStack.d.ts +18 -0
- package/dist/types/iconValue.d.ts +22 -0
- package/dist/types/icons/actions.d.ts +1 -0
- package/dist/types/icons/index.d.ts +1 -1
- package/dist/types/index.d.ts +8 -2
- package/package.json +2 -2
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var iconHtml = require('./iconHtml.js');
|
|
4
|
+
var iconStack = require('./iconStack.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* An icon — or a stack of icons — kept as short text (1.3.10): what NiceIconPicker stores with
|
|
8
|
+
* `valueFormat="name"` (the default) or `"json"`, as short as a database value can be and still be
|
|
9
|
+
* read by people.
|
|
10
|
+
*
|
|
11
|
+
* **The code** (`'name'`) — a plain icon is its name (`NtdFolder`); a stack nests like a function
|
|
12
|
+
* call, the parent first, each setting behind a sign of its own:
|
|
13
|
+
*
|
|
14
|
+
* ```
|
|
15
|
+
* Folder(Star@tr) a star in the folder's top-right corner
|
|
16
|
+
* Bell(Circle@tr'3') a circle with "3" in the bell's corner
|
|
17
|
+
* Folder(Star@tr%40^15,Lock@bl) two icons in the folder: 40 %, turned 15°; a lock
|
|
18
|
+
* User:o(Circle@br#2a2{count}'5'#fff) an outline user, a green circle bound to `count`
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* | sign | meaning | example |
|
|
22
|
+
* |---|---|---|
|
|
23
|
+
* | `( , )` | what sits in the icon, side by side | `Folder(Star,Lock)` |
|
|
24
|
+
* | `:` | variant — `so` solid, `sh` sharp, `o` outline, `w` wireframe, `d` duotone, `c` cutout, `r` rounded, `m` mini, `3d`, `v` vivid | `:o` |
|
|
25
|
+
* | `@` | position in the parent — `c t b l r tl tr bl br`, `h…` halfway (`ht`, `hbr`…); the parent's own spot when absent | `@tr` |
|
|
26
|
+
* | `%` | size, percent of the parent | `%40` |
|
|
27
|
+
* | `^` | turn, degrees clockwise | `^-30` |
|
|
28
|
+
* | `~` | nudge right / down, percent of the parent | `~5/-3` |
|
|
29
|
+
* | `#` | colours: primary, secondary, accent (`##0f0` — secondary only) | `#2a2` |
|
|
30
|
+
* | `'…'` | text; `#` and `%` after it are the text's colour and size | `'3'#fff%60` |
|
|
31
|
+
* | `{…}` | the value the text is bound to (the text after it is a sample) | `{count}'5'` |
|
|
32
|
+
*
|
|
33
|
+
* Names drop `Ntd` inside a stack. A name or colour holding any of the signs goes in backticks
|
|
34
|
+
* (`` `fa:home` ``); `\` escapes inside quotes.
|
|
35
|
+
*
|
|
36
|
+
* **JSON** (`'json'`) — the same tree as JsonML: `["Folder",["Star",{"a":"tr"}]]`, a node being
|
|
37
|
+
* `[name, {settings}?, ...nodes, "text"?]` with the settings `v a s r x y p sc ac b tc ts` written
|
|
38
|
+
* as in the code; a plain icon is its name as a JSON string.
|
|
39
|
+
*/
|
|
40
|
+
const VARIANT_CODE = {
|
|
41
|
+
solid: 'so',
|
|
42
|
+
sharp: 'sh',
|
|
43
|
+
outline: 'o',
|
|
44
|
+
wireframe: 'w',
|
|
45
|
+
duotone: 'd',
|
|
46
|
+
cutout: 'c',
|
|
47
|
+
rounded: 'r',
|
|
48
|
+
mini: 'm',
|
|
49
|
+
'3d': '3d',
|
|
50
|
+
vivid: 'v',
|
|
51
|
+
};
|
|
52
|
+
const ALIGN_CODE = {
|
|
53
|
+
center: 'c',
|
|
54
|
+
top: 't',
|
|
55
|
+
bottom: 'b',
|
|
56
|
+
left: 'l',
|
|
57
|
+
right: 'r',
|
|
58
|
+
'top-left': 'tl',
|
|
59
|
+
'top-right': 'tr',
|
|
60
|
+
'bottom-left': 'bl',
|
|
61
|
+
'bottom-right': 'br',
|
|
62
|
+
'half-top': 'ht',
|
|
63
|
+
'half-bottom': 'hb',
|
|
64
|
+
'half-left': 'hl',
|
|
65
|
+
'half-right': 'hr',
|
|
66
|
+
'half-top-left': 'htl',
|
|
67
|
+
'half-top-right': 'htr',
|
|
68
|
+
'half-bottom-left': 'hbl',
|
|
69
|
+
'half-bottom-right': 'hbr',
|
|
70
|
+
};
|
|
71
|
+
/** A code or a full name → the value; an unknown one (a newer writer's) reads as unset. */
|
|
72
|
+
function reverse(codes) {
|
|
73
|
+
const map = new Map();
|
|
74
|
+
for (const [full, code] of Object.entries(codes)) {
|
|
75
|
+
map.set(code, full);
|
|
76
|
+
map.set(full, full);
|
|
77
|
+
}
|
|
78
|
+
return map;
|
|
79
|
+
}
|
|
80
|
+
const VARIANTS = reverse(VARIANT_CODE);
|
|
81
|
+
const ALIGNS = reverse({ ...ALIGN_CODE, perfect: 'p' });
|
|
82
|
+
/** The signs of the code; a name or colour holding one of them goes in backticks. */
|
|
83
|
+
const SIGNS = new Set(['(', ')', ',', ':', '@', '%', '^', '~', '#', "'", '{', '}', '`', '\\']);
|
|
84
|
+
/** A plain icon: one layer and nothing set on it but its name. */
|
|
85
|
+
function isPlain(layers) {
|
|
86
|
+
return (layers.length === 1 &&
|
|
87
|
+
Object.entries(layers[0]).every(([key, value]) => key === 'id' || key === 'icon' || value === undefined));
|
|
88
|
+
}
|
|
89
|
+
function quote(text, mark) {
|
|
90
|
+
return mark + text.replace(/[\\`']/g, (c) => (c === mark || c === '\\' ? `\\${c}` : c)) + mark;
|
|
91
|
+
}
|
|
92
|
+
function writeName(name) {
|
|
93
|
+
const needsQuotes = name === '' ||
|
|
94
|
+
name !== name.trim() ||
|
|
95
|
+
[...name].some((c) => SIGNS.has(c)) ||
|
|
96
|
+
/^["[<]/.test(name);
|
|
97
|
+
return needsQuotes ? quote(name, '`') : name;
|
|
98
|
+
}
|
|
99
|
+
function writeNumber(n) {
|
|
100
|
+
return String(Math.round(n * 1000) / 1000);
|
|
101
|
+
}
|
|
102
|
+
/** `#22aa22` → `2a2`, any other hex as is; another colour (`var(--x)`) in backticks. */
|
|
103
|
+
function writeColor(color) {
|
|
104
|
+
if (!color) {
|
|
105
|
+
return '';
|
|
106
|
+
}
|
|
107
|
+
const hex = /^#([0-9a-f]{3,8})$/i.exec(color);
|
|
108
|
+
if (!hex) {
|
|
109
|
+
return quote(color, '`');
|
|
110
|
+
}
|
|
111
|
+
const h = hex[1].toLowerCase();
|
|
112
|
+
return h.length === 6 && h[0] === h[1] && h[2] === h[3] && h[4] === h[5] ? h[0] + h[2] + h[4] : h;
|
|
113
|
+
}
|
|
114
|
+
function writeCode(layers, shortName) {
|
|
115
|
+
const write = (layer, isBase) => {
|
|
116
|
+
var _a, _b, _c, _d;
|
|
117
|
+
let out = writeName(shortName(layer.icon));
|
|
118
|
+
if (layer.variant) {
|
|
119
|
+
out += `:${(_a = VARIANT_CODE[layer.variant]) !== null && _a !== void 0 ? _a : layer.variant}`;
|
|
120
|
+
}
|
|
121
|
+
if (!isBase) {
|
|
122
|
+
if (layer.align && layer.align !== 'perfect') {
|
|
123
|
+
out += `@${(_b = ALIGN_CODE[layer.align]) !== null && _b !== void 0 ? _b : layer.align}`;
|
|
124
|
+
}
|
|
125
|
+
if (layer.size !== undefined) {
|
|
126
|
+
out += `%${writeNumber(layer.size * 100)}`;
|
|
127
|
+
}
|
|
128
|
+
if (layer.rotation !== undefined) {
|
|
129
|
+
out += `^${writeNumber(layer.rotation)}`;
|
|
130
|
+
}
|
|
131
|
+
if (layer.offsetX || layer.offsetY) {
|
|
132
|
+
out += `~${writeNumber((_c = layer.offsetX) !== null && _c !== void 0 ? _c : 0)}`;
|
|
133
|
+
if (layer.offsetY) {
|
|
134
|
+
out += `/${writeNumber(layer.offsetY)}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const colors = [layer.primaryColor, layer.secondaryColor, layer.accentColor];
|
|
139
|
+
const lastColor = colors.reduce((last, c, i) => (c ? i : last), -1);
|
|
140
|
+
for (let i = 0; i <= lastColor; i++) {
|
|
141
|
+
out += `#${writeColor(colors[i])}`;
|
|
142
|
+
}
|
|
143
|
+
const bound = !!layer.textBinding && /^[A-Za-z_$][\w$]*$/.test(layer.textBinding);
|
|
144
|
+
if (bound) {
|
|
145
|
+
out += `{${layer.textBinding}}`;
|
|
146
|
+
}
|
|
147
|
+
// text settings need a text part to follow; an empty text carries them
|
|
148
|
+
if (layer.text || (!bound && (layer.textColor || layer.textSize !== undefined))) {
|
|
149
|
+
out += quote((_d = layer.text) !== null && _d !== void 0 ? _d : '', "'");
|
|
150
|
+
}
|
|
151
|
+
if (layer.textColor) {
|
|
152
|
+
out += `#${writeColor(layer.textColor)}`;
|
|
153
|
+
}
|
|
154
|
+
if (layer.textSize !== undefined) {
|
|
155
|
+
out += `%${writeNumber(layer.textSize)}`;
|
|
156
|
+
}
|
|
157
|
+
const inner = iconStack.stackChildrenOf(layers, layer.id);
|
|
158
|
+
return inner.length > 0 ? `${out}(${inner.map((l) => write(l, false)).join(',')})` : out;
|
|
159
|
+
};
|
|
160
|
+
return write(layers[0], true);
|
|
161
|
+
}
|
|
162
|
+
function writeJson(layers, shortName) {
|
|
163
|
+
const write = (layer, isBase) => {
|
|
164
|
+
var _a, _b;
|
|
165
|
+
const s = {};
|
|
166
|
+
const set = (key, value) => {
|
|
167
|
+
if (value !== undefined && value !== '' && value !== 0) {
|
|
168
|
+
s[key] = value;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
set('v', layer.variant && ((_a = VARIANT_CODE[layer.variant]) !== null && _a !== void 0 ? _a : layer.variant));
|
|
172
|
+
if (!isBase) {
|
|
173
|
+
if (layer.align && layer.align !== 'perfect') {
|
|
174
|
+
set('a', (_b = ALIGN_CODE[layer.align]) !== null && _b !== void 0 ? _b : layer.align);
|
|
175
|
+
}
|
|
176
|
+
if (layer.size !== undefined) {
|
|
177
|
+
s.s = Math.round(layer.size * 100000) / 1000;
|
|
178
|
+
}
|
|
179
|
+
if (layer.rotation !== undefined) {
|
|
180
|
+
s.r = layer.rotation;
|
|
181
|
+
}
|
|
182
|
+
set('x', layer.offsetX);
|
|
183
|
+
set('y', layer.offsetY);
|
|
184
|
+
}
|
|
185
|
+
set('p', layer.primaryColor);
|
|
186
|
+
set('sc', layer.secondaryColor);
|
|
187
|
+
set('ac', layer.accentColor);
|
|
188
|
+
set('b', layer.textBinding);
|
|
189
|
+
set('tc', layer.textColor);
|
|
190
|
+
if (layer.textSize !== undefined) {
|
|
191
|
+
s.ts = layer.textSize;
|
|
192
|
+
}
|
|
193
|
+
const node = [shortName(layer.icon)];
|
|
194
|
+
if (Object.keys(s).length > 0) {
|
|
195
|
+
node.push(s);
|
|
196
|
+
}
|
|
197
|
+
for (const child of iconStack.stackChildrenOf(layers, layer.id)) {
|
|
198
|
+
node.push(write(child, false));
|
|
199
|
+
}
|
|
200
|
+
if (layer.text) {
|
|
201
|
+
node.push(layer.text);
|
|
202
|
+
}
|
|
203
|
+
return node;
|
|
204
|
+
};
|
|
205
|
+
return write(layers[0], true);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Writes an icon or a stack as short text (1.3.10): `'name'` — a plain icon's name, a stack's code
|
|
209
|
+
* (`Folder(Star@tr)`) — or `'json'` (`["Folder",["Star",{"a":"tr"}]]`). Empty for no layers.
|
|
210
|
+
* `parseIconValue` reads it back; the ids of the layers are not kept.
|
|
211
|
+
*/
|
|
212
|
+
function formatIconValue(layers, format = 'name', { shortName = iconStack.iconDisplayName } = {}) {
|
|
213
|
+
if (layers.length === 0) {
|
|
214
|
+
return '';
|
|
215
|
+
}
|
|
216
|
+
if (isPlain(layers)) {
|
|
217
|
+
return format === 'json' ? JSON.stringify(layers[0].icon) : layers[0].icon;
|
|
218
|
+
}
|
|
219
|
+
return format === 'json'
|
|
220
|
+
? JSON.stringify(writeJson(layers, shortName))
|
|
221
|
+
: writeCode(layers, shortName);
|
|
222
|
+
}
|
|
223
|
+
/* ─── Reading ─── */
|
|
224
|
+
class IconValueError extends Error {
|
|
225
|
+
}
|
|
226
|
+
/** Collects the layers in document order, ids `'1'`, `'2'`…; what sits in the base has no parent. */
|
|
227
|
+
class LayerSink {
|
|
228
|
+
constructor() {
|
|
229
|
+
this.layers = [];
|
|
230
|
+
}
|
|
231
|
+
add(layer, parent, isBase) {
|
|
232
|
+
const data = isBase
|
|
233
|
+
? // where a layer sits means nothing for the base
|
|
234
|
+
{ ...layer, align: undefined, size: undefined, rotation: undefined }
|
|
235
|
+
: layer;
|
|
236
|
+
if (isBase || !data.offsetX) {
|
|
237
|
+
data.offsetX = undefined;
|
|
238
|
+
}
|
|
239
|
+
if (isBase || !data.offsetY) {
|
|
240
|
+
data.offsetY = undefined;
|
|
241
|
+
}
|
|
242
|
+
if (data.align === 'perfect') {
|
|
243
|
+
data.align = undefined;
|
|
244
|
+
}
|
|
245
|
+
const id = String(this.layers.length + 1);
|
|
246
|
+
const clean = Object.fromEntries(Object.entries(data).filter(([, v]) => v !== undefined && v !== ''));
|
|
247
|
+
this.layers.push({ id, ...clean, ...(parent && parent !== '1' ? { parent } : {}) });
|
|
248
|
+
return id;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function readCode(code) {
|
|
252
|
+
const sink = new LayerSink();
|
|
253
|
+
let i = 0;
|
|
254
|
+
const peek = () => code[i];
|
|
255
|
+
const skipSpaces = () => {
|
|
256
|
+
while (i < code.length && /\s/.test(code[i])) {
|
|
257
|
+
i++;
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
const quoted = (mark) => {
|
|
261
|
+
i++;
|
|
262
|
+
let out = '';
|
|
263
|
+
while (i < code.length && code[i] !== mark) {
|
|
264
|
+
if (code[i] === '\\' && i + 1 < code.length) {
|
|
265
|
+
i++;
|
|
266
|
+
}
|
|
267
|
+
out += code[i];
|
|
268
|
+
i++;
|
|
269
|
+
}
|
|
270
|
+
if (code[i] !== mark) {
|
|
271
|
+
throw new IconValueError('unclosed quote');
|
|
272
|
+
}
|
|
273
|
+
i++;
|
|
274
|
+
return out;
|
|
275
|
+
};
|
|
276
|
+
const name = () => {
|
|
277
|
+
skipSpaces();
|
|
278
|
+
if (peek() === '`') {
|
|
279
|
+
return quoted('`');
|
|
280
|
+
}
|
|
281
|
+
const start = i;
|
|
282
|
+
while (i < code.length && !SIGNS.has(code[i])) {
|
|
283
|
+
i++;
|
|
284
|
+
}
|
|
285
|
+
const out = code.slice(start, i).trim();
|
|
286
|
+
if (!out) {
|
|
287
|
+
throw new IconValueError('name expected');
|
|
288
|
+
}
|
|
289
|
+
return out;
|
|
290
|
+
};
|
|
291
|
+
const word = () => {
|
|
292
|
+
var _a, _b;
|
|
293
|
+
const hit = (_b = (_a = /^[A-Za-z0-9-]*/.exec(code.slice(i))) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : '';
|
|
294
|
+
i += hit.length;
|
|
295
|
+
return hit;
|
|
296
|
+
};
|
|
297
|
+
const number = () => {
|
|
298
|
+
var _a;
|
|
299
|
+
const hit = (_a = /^-?(?:\d+(?:\.\d*)?|\.\d+)/.exec(code.slice(i))) === null || _a === void 0 ? void 0 : _a[0];
|
|
300
|
+
if (!hit) {
|
|
301
|
+
throw new IconValueError('number expected');
|
|
302
|
+
}
|
|
303
|
+
i += hit.length;
|
|
304
|
+
return Number(hit);
|
|
305
|
+
};
|
|
306
|
+
const color = () => {
|
|
307
|
+
var _a, _b;
|
|
308
|
+
if (peek() === '`') {
|
|
309
|
+
return quoted('`');
|
|
310
|
+
}
|
|
311
|
+
const hit = (_b = (_a = /^[0-9a-fA-F]{0,8}/.exec(code.slice(i))) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : '';
|
|
312
|
+
i += hit.length;
|
|
313
|
+
return hit ? `#${hit.toLowerCase()}` : undefined;
|
|
314
|
+
};
|
|
315
|
+
const node = (parent, isBase) => {
|
|
316
|
+
const layer = { icon: name() };
|
|
317
|
+
const colors = [];
|
|
318
|
+
let settings = true;
|
|
319
|
+
while (settings) {
|
|
320
|
+
const sign = peek();
|
|
321
|
+
if (sign === ':' ||
|
|
322
|
+
sign === '@' ||
|
|
323
|
+
sign === '%' ||
|
|
324
|
+
sign === '^' ||
|
|
325
|
+
sign === '~' ||
|
|
326
|
+
sign === '#') {
|
|
327
|
+
i++;
|
|
328
|
+
}
|
|
329
|
+
if (sign === ':') {
|
|
330
|
+
layer.variant = VARIANTS.get(word());
|
|
331
|
+
}
|
|
332
|
+
else if (sign === '@') {
|
|
333
|
+
layer.align = ALIGNS.get(word());
|
|
334
|
+
}
|
|
335
|
+
else if (sign === '%') {
|
|
336
|
+
layer.size = Math.round(number() * 1000) / 100000;
|
|
337
|
+
}
|
|
338
|
+
else if (sign === '^') {
|
|
339
|
+
layer.rotation = number();
|
|
340
|
+
}
|
|
341
|
+
else if (sign === '~') {
|
|
342
|
+
layer.offsetX = number();
|
|
343
|
+
if (peek() === '/') {
|
|
344
|
+
i++;
|
|
345
|
+
layer.offsetY = number();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else if (sign === '#') {
|
|
349
|
+
colors.push(color());
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
settings = false;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
[layer.primaryColor, layer.secondaryColor, layer.accentColor] = colors;
|
|
356
|
+
if (peek() === '{') {
|
|
357
|
+
const end = code.indexOf('}', i);
|
|
358
|
+
if (end < 0) {
|
|
359
|
+
throw new IconValueError('unclosed binding');
|
|
360
|
+
}
|
|
361
|
+
layer.textBinding = code.slice(i + 1, end).trim();
|
|
362
|
+
i = end + 1;
|
|
363
|
+
}
|
|
364
|
+
if (peek() === "'") {
|
|
365
|
+
layer.text = quoted("'");
|
|
366
|
+
}
|
|
367
|
+
if (layer.text !== undefined || layer.textBinding) {
|
|
368
|
+
for (let sign = peek(); sign === '#' || sign === '%'; sign = peek()) {
|
|
369
|
+
i++;
|
|
370
|
+
if (sign === '#') {
|
|
371
|
+
layer.textColor = color();
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
layer.textSize = number();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const id = sink.add(layer, parent, isBase);
|
|
379
|
+
skipSpaces();
|
|
380
|
+
if (peek() === '(') {
|
|
381
|
+
i++;
|
|
382
|
+
let more = true;
|
|
383
|
+
while (more) {
|
|
384
|
+
node(id, false);
|
|
385
|
+
skipSpaces();
|
|
386
|
+
more = peek() === ',';
|
|
387
|
+
if (more) {
|
|
388
|
+
i++;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (peek() !== ')') {
|
|
392
|
+
throw new IconValueError(') expected');
|
|
393
|
+
}
|
|
394
|
+
i++;
|
|
395
|
+
skipSpaces();
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
node(undefined, true);
|
|
399
|
+
if (i < code.length) {
|
|
400
|
+
throw new IconValueError('unexpected text');
|
|
401
|
+
}
|
|
402
|
+
return sink.layers;
|
|
403
|
+
}
|
|
404
|
+
function readJson(json) {
|
|
405
|
+
const parsed = JSON.parse(json);
|
|
406
|
+
if (typeof parsed === 'string') {
|
|
407
|
+
return parsed.trim() ? [{ id: '1', icon: parsed }] : null;
|
|
408
|
+
}
|
|
409
|
+
const sink = new LayerSink();
|
|
410
|
+
const str = (v) => (typeof v === 'string' ? v : undefined);
|
|
411
|
+
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : undefined);
|
|
412
|
+
const node = (value, parent, isBase) => {
|
|
413
|
+
var _a, _b;
|
|
414
|
+
if (!Array.isArray(value) || typeof value[0] !== 'string' || !value[0]) {
|
|
415
|
+
throw new IconValueError('node expected');
|
|
416
|
+
}
|
|
417
|
+
const [icon, ...rest] = value;
|
|
418
|
+
const first = rest[0];
|
|
419
|
+
const s = (first && typeof first === 'object' && !Array.isArray(first) ? rest.shift() : {});
|
|
420
|
+
const text = rest.filter((v) => typeof v === 'string').join('');
|
|
421
|
+
const size = num(s.s);
|
|
422
|
+
const id = sink.add({
|
|
423
|
+
icon,
|
|
424
|
+
variant: VARIANTS.get((_a = str(s.v)) !== null && _a !== void 0 ? _a : ''),
|
|
425
|
+
align: ALIGNS.get((_b = str(s.a)) !== null && _b !== void 0 ? _b : ''),
|
|
426
|
+
size: size === undefined ? undefined : Math.round(size * 1000) / 100000,
|
|
427
|
+
rotation: num(s.r),
|
|
428
|
+
offsetX: num(s.x),
|
|
429
|
+
offsetY: num(s.y),
|
|
430
|
+
primaryColor: str(s.p),
|
|
431
|
+
secondaryColor: str(s.sc),
|
|
432
|
+
accentColor: str(s.ac),
|
|
433
|
+
text: text || undefined,
|
|
434
|
+
textBinding: str(s.b),
|
|
435
|
+
textColor: str(s.tc),
|
|
436
|
+
textSize: num(s.ts),
|
|
437
|
+
}, parent, isBase);
|
|
438
|
+
for (const child of rest) {
|
|
439
|
+
if (Array.isArray(child)) {
|
|
440
|
+
node(child, id, false);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
node(parsed, undefined, true);
|
|
445
|
+
return sink.layers;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Reads an icon kept as text (1.3.10) — a name, the code (`Folder(Star@tr)`), JSON or the HTML of
|
|
449
|
+
* NiceIconPicker 1.3.9 — into stack layers (ids `'1'`, `'2'`… in document order). `null` for empty
|
|
450
|
+
* or unreadable text. Names stay as written: `renderIconStack` resolves `Star` to `NtdStar`.
|
|
451
|
+
*/
|
|
452
|
+
function parseIconValue(value) {
|
|
453
|
+
var _a, _b;
|
|
454
|
+
const text = value === null || value === void 0 ? void 0 : value.trim();
|
|
455
|
+
if (!text) {
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
try {
|
|
459
|
+
if (text.startsWith('<')) {
|
|
460
|
+
return (_b = (_a = iconHtml.parseIconHtml(text)) === null || _a === void 0 ? void 0 : _a.layers) !== null && _b !== void 0 ? _b : null;
|
|
461
|
+
}
|
|
462
|
+
if (text.startsWith('[') || text.startsWith('"')) {
|
|
463
|
+
return readJson(text);
|
|
464
|
+
}
|
|
465
|
+
return readCode(text);
|
|
466
|
+
}
|
|
467
|
+
catch (_c) {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
exports.formatIconValue = formatIconValue;
|
|
473
|
+
exports.parseIconValue = parseIconValue;
|
|
@@ -131,16 +131,19 @@ const NtdShare = /* @__PURE__ */ createIcon.createIcon({
|
|
|
131
131
|
// the bottom left as a line that stops 1 short of the front — closer than before. The gap is
|
|
132
132
|
// worked out from the stroke width, so it stays the same at any weight; `sharp` draws the back
|
|
133
133
|
// sheet with square corners (the derived one kept their arcs). Duotone, fills only: the back sheet
|
|
134
|
-
// secondary under the primary front one; vivid: the back line secondary.
|
|
134
|
+
// secondary under the primary front one; vivid: the back line secondary. Round 40: the back sheet
|
|
135
|
+
// smaller, 11 (was 12.5), kept in the bottom-left corner.
|
|
135
136
|
const COPY_FRONT = { x: 8.5, y: 3, width: 12.5, height: 12.5, rx: 2.5 };
|
|
136
|
-
const COPY_BACK = { x: 3, y:
|
|
137
|
+
const COPY_BACK = { x: 3, y: 10, width: 11, height: 11, rx: 2.5 };
|
|
137
138
|
/** What shows of the back sheet: its edges outside the front one, `gap` short of it. */
|
|
138
139
|
function copyBack(gap, square = false) {
|
|
140
|
+
const { x, y, width, height, rx } = COPY_BACK;
|
|
139
141
|
const top = COPY_FRONT.x - gap;
|
|
140
142
|
const right = COPY_FRONT.y + COPY_FRONT.height + gap;
|
|
143
|
+
const arc = `a${rx} ${rx} 0 00`;
|
|
141
144
|
return square
|
|
142
|
-
? `M${top}
|
|
143
|
-
: `M${top}
|
|
145
|
+
? `M${top} ${y}H${x}V${y + height}H${x + width}V${right}`
|
|
146
|
+
: `M${top} ${y}H${x + rx}${arc}-${rx} ${rx}V${y + height - rx}${arc}${rx} ${rx}H${x + width - rx}${arc}${rx}-${rx}V${right}`;
|
|
144
147
|
}
|
|
145
148
|
/** The front sheet filled and the back one as a line 1 short of it (past its round cap). */
|
|
146
149
|
function copyFilled(front, back, strokeWidth, square = false) {
|
|
@@ -344,15 +347,42 @@ const NtdUnlock = /* @__PURE__ */ createIcon.createIcon({
|
|
|
344
347
|
vivid: ({ primaryColor, secondaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2.5", fill: primaryColor }), jsxRuntime.jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2.5", fill: "white", opacity: "0.08" }), jsxRuntime.jsx("circle", { cx: "12", cy: "15.5", r: "1.5", fill: secondaryColor }), jsxRuntime.jsx("rect", { x: "11.25", y: "16.5", width: "1.5", height: "2", rx: "0.5", fill: "#3B82F6" }), jsxRuntime.jsx("path", { d: "M7 11V7a5 5 0 019.9-1", stroke: "white", strokeWidth: "1" })] })),
|
|
345
348
|
},
|
|
346
349
|
});
|
|
350
|
+
// The selection frame of four corners, shared by NtdFrameCorners and NtdGroup (round 40: the user
|
|
351
|
+
// asked for the frame as an icon of its own). A frame glyph: twice the stroke width in every variant
|
|
352
|
+
// but `outline`, mitred corners.
|
|
353
|
+
/** The top-left and bottom-right corners. */
|
|
354
|
+
const FRAME_CORNERS_MAIN = 'M3 7V3h4M21 17v4h-4';
|
|
355
|
+
/** The top-right and bottom-left corners. */
|
|
356
|
+
const FRAME_CORNERS_OTHER = 'M17 3h4v4M7 21H3v-4';
|
|
357
|
+
function frameCorners(main, other, width) {
|
|
358
|
+
return main === other ? (jsxRuntime.jsx("path", { d: `${FRAME_CORNERS_MAIN}${FRAME_CORNERS_OTHER}`, stroke: main, strokeWidth: width, strokeLinejoin: "miter", fill: "none" })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: FRAME_CORNERS_MAIN, stroke: main, strokeWidth: width, strokeLinejoin: "miter", fill: "none" }), jsxRuntime.jsx("path", { d: FRAME_CORNERS_OTHER, stroke: other, strokeWidth: width, strokeLinejoin: "miter", fill: "none" })] }));
|
|
359
|
+
}
|
|
360
|
+
// Duotone and vivid: two opposite corners primary, the other two secondary.
|
|
361
|
+
const NtdFrameCorners = /* @__PURE__ */ createIcon.createIcon({
|
|
362
|
+
displayName: 'NtdFrameCorners',
|
|
363
|
+
paths: {
|
|
364
|
+
solid: ({ primaryColor, strokeWidth }) => frameCorners(primaryColor, primaryColor, strokeWidth * 2),
|
|
365
|
+
outline: ({ primaryColor, strokeWidth }) => frameCorners(primaryColor, primaryColor, strokeWidth),
|
|
366
|
+
duotone: ({ primaryColor, secondaryColor, strokeWidth }) => frameCorners(primaryColor, secondaryColor, strokeWidth * 2),
|
|
367
|
+
vivid: ({ primaryColor, secondaryColor, strokeWidth }) => frameCorners(primaryColor, secondaryColor, strokeWidth * 2),
|
|
368
|
+
},
|
|
369
|
+
});
|
|
347
370
|
// Group / ungroup selected objects (1.2.2: the diagram toolbar drew them as ⊞ / ⊟).
|
|
348
371
|
// Group: two objects inside the corners of one selection frame; ungroup: the two apart.
|
|
372
|
+
// Round 40: the frame is NtdFrameCorners' (2× the stroke width; the solid one was 1×, vivid's a
|
|
373
|
+
// fixed 2.2). Duotone, fills and the frame: the frame and the top-left object primary, the other
|
|
374
|
+
// object secondary; vivid puts the frame in the accent colour.
|
|
375
|
+
const GROUP_OBJECTS = ['M7 7h5v5H7z', 'M12 12h5v5h-5z'];
|
|
376
|
+
function groupFilled(frame, first, second, strokeWidth, frameOpacity) {
|
|
377
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("g", { opacity: frameOpacity, children: frameCorners(frame, frame, strokeWidth * 2) }), jsxRuntime.jsx("path", { d: GROUP_OBJECTS[0], fill: first }), jsxRuntime.jsx("path", { d: GROUP_OBJECTS[1], fill: second })] }));
|
|
378
|
+
}
|
|
349
379
|
const NtdGroup = /* @__PURE__ */ createIcon.createIcon({
|
|
350
380
|
displayName: 'NtdGroup',
|
|
351
381
|
paths: {
|
|
352
|
-
solid: ({ primaryColor, strokeWidth }) => (
|
|
353
|
-
outline: ({ primaryColor, strokeWidth }) => (jsxRuntime.
|
|
354
|
-
duotone: ({ primaryColor, secondaryColor,
|
|
355
|
-
vivid: ({ primaryColor, secondaryColor
|
|
382
|
+
solid: ({ primaryColor, strokeWidth }) => groupFilled(primaryColor, primaryColor, primaryColor, strokeWidth),
|
|
383
|
+
outline: ({ primaryColor, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [frameCorners(primaryColor, primaryColor, strokeWidth), jsxRuntime.jsx("path", { d: GROUP_OBJECTS.join(''), stroke: primaryColor, strokeWidth: strokeWidth, strokeLinejoin: "miter", fill: "none" })] })),
|
|
384
|
+
duotone: ({ primaryColor, secondaryColor, strokeWidth }) => groupFilled(primaryColor, primaryColor, secondaryColor, strokeWidth),
|
|
385
|
+
vivid: ({ primaryColor, secondaryColor, accentColor, accentOpacity, strokeWidth }) => groupFilled(accentColor, primaryColor, secondaryColor, strokeWidth, accentOpacity),
|
|
356
386
|
},
|
|
357
387
|
});
|
|
358
388
|
const NtdUngroup = /* @__PURE__ */ createIcon.createIcon({
|
|
@@ -372,6 +402,7 @@ exports.NtdDownload = NtdDownload;
|
|
|
372
402
|
exports.NtdEdit = NtdEdit;
|
|
373
403
|
exports.NtdEditDetail = NtdEditDetail;
|
|
374
404
|
exports.NtdFilter = NtdFilter;
|
|
405
|
+
exports.NtdFrameCorners = NtdFrameCorners;
|
|
375
406
|
exports.NtdGroup = NtdGroup;
|
|
376
407
|
exports.NtdLink = NtdLink;
|
|
377
408
|
exports.NtdLock = NtdLock;
|
package/dist/cjs/icons/files.js
CHANGED
|
@@ -377,12 +377,33 @@ const NtdTarget = /* @__PURE__ */ createIcon.createIcon({
|
|
|
377
377
|
vivid: ({ primaryColor, secondaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "2", fill: primaryColor }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "2", fill: "white", opacity: "0.1" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", stroke: secondaryColor, strokeWidth: "1.8", fill: "none" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "6", stroke: "#3B82F6", strokeWidth: "1.5", fill: "none" })] })),
|
|
378
378
|
},
|
|
379
379
|
});
|
|
380
|
+
// NtdTruck, round 40: the filled variants all primary (the cab was a lighter primary with a stroke
|
|
381
|
+
// that also pushed its bottom 0.5 below the box's). The box and the cab are one shape, level at the
|
|
382
|
+
// bottom above the wheels — two shapes of one colour show a seam, and the box's rounded corner left
|
|
383
|
+
// a notch where it met the cab. Duotone and vivid on the theme's colours (vivid had fixed blue and
|
|
384
|
+
// amber wheels): the box primary, the cab secondary; the wheels primary with a ring — secondary in
|
|
385
|
+
// duotone, the accent in vivid, as in solid.
|
|
386
|
+
const TRUCK_BODY = 'M2 3h13a1 1 0 011 1v4h4l3 3v5H2a1 1 0 01-1-1V4a1 1 0 011-1z';
|
|
387
|
+
/** The body with `rounded`'s corners — the derived variant cannot round a path. */
|
|
388
|
+
const TRUCK_BODY_ROUNDED = 'M4 3h9a3 3 0 013 3v2h4l3 3v3a2 2 0 01-2 2H4a3 3 0 01-3-3V6a3 3 0 013-3z';
|
|
389
|
+
/** Duotone and vivid: the box, square where the cab covers it, and the cab 0.5 over it. */
|
|
390
|
+
const TRUCK_BOX = 'M2 3h13a1 1 0 011 1v12H2a1 1 0 01-1-1V4a1 1 0 011-1z';
|
|
391
|
+
const TRUCK_CAB = 'M15.5 8H20l3 3v5h-7.5z';
|
|
392
|
+
const TRUCK_WHEELS = [5.5, 18.5];
|
|
393
|
+
function truckWheels(fill, ring, opacity) {
|
|
394
|
+
return TRUCK_WHEELS.map((cx) => (jsxRuntime.jsx("circle", { cx: cx, cy: "18.5", r: "2.5", fill: fill, stroke: ring, strokeWidth: "1.5", opacity: opacity }, cx)));
|
|
395
|
+
}
|
|
396
|
+
function truckSolid(body, { primaryColor, accentColor, accentOpacity }) {
|
|
397
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: body, fill: primaryColor }), truckWheels(primaryColor, accentColor, accentOpacity)] }));
|
|
398
|
+
}
|
|
380
399
|
const NtdTruck = /* @__PURE__ */ createIcon.createIcon({
|
|
381
400
|
displayName: 'NtdTruck',
|
|
382
401
|
paths: {
|
|
383
|
-
solid: (
|
|
402
|
+
solid: (props) => truckSolid(TRUCK_BODY, props),
|
|
403
|
+
rounded: (props) => truckSolid(TRUCK_BODY_ROUNDED, props),
|
|
384
404
|
outline: ({ primaryColor, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: "M1 3h15v13H1z", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("path", { d: "M16 8h4l3 3v5h-7V8z", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("circle", { cx: "5.5", cy: "18.5", r: "2.5", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("circle", { cx: "18.5", cy: "18.5", r: "2.5", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" })] })),
|
|
385
|
-
|
|
405
|
+
duotone: ({ primaryColor, secondaryColor, secondaryOpacity }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: TRUCK_BOX, fill: primaryColor }), jsxRuntime.jsx("path", { d: TRUCK_CAB, fill: secondaryColor, opacity: secondaryOpacity }), truckWheels(primaryColor, secondaryColor)] })),
|
|
406
|
+
vivid: ({ primaryColor, secondaryColor, accentColor, accentOpacity }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: TRUCK_BOX, fill: primaryColor }), jsxRuntime.jsx("path", { d: TRUCK_CAB, fill: secondaryColor }), truckWheels(primaryColor, accentColor, accentOpacity)] })),
|
|
386
407
|
},
|
|
387
408
|
});
|
|
388
409
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var createIcon = require('../createIcon.js');
|
|
5
|
-
var iconParts = require('../iconParts.js');
|
|
6
5
|
|
|
7
6
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
8
7
|
// Fintech & Crypto Icons
|
|
@@ -25,13 +24,21 @@ const NtdBlockchain = /* @__PURE__ */ createIcon.createIcon({
|
|
|
25
24
|
vivid: ({ primaryColor, secondaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("rect", { x: "3", y: "3", width: "6", height: "6", rx: "1", fill: primaryColor }), jsxRuntime.jsx("rect", { x: "3", y: "3", width: "6", height: "6", rx: "1", fill: "white", opacity: "0.08" }), jsxRuntime.jsx("rect", { x: "15", y: "3", width: "6", height: "6", rx: "1", fill: secondaryColor }), jsxRuntime.jsx("rect", { x: "3", y: "15", width: "6", height: "6", rx: "1", fill: "#10B981" }), jsxRuntime.jsx("rect", { x: "15", y: "15", width: "6", height: "6", rx: "1", fill: "#F59E0B" }), jsxRuntime.jsx("path", { d: "M9 6h6M9 18h6M6 9v6M18 9v6", stroke: "white", strokeWidth: "1", opacity: "0.35" })] })),
|
|
26
25
|
},
|
|
27
26
|
});
|
|
27
|
+
// NtdBitcoin, round 40: the ₿ alone, without the disc it sat on, grown to fill the box and 1.5 × the
|
|
28
|
+
// stroke width in every variant but `outline`. The bars are drawn first, so their ends hide under
|
|
29
|
+
// the letter's top and bottom strokes. Duotone and vivid: the letter primary, the bars secondary.
|
|
30
|
+
const BITCOIN_B = 'M7 12V5h6a3.5 3.5 0 010 7zm0 0v7h7a3.5 3.5 0 000-7z';
|
|
31
|
+
const BITCOIN_BARS = 'M9.5 2v3M13 2v3M9.5 19v3M13 19v3';
|
|
32
|
+
function bitcoinSign(letter, bars, width, barsOpacity) {
|
|
33
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: BITCOIN_BARS, stroke: bars, strokeWidth: width, opacity: barsOpacity }), jsxRuntime.jsx("path", { d: BITCOIN_B, stroke: letter, strokeWidth: width, fill: "none" })] }));
|
|
34
|
+
}
|
|
28
35
|
const NtdBitcoin = /* @__PURE__ */ createIcon.createIcon({
|
|
29
36
|
displayName: 'NtdBitcoin',
|
|
30
37
|
paths: {
|
|
31
|
-
solid: ({ primaryColor }) => (
|
|
32
|
-
outline: ({ primaryColor, strokeWidth }) => (
|
|
33
|
-
duotone:
|
|
34
|
-
vivid: ({ primaryColor, secondaryColor
|
|
38
|
+
solid: ({ primaryColor, strokeWidth }) => bitcoinSign(primaryColor, primaryColor, strokeWidth * 1.5),
|
|
39
|
+
outline: ({ primaryColor, strokeWidth }) => bitcoinSign(primaryColor, primaryColor, strokeWidth),
|
|
40
|
+
duotone: ({ primaryColor, secondaryColor, secondaryOpacity, strokeWidth }) => bitcoinSign(primaryColor, secondaryColor, strokeWidth * 1.5, secondaryOpacity),
|
|
41
|
+
vivid: ({ primaryColor, secondaryColor, strokeWidth }) => bitcoinSign(primaryColor, secondaryColor, strokeWidth * 1.5),
|
|
35
42
|
},
|
|
36
43
|
});
|
|
37
44
|
const NtdEthereum = /* @__PURE__ */ createIcon.createIcon({
|
package/dist/cjs/icons/index.js
CHANGED
|
@@ -54,6 +54,7 @@ exports.NtdDownload = actions.NtdDownload;
|
|
|
54
54
|
exports.NtdEdit = actions.NtdEdit;
|
|
55
55
|
exports.NtdEditDetail = actions.NtdEditDetail;
|
|
56
56
|
exports.NtdFilter = actions.NtdFilter;
|
|
57
|
+
exports.NtdFrameCorners = actions.NtdFrameCorners;
|
|
57
58
|
exports.NtdGroup = actions.NtdGroup;
|
|
58
59
|
exports.NtdLink = actions.NtdLink;
|
|
59
60
|
exports.NtdLock = actions.NtdLock;
|