@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.
Files changed (40) hide show
  1. package/CHANGELOG.md +53 -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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # @nice2dev/icons — Changelog
2
2
 
3
+ ## 1.3.10
4
+
5
+ ### Patch Changes
6
+
7
+ - c694c87: **NiceIconPicker: a stack in every value format, stored as short code by default.**
8
+
9
+ `stackable` no longer needs HTML. With the default `valueFormat="name"` a plain icon stays its export
10
+ name (`NtdFolder`, as before), and a stack becomes short code. A folder with a star in its corner is
11
+ `Folder(Star@tr)`: 15 characters, against close to 1 kB as HTML.
12
+
13
+ The code nests like a function call, parent first, and gives each setting a sign of its own:
14
+
15
+ - `( , )`: what sits in the icon;
16
+ - `:o`: variant;
17
+ - `@tr`: position (`c t b l r`, corners, `h…` halfway);
18
+ - `%40`: size;
19
+ - `^15`: turn;
20
+ - `~5/-3`: nudge;
21
+ - `#2a2`: colours;
22
+ - `'3'`: text, with its own colour and size after it;
23
+ - `{count}`: bound text.
24
+
25
+ Names drop `Ntd`; a name or colour with one of the signs goes in backticks.
26
+
27
+ - **`valueFormat="json"`:** the same tree as JsonML, `["Folder",["Star",{"a":"tr"}]]`.
28
+ `valueFormat="html"` stays as in 1.3.9.
29
+ - **Every format is read, whatever the picker writes:** names, code, JSON and the HTML of 1.3.9.
30
+ Changing the format later breaks no stored value.
31
+ - **New:**
32
+ - `formatIconValue(layers, 'name' | 'json')` and `parseIconValue(text)`, outside React;
33
+ - `NiceIconValue`, which draws a stored value in any format and never injects markup.
34
+ - **`NiceIconHtml`** is now a deprecated wrapper of `NiceIconValue`.
35
+ - **`renderIconStack` / `NiceIconStack`** resolve a name without `Ntd` (`Star` → `NtdStar`).
36
+
37
+ Behaviour change: `stackable` without `valueFormat` used to write HTML (1.3.9) and now writes the
38
+ code. Pass `valueFormat="html"` to keep HTML. Values stored as HTML are still read; the next change
39
+ writes the picker's format.
40
+
41
+ - 4409530: Icons, showcase feedback round 40:
42
+
43
+ - **NtdFrameCorners** (new): the four-corner selection frame, shared with NtdGroup.
44
+ - NtdGroup: the frame is 2× the stroke width in the filled variants. Duotone shows the frame and
45
+ the top-left object in primary and the other object in secondary; vivid puts the frame in the
46
+ accent colour.
47
+ - NtdShuffle: redrawn as two S-curves, 2× the stroke width except in `outline`. The arrow
48
+ underneath breaks where the arrows cross, and the gap is worked out from the stroke width.
49
+ - NtdTruck: the filled variants are all primary. The box and the cab are one shape, level at
50
+ the bottom. Duotone and vivid now use the theme's colours (vivid had fixed blue and amber
51
+ wheels).
52
+ - NtdBitcoin: the ₿ alone, without the disc, 1.5× the stroke width.
53
+ - NtdBluetooth: 1.5× the stroke width except in `outline` (vivid had a fixed 2.2).
54
+ - NtdCopy: the back sheet is smaller; NtdApartment: the building and the door are narrower.
55
+
3
56
  ## 1.3.9
4
57
 
5
58
  ### Patch Changes
@@ -10,6 +10,7 @@ var media = require('./icons/media.js');
10
10
  var navigation = require('./icons/navigation.js');
11
11
  var ui = require('./icons/ui.js');
12
12
  var iconStack = require('./iconStack.js');
13
+ var iconValue = require('./iconValue.js');
13
14
  var NiceIconStacker = require('./NiceIconStacker.js');
14
15
 
15
16
  const MAX_HISTORY_ITEMS = 20;
@@ -73,8 +74,8 @@ function saveToStorage(key, value) {
73
74
  * A fully-featured icon picker dropdown component.
74
75
  *
75
76
  * Provides a trigger button that opens a searchable, categorized icon grid. The value binds both
76
- * ways — `value` / `defaultValue` + `onChange` (1.3.9) — as the icon's export name or, with
77
- * `valueFormat="html"`, as the icon drawn in HTML, ready to store. With `stackable` the panel gets
77
+ * ways — `value` / `defaultValue` + `onChange` (1.3.9) — as the icon's export name, a stack as
78
+ * short code (`Folder(Star@tr)`), JSON or HTML (`valueFormat`). With `stackable` the panel gets
78
79
  * an "Overlays" tab where icons are stacked on the chosen one. Names show without `Ntd`; the
79
80
  * trigger shows the icon alone or the icon and its name (`displayMode`). Keyboard: arrows in the
80
81
  * grid, Escape to close.
@@ -87,7 +88,7 @@ function saveToStorage(key, value) {
87
88
  * import { NiceIconPicker } from '@nice2dev/icons';
88
89
  *
89
90
  * function IconField({ icons, value, onChange }) {
90
- * // stores `<svg data-ntd-icon="NtdStar" …>…</svg>`, a stack included
91
+ * // stores `NtdFolder`, or `Folder(Star@tr)` with a star stacked in its corner
91
92
  * return <NiceIconPicker icons={icons} value={value} onChange={onChange} stackable />;
92
93
  * }
93
94
  * ```
@@ -106,8 +107,8 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
106
107
  const [view, setView] = React.useState('icons');
107
108
  const [picking, setPicking] = React.useState(null);
108
109
  const panelId = React.useId();
109
- const valueFormat = valueFormatProp !== null && valueFormatProp !== void 0 ? valueFormatProp : (stackable ? 'html' : 'name');
110
- const canStack = stackable && !multiSelect && valueFormat === 'html';
110
+ const valueFormat = valueFormatProp !== null && valueFormatProp !== void 0 ? valueFormatProp : 'name';
111
+ const canStack = stackable && !multiSelect;
111
112
  const drawProps = React.useMemo(() => ({ accentColor: PAGE_ACCENT, ...iconProps, variant }), [iconProps, variant]);
112
113
  // Virtualization state
113
114
  const [visibleRange, setVisibleRange] = React.useState({ start: 0, end: virtualizedItemCount });
@@ -143,41 +144,61 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
143
144
  }, [entryOf]);
144
145
  const resolve = React.useCallback((n) => { var _a; return (_a = entryOf(n)) === null || _a === void 0 ? void 0 : _a.Component; }, [entryOf]);
145
146
  /* ─── The single value as a stack — a plain icon is a stack of one ─── */
147
+ // The last value emitted with its layers: read back, the text would number the layers anew
148
+ // (it keeps no ids) and the stacker would lose the layer it has selected.
149
+ const [emitted, setEmitted] = React.useState(null);
146
150
  const model = React.useMemo(() => {
147
151
  if (!value) {
148
152
  return NO_LAYERS;
149
153
  }
150
- const source = iconHtml.parseIconHtml(value);
151
- if (source) {
152
- return source.layers;
154
+ if ((emitted === null || emitted === void 0 ? void 0 : emitted.value) === value) {
155
+ return emitted.layers;
153
156
  }
154
- const entry = value.includes('<') ? undefined : entryOf(value);
155
- return entry ? [{ id: '1', icon: entry.name }] : NO_LAYERS;
156
- }, [value, entryOf]);
157
+ // a name as is first: an older value may hold one of the code's signs
158
+ const exact = value.includes('<') ? undefined : entryOf(value);
159
+ if (exact) {
160
+ return [{ id: '1', icon: exact.name }];
161
+ }
162
+ const layers = iconValue.parseIconValue(value);
163
+ if (!layers || !entryOf(layers[0].icon)) {
164
+ return NO_LAYERS;
165
+ }
166
+ // the code names icons without `Ntd`; the stacker and the grid know them by entry name
167
+ return layers.map((l) => {
168
+ const entry = entryOf(l.icon);
169
+ return entry && entry.name !== l.icon ? { ...l, icon: entry.name } : l;
170
+ });
171
+ }, [value, emitted, entryOf]);
157
172
  // A stack waiting to be drawn into HTML: shown at once, emitted once drawn (below).
158
173
  const [pending, setPending] = React.useState(null);
159
174
  const shown = pending !== null && pending !== void 0 ? pending : model;
160
175
  const base = shown[0];
176
+ /** The name a stack's code gives an icon: without `Ntd`, unless that is another icon's name. */
177
+ const shortName = React.useCallback((n) => {
178
+ const short = iconStack.iconDisplayName(n);
179
+ return short !== n && !byName.has(short) ? short : n;
180
+ }, [byName]);
161
181
  const onChangeRef = React.useRef(onChange);
162
182
  onChangeRef.current = onChange;
163
- const emit = React.useCallback((next, baseName) => {
164
- var _a, _b;
183
+ const emit = React.useCallback((next, layers) => {
184
+ var _a, _b, _c;
185
+ setEmitted(next === null ? null : { value: next, layers });
165
186
  setValue(next);
166
- (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, next, (_b = entryOf(baseName)) !== null && _b !== void 0 ? _b : null);
187
+ (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, next, (_c = entryOf((_b = layers[0]) === null || _b === void 0 ? void 0 : _b.icon)) !== null && _c !== void 0 ? _c : null);
167
188
  }, [setValue, entryOf]);
168
- /** Sets the single value to a stack: its base's name, or the stack drawn as HTML. */
189
+ /** Sets the single value to a stack: written as `valueFormat` holds it, HTML once drawn. */
169
190
  const commit = React.useCallback((layers) => {
170
191
  if (layers.length === 0) {
171
192
  setPending(null);
172
- emit(null);
193
+ emit(null, NO_LAYERS);
173
194
  }
174
- else if (valueFormat === 'name') {
175
- emit(layers[0].icon, layers[0].icon);
195
+ else if (valueFormat === 'html') {
196
+ setPending(layers);
176
197
  }
177
198
  else {
178
- setPending(layers);
199
+ emit(iconValue.formatIconValue(layers, valueFormat, { shortName }), layers);
179
200
  }
180
- }, [valueFormat, emit]);
201
+ }, [valueFormat, emit, shortName]);
181
202
  // The HTML is the icon as drawn: the hidden copy below renders the pending stack, and its
182
203
  // markup — ids renamed after the drawing — is the new value, emitted before the paint.
183
204
  useIsoLayoutEffect(() => {
@@ -188,7 +209,7 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
188
209
  const svg = (_a = serializerRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
189
210
  setPending(null);
190
211
  if (svg) {
191
- emit(iconHtml.scopeIconHtmlIds(svg.outerHTML), pending[0].icon);
212
+ emit(iconHtml.scopeIconHtmlIds(svg.outerHTML), pending);
192
213
  }
193
214
  }, [pending, emit]);
194
215
  const selectedValues = React.useMemo(() => (multiSelect ? values : base ? [base.icon] : NO_NAMES), [multiSelect, values, base]);
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var iconStack = require('./iconStack.js');
5
+ var iconValue = require('./iconValue.js');
6
+
7
+ /** The value's layers: a name the resolver knows as is (it may hold the code's signs), else parsed. */
8
+ function layersOf(value, icons) {
9
+ const text = value === null || value === void 0 ? void 0 : value.trim();
10
+ if (!text) {
11
+ return null;
12
+ }
13
+ const known = typeof icons === 'function' ? icons(text) : icons[text];
14
+ const plain = [{ id: '1', icon: text }];
15
+ return known ? plain : iconValue.parseIconValue(text);
16
+ }
17
+ /**
18
+ * NiceIconValue (1.3.10) — shows an icon as NiceIconPicker stored it, whatever the format: a name,
19
+ * the code of a stack, JSON or HTML. It draws the icon again from the data; stored markup is never
20
+ * injected, so a value from a database cannot run anything. The rest of the props go to the base
21
+ * icon.
22
+ */
23
+ function NiceIconValue({ value, icons, values, fallback = null, ...baseProps }) {
24
+ const layers = layersOf(value, icons);
25
+ const drawn = layers ? iconStack.renderIconStack(layers, icons, { baseProps, values }) : null;
26
+ return jsxRuntime.jsx(jsxRuntime.Fragment, { children: drawn !== null && drawn !== void 0 ? drawn : fallback });
27
+ }
28
+ if (process.env.NODE_ENV !== 'production') {
29
+ NiceIconValue.displayName = 'NiceIconValue';
30
+ }
31
+ /**
32
+ * NiceIconHtml (1.3.9) — shows an icon kept as HTML.
33
+ *
34
+ * @deprecated Since 1.3.10 use `NiceIconValue`, which reads every format the picker writes.
35
+ */
36
+ function NiceIconHtml({ html, ...props }) {
37
+ return jsxRuntime.jsx(NiceIconValue, { value: html, ...props });
38
+ }
39
+ if (process.env.NODE_ENV !== 'production') {
40
+ NiceIconHtml.displayName = 'NiceIconHtml';
41
+ }
42
+
43
+ exports.NiceIconHtml = NiceIconHtml;
44
+ exports.NiceIconValue = NiceIconValue;
@@ -2,6 +2,8 @@
2
2
 
3
3
  var animationControls = require('./animationControls.js');
4
4
  var NiceIconPicker = require('./NiceIconPicker.js');
5
+ var NiceIconValue = require('./NiceIconValue.js');
6
+ var iconValue = require('./iconValue.js');
5
7
  var iconHtml = require('./iconHtml.js');
6
8
  var NiceIconStacker = require('./NiceIconStacker.js');
7
9
  var iconStack = require('./iconStack.js');
@@ -21,7 +23,10 @@ exports.createHoverAnimation = animationControls.createHoverAnimation;
21
23
  exports.createVisibilityAnimation = animationControls.createVisibilityAnimation;
22
24
  exports.useAnimationSequence = animationControls.useAnimationSequence;
23
25
  exports.NiceIconPicker = NiceIconPicker.NiceIconPicker;
24
- exports.NiceIconHtml = iconHtml.NiceIconHtml;
26
+ exports.NiceIconHtml = NiceIconValue.NiceIconHtml;
27
+ exports.NiceIconValue = NiceIconValue.NiceIconValue;
28
+ exports.formatIconValue = iconValue.formatIconValue;
29
+ exports.parseIconValue = iconValue.parseIconValue;
25
30
  exports.parseIconHtml = iconHtml.parseIconHtml;
26
31
  exports.NiceIconStacker = NiceIconStacker.NiceIconStacker;
27
32
  exports.NiceIconStack = iconStack.NiceIconStack;
@@ -1,8 +1,5 @@
1
1
  'use strict';
2
2
 
3
- var jsxRuntime = require('react/jsx-runtime');
4
- var iconStack = require('./iconStack.js');
5
-
6
3
  /**
7
4
  * An icon — or a stack of icons — kept as HTML (1.3.9): the `<svg>` NiceIconPicker draws, ready to
8
5
  * store in a database and to show anywhere, even without React. What it was drawn from rides along
@@ -101,22 +98,7 @@ function scopeIconHtmlIds(markup) {
101
98
  const name = hash(rename((id) => `#${index.get(id)}`));
102
99
  return rename((id) => `ntd-${name}-${index.get(id)}`);
103
100
  }
104
- /**
105
- * NiceIconHtml (1.3.9) — shows an icon kept as HTML in a React page by drawing it again from its
106
- * data attributes; the markup itself is never injected, so HTML from a database cannot run anything.
107
- * A plain export name (`'NtdStar'`) works too. The rest of the props go to the base icon.
108
- */
109
- function NiceIconHtml({ html, icons, values, fallback = null, ...baseProps }) {
110
- var _a;
111
- const source = (_a = parseIconHtml(html)) !== null && _a !== void 0 ? _a : (html && !html.includes('<') ? { layers: [{ id: '1', icon: html }] } : null);
112
- const drawn = source ? iconStack.renderIconStack(source.layers, icons, { baseProps, values }) : null;
113
- return jsxRuntime.jsx(jsxRuntime.Fragment, { children: drawn !== null && drawn !== void 0 ? drawn : fallback });
114
- }
115
- if (process.env.NODE_ENV !== 'production') {
116
- NiceIconHtml.displayName = 'NiceIconHtml';
117
- }
118
101
 
119
- exports.NiceIconHtml = NiceIconHtml;
120
102
  exports.iconHtmlAttributes = iconHtmlAttributes;
121
103
  exports.parseIconHtml = parseIconHtml;
122
104
  exports.scopeIconHtmlIds = scopeIconHtmlIds;
@@ -127,7 +127,9 @@ function niceIconStackCode(layers) {
127
127
  * One SVG, as nesting the icons by hand would give.
128
128
  */
129
129
  function renderIconStack(layers, icons, { baseProps, values } = {}) {
130
- const resolve = (name) => (typeof icons === 'function' ? icons(name) : icons[name]);
130
+ const lookup = (name) => (typeof icons === 'function' ? icons(name) : icons[name]);
131
+ // a stack kept as text names its icons without `Ntd` (1.3.10)
132
+ const resolve = (name) => { var _a; return (_a = lookup(name)) !== null && _a !== void 0 ? _a : lookup(`Ntd${name}`); };
131
133
  const draw = (layer, parent) => {
132
134
  var _a;
133
135
  const Icon = resolve(layer.icon);