@nice2dev/icons 1.3.9 → 1.3.11

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 (40) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/cjs/NiceIconPicker.js +42 -21
  3. package/dist/cjs/NiceIconValue.js +44 -0
  4. package/dist/cjs/client.js +6 -1
  5. package/dist/cjs/iconHtml.js +0 -18
  6. package/dist/cjs/iconStack.js +3 -1
  7. package/dist/cjs/iconValue.js +473 -0
  8. package/dist/cjs/icons/actions.js +39 -8
  9. package/dist/cjs/icons/files.js +23 -2
  10. package/dist/cjs/icons/fintech.js +12 -5
  11. package/dist/cjs/icons/index.js +1 -0
  12. package/dist/cjs/icons/media.js +7 -4
  13. package/dist/cjs/icons/realestate.js +8 -7
  14. package/dist/cjs/icons/shapes.js +55 -4
  15. package/dist/cjs/index.js +7 -1
  16. package/dist/cjs/nicetodev-icons.css +1 -1
  17. package/dist/esm/NiceIconPicker.js +43 -22
  18. package/dist/esm/NiceIconValue.js +41 -0
  19. package/dist/esm/client.js +3 -1
  20. package/dist/esm/iconHtml.js +1 -18
  21. package/dist/esm/iconStack.js +3 -1
  22. package/dist/esm/iconValue.js +470 -0
  23. package/dist/esm/icons/actions.js +39 -9
  24. package/dist/esm/icons/files.js +23 -2
  25. package/dist/esm/icons/fintech.js +12 -5
  26. package/dist/esm/icons/index.js +1 -1
  27. package/dist/esm/icons/media.js +8 -5
  28. package/dist/esm/icons/realestate.js +8 -7
  29. package/dist/esm/icons/shapes.js +55 -4
  30. package/dist/esm/index.js +4 -2
  31. package/dist/esm/nicetodev-icons.css +1 -1
  32. package/dist/types/NiceIconPicker.d.ts +22 -16
  33. package/dist/types/NiceIconValue.d.ts +40 -0
  34. package/dist/types/client.d.ts +6 -2
  35. package/dist/types/iconHtml.d.ts +1 -23
  36. package/dist/types/iconValue.d.ts +22 -0
  37. package/dist/types/icons/actions.d.ts +1 -0
  38. package/dist/types/icons/index.d.ts +1 -1
  39. package/dist/types/index.d.ts +6 -2
  40. 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: 8.5, width: 12.5, height: 12.5, rx: 2.5 };
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} 8.5H3V21h12.5V${right}`
143
- : `M${top} 8.5H5.5a2.5 2.5 0 00-2.5 2.5v7.5a2.5 2.5 0 002.5 2.5h7.5a2.5 2.5 0 002.5-2.5V${right}`;
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 }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: "M3 7V3h4M17 3h4v4M21 17v4h-4M7 21H3v-4", stroke: primaryColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }), jsxRuntime.jsx("rect", { x: "7", y: "7", width: "5", height: "5", fill: primaryColor }), jsxRuntime.jsx("rect", { x: "12", y: "12", width: "5", height: "5", fill: primaryColor })] })),
353
- outline: ({ primaryColor, strokeWidth }) => (jsxRuntime.jsx("path", { d: "M3 7V3h4M17 3h4v4M21 17v4h-4M7 21H3v-4M7 7h5v5H7zM12 12h5v5h-5z", stroke: primaryColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" })),
354
- duotone: ({ primaryColor, secondaryColor, secondaryOpacity, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("rect", { x: "7", y: "7", width: "5", height: "5", fill: secondaryColor, opacity: secondaryOpacity }), jsxRuntime.jsx("rect", { x: "12", y: "12", width: "5", height: "5", fill: secondaryColor, opacity: secondaryOpacity }), jsxRuntime.jsx("path", { d: "M3 7V3h4M17 3h4v4M21 17v4h-4M7 21H3v-4M7 7h5v5H7zM12 12h5v5h-5z", stroke: primaryColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" })] })),
355
- vivid: ({ primaryColor, secondaryColor: _secondaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: "M3 7V3h4M17 3h4v4M21 17v4h-4M7 21H3v-4", stroke: primaryColor, strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }), jsxRuntime.jsx("rect", { x: "7", y: "7", width: "5", height: "5", fill: primaryColor }), jsxRuntime.jsx("rect", { x: "12", y: "12", width: "5", height: "5", fill: primaryColor })] })),
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;
@@ -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: ({ primaryColor, accentColor, accentOpacity, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("rect", { x: "1", y: "3", width: "15", height: "13", rx: "1", fill: primaryColor }), jsxRuntime.jsx("path", { d: "M16 8h4l3 3v5h-7V8z", fill: primaryColor, opacity: "0.7", stroke: primaryColor, strokeWidth: strokeWidth }), jsxRuntime.jsx("circle", { cx: "5.5", cy: "18.5", r: "2.5", fill: primaryColor, stroke: accentColor, strokeWidth: "1.5", opacity: accentOpacity }), jsxRuntime.jsx("circle", { cx: "18.5", cy: "18.5", r: "2.5", fill: primaryColor, stroke: accentColor, strokeWidth: "1.5", opacity: accentOpacity })] })),
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
- vivid: ({ primaryColor, secondaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("rect", { x: "1", y: "3", width: "15", height: "13", rx: "1", fill: primaryColor }), jsxRuntime.jsx("rect", { x: "1", y: "3", width: "15", height: "13", rx: "1", fill: "white", opacity: "0.08" }), jsxRuntime.jsx("path", { d: "M16 8h4l3 3v5h-7V8z", fill: secondaryColor, opacity: "0.7", stroke: secondaryColor, strokeWidth: "2" }), jsxRuntime.jsx("circle", { cx: "5.5", cy: "18.5", r: "2.5", fill: "#3B82F6", stroke: "#3B82F6", strokeWidth: "1.5" }), jsxRuntime.jsx("circle", { cx: "18.5", cy: "18.5", r: "2.5", fill: "#F59E0B", stroke: "#F59E0B", strokeWidth: "1.5" })] })),
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 }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", fill: primaryColor }), jsxRuntime.jsx("path", { d: "M9 7h4.5a2.5 2.5 0 010 5H9V7zM9 12h5a2.5 2.5 0 010 5H9v-5z", fill: "#fff" }), jsxRuntime.jsx("path", { d: "M10 5v2M14 5v2M10 17v2M14 17v2", stroke: "#fff", strokeWidth: "1.5" })] })),
32
- outline: ({ primaryColor, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("path", { d: "M9 7h4.5a2.5 2.5 0 010 5H9V7zM9 12h5a2.5 2.5 0 010 5H9v-5z", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("path", { d: "M10 5v2M14 5v2M10 17v2M14 17v2", stroke: primaryColor, strokeWidth: strokeWidth })] })),
33
- duotone: iconParts.swapDuotone(({ primaryColor, secondaryColor, secondaryOpacity, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", fill: secondaryColor, opacity: secondaryOpacity }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("path", { d: "M9 7h4.5a2.5 2.5 0 010 5H9V7zM9 12h5a2.5 2.5 0 010 5H9v-5z", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("path", { d: "M10 5v2M14 5v2M10 17v2M14 17v2", stroke: primaryColor, strokeWidth: strokeWidth })] }))),
34
- vivid: ({ primaryColor, secondaryColor: _secondaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", fill: primaryColor }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10", fill: "white", opacity: "0.08" }), jsxRuntime.jsx("path", { d: "M9 7h4.5a2.5 2.5 0 010 5H9V7zM9 12h5a2.5 2.5 0 010 5H9v-5z", fill: "#fff" }), jsxRuntime.jsx("path", { d: "M10 5v2M14 5v2M10 17v2M14 17v2", stroke: "#fff", strokeWidth: "1" })] })),
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({
@@ -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;