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