@nice2dev/icons 1.3.6 → 1.3.8

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 (88) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +37 -17
  3. package/dist/cjs/NiceIconStacker.js +19 -5
  4. package/dist/cjs/createIcon.js +19 -6
  5. package/dist/cjs/iconParts.js +24 -2
  6. package/dist/cjs/iconStack.js +7 -5
  7. package/dist/cjs/icons/accessibility.js +9 -8
  8. package/dist/cjs/icons/actions.js +42 -32
  9. package/dist/cjs/icons/ai.js +12 -11
  10. package/dist/cjs/icons/brand.js +2 -2
  11. package/dist/cjs/icons/business.js +37 -29
  12. package/dist/cjs/icons/devtech.js +17 -15
  13. package/dist/cjs/icons/ecommerce.js +19 -14
  14. package/dist/cjs/icons/education.js +30 -25
  15. package/dist/cjs/icons/files.js +64 -32
  16. package/dist/cjs/icons/fintech.js +2 -11
  17. package/dist/cjs/icons/food.js +12 -8
  18. package/dist/cjs/icons/fun.js +11 -11
  19. package/dist/cjs/icons/gaming.js +20 -13
  20. package/dist/cjs/icons/health.js +38 -25
  21. package/dist/cjs/icons/index.js +1 -0
  22. package/dist/cjs/icons/input.js +31 -21
  23. package/dist/cjs/icons/legal.js +11 -11
  24. package/dist/cjs/icons/media.js +24 -15
  25. package/dist/cjs/icons/navigation.js +16 -13
  26. package/dist/cjs/icons/omniverk.js +2 -7
  27. package/dist/cjs/icons/realestate.js +14 -14
  28. package/dist/cjs/icons/saas.js +0 -10
  29. package/dist/cjs/icons/science.js +12 -12
  30. package/dist/cjs/icons/shapes.js +20 -17
  31. package/dist/cjs/icons/smarthome.js +0 -11
  32. package/dist/cjs/icons/social.js +7 -6
  33. package/dist/cjs/icons/sports.js +5 -6
  34. package/dist/cjs/icons/sustainability.js +12 -11
  35. package/dist/cjs/icons/travel.js +13 -13
  36. package/dist/cjs/icons/ui.js +60 -35
  37. package/dist/cjs/icons/weather.js +12 -16
  38. package/dist/cjs/index.js +1 -0
  39. package/dist/cjs/resolver.js +1 -0
  40. package/dist/cjs/rsc.js +1 -1
  41. package/dist/cjs/stacking.js +49 -11
  42. package/dist/esm/NiceIconStacker.js +22 -8
  43. package/dist/esm/createIcon.js +20 -7
  44. package/dist/esm/iconParts.js +24 -3
  45. package/dist/esm/iconStack.js +7 -5
  46. package/dist/esm/icons/accessibility.js +9 -8
  47. package/dist/esm/icons/actions.js +43 -33
  48. package/dist/esm/icons/ai.js +12 -11
  49. package/dist/esm/icons/brand.js +2 -2
  50. package/dist/esm/icons/business.js +38 -30
  51. package/dist/esm/icons/devtech.js +17 -15
  52. package/dist/esm/icons/ecommerce.js +19 -14
  53. package/dist/esm/icons/education.js +30 -25
  54. package/dist/esm/icons/files.js +65 -33
  55. package/dist/esm/icons/fintech.js +2 -11
  56. package/dist/esm/icons/food.js +12 -8
  57. package/dist/esm/icons/fun.js +11 -11
  58. package/dist/esm/icons/gaming.js +21 -14
  59. package/dist/esm/icons/health.js +38 -25
  60. package/dist/esm/icons/index.js +1 -1
  61. package/dist/esm/icons/input.js +31 -21
  62. package/dist/esm/icons/legal.js +12 -12
  63. package/dist/esm/icons/media.js +25 -16
  64. package/dist/esm/icons/navigation.js +16 -13
  65. package/dist/esm/icons/omniverk.js +2 -7
  66. package/dist/esm/icons/realestate.js +15 -15
  67. package/dist/esm/icons/saas.js +0 -10
  68. package/dist/esm/icons/science.js +12 -12
  69. package/dist/esm/icons/shapes.js +20 -17
  70. package/dist/esm/icons/smarthome.js +0 -11
  71. package/dist/esm/icons/social.js +8 -7
  72. package/dist/esm/icons/sports.js +6 -7
  73. package/dist/esm/icons/sustainability.js +12 -11
  74. package/dist/esm/icons/travel.js +14 -14
  75. package/dist/esm/icons/ui.js +61 -37
  76. package/dist/esm/icons/weather.js +13 -17
  77. package/dist/esm/index.js +1 -1
  78. package/dist/esm/resolver.js +1 -0
  79. package/dist/esm/rsc.js +1 -1
  80. package/dist/esm/stacking.js +46 -12
  81. package/dist/types/createIcon.d.ts +16 -2
  82. package/dist/types/iconParts.d.ts +8 -2
  83. package/dist/types/iconStack.d.ts +18 -3
  84. package/dist/types/icons/index.d.ts +1 -1
  85. package/dist/types/icons/ui.d.ts +1 -0
  86. package/dist/types/stacking.d.ts +30 -5
  87. package/dist/types/types.d.ts +22 -8
  88. package/package.json +2 -2
@@ -14,6 +14,16 @@ function isNtdIconElement(node) {
14
14
  typeof node.type !== 'string' &&
15
15
  Boolean(node.type[NTD_ICON_MARK]));
16
16
  }
17
+ /** Set on every component createIcon makes, next to {@link NTD_ICON_MARK}: its {@link PerfectStack}. */
18
+ const PERFECT_STACK = 'perfectStack';
19
+ /** The spot icon component `icon` keeps for stacked icons; `undefined` when it is not an icon. */
20
+ function perfectStackOf(icon) {
21
+ return icon && (typeof icon === 'object' || typeof icon === 'function')
22
+ ? icon[PERFECT_STACK]
23
+ : undefined;
24
+ }
25
+ /** A child of the spot's default size and no turn, at the box centre — `'center'`. */
26
+ const BOX_PERFECT_STACK = { rotation: 0, size: 0.6 };
17
27
  /** Variants drawn with lines; every other variant is a filled shape. */
18
28
  const LINE_VARIANTS = new Set(['outline', 'wireframe']);
19
29
  function isFilledVariant(variant) {
@@ -36,6 +46,13 @@ function stackPlacement(align, size) {
36
46
  const y = edge.startsWith('top') ? 0 : edge.startsWith('bottom') ? far : mid;
37
47
  return half ? [(x + mid) / 2, (y + mid) / 2] : [x, y];
38
48
  }
49
+ /**
50
+ * `at` moved by `percent` of the parent (`stackOffsetX` / `stackOffsetY`, 1.3.7), in the parent's
51
+ * 24 units. Rounded to a thousandth, so the markup reads 7.2, not 7.199999999999999.
52
+ */
53
+ function stackOffset(at, percent) {
54
+ return percent ? Math.round(1000 * at + 240 * percent) / 1000 : at;
55
+ }
39
56
  /** A corner badge — a full corner; `half-` corners sit inside the parent like its centre. */
40
57
  function isCornerBadge(align) {
41
58
  return /^(top|bottom)-(left|right)$/.test(align);
@@ -43,17 +60,25 @@ function isCornerBadge(align) {
43
60
  /**
44
61
  * Font size of text children by length: one character 9, two 7.5, three 6, more 5 (1.3.6 — three
45
62
  * quarters of the first sizes, so a number sits inside a star or a circle with room round it).
63
+ * In a spot smaller or larger than the default 0.6 (`perfectStackSize`, 1.3.8) it scales with it.
46
64
  */
47
- function defaultTextSize(length) {
48
- return length <= 1 ? 9 : length === 2 ? 7.5 : length === 3 ? 6 : 5;
65
+ function defaultTextSize(length, spot = BOX_PERFECT_STACK.size) {
66
+ const size = length <= 1 ? 9 : length === 2 ? 7.5 : length === 3 ? 6 : 5;
67
+ return spot === BOX_PERFECT_STACK.size
68
+ ? size
69
+ : Math.round((10 * size * spot) / BOX_PERFECT_STACK.size) / 10;
49
70
  }
71
+ /** `n` rounded to a thousandth — 7.2 in the markup, not 7.199999999999999. */
72
+ const thousandth = (n) => Math.round(1000 * n) / 1000;
50
73
  /** The cutout variant draws its shape at 80% in the tile; its stack follows the shape. */
51
74
  const CUTOUT_SHAPE = 'translate(12 12) scale(0.8) translate(-12 -12)';
52
75
  /** The gap kept round a corner badge, in the parent's units. */
53
76
  const BADGE_GAP = 1;
54
77
  /**
55
- * The children of an icon, drawn into it. Colours given on a child win; otherwise:
56
- * - content inside — centred, at an edge or halfway out — is cut out of a filled parent: an icon child takes
78
+ * The children of an icon, drawn into it. A child without a `stackAlign` goes to the spot the icon
79
+ * keeps for it (`ctx.perfect`: its centre, size and turn), and so does text. Colours given on a
80
+ * child win; otherwise:
81
+ * - content inside — at that spot, centred, at an edge or halfway out — is cut out of a filled parent: an icon child takes
57
82
  * the parent's accent as its primary (and the parent's primary as its accent, so its own text
58
83
  * and details read), text the accent; on `outline` / `wireframe` it stays in the parent's
59
84
  * colours; in a cutout it takes the tile's colour, drawn solid in the cut;
@@ -73,13 +98,21 @@ function renderStackChildren(children, ctx) {
73
98
  const text = items
74
99
  .filter((c) => typeof c === 'string' || typeof c === 'number')
75
100
  .join('');
101
+ const { perfect } = ctx;
76
102
  const layers = items.map((child, i) => {
77
- var _a, _b, _c, _d, _e, _f, _g;
103
+ var _a, _b, _c, _d, _e, _f, _g, _h;
78
104
  if (isNtdIconElement(child)) {
79
105
  const p = child.props;
80
- const align = (_a = p.stackAlign) !== null && _a !== void 0 ? _a : 'center';
81
- const size = Math.round(24000 * ((_b = p.stackSize) !== null && _b !== void 0 ? _b : defaultStackSize(align))) / 1000;
82
- const [x, y] = stackPlacement(align, size);
106
+ const align = (_a = p.stackAlign) !== null && _a !== void 0 ? _a : 'perfect';
107
+ // the parent's own spot (1.3.8): its centre, size and turn, unless the child sets them
108
+ const atSpot = align === 'perfect';
109
+ const size = thousandth(24 * ((_b = p.stackSize) !== null && _b !== void 0 ? _b : (atSpot ? perfect.size : defaultStackSize(align))));
110
+ const [alignX, alignY] = atSpot
111
+ ? [thousandth(perfect.x - size / 2), thousandth(perfect.y - size / 2)]
112
+ : stackPlacement(align, size);
113
+ // nudged from the aligned spot (1.3.7) — a share of the parent, so it scales with it
114
+ const x = stackOffset(alignX, p.stackOffsetX);
115
+ const y = stackOffset(alignY, p.stackOffsetY);
83
116
  const badge = isCornerBadge(align);
84
117
  const icon = cloneElement(child, {
85
118
  x,
@@ -93,16 +126,17 @@ function renderStackChildren(children, ctx) {
93
126
  const cx = x + size / 2;
94
127
  const cy = y + size / 2;
95
128
  // turned about its own centre (1.3.6) — through a group: a nested <svg> takes no transform
96
- const turn = p.stackRotation ? `rotate(${p.stackRotation} ${cx} ${cy})` : undefined;
129
+ const rotation = (_g = p.stackRotation) !== null && _g !== void 0 ? _g : (atSpot ? perfect.rotation : 0);
130
+ const turn = rotation ? `rotate(${rotation} ${cx} ${cy})` : undefined;
97
131
  if (!badge && !turn) {
98
132
  return icon;
99
133
  }
100
- return (jsxs("g", { transform: turn, children: [badge && jsx("circle", { cx: cx, cy: cy, r: size / 2 + BADGE_GAP, fill: ctx.accentColor }), icon] }, (_g = child.key) !== null && _g !== void 0 ? _g : i));
134
+ return (jsxs("g", { transform: turn, children: [badge && jsx("circle", { cx: cx, cy: cy, r: size / 2 + BADGE_GAP, fill: ctx.accentColor }), icon] }, (_h = child.key) !== null && _h !== void 0 ? _h : i));
101
135
  }
102
136
  return isValidElement(child) ? child : null;
103
137
  });
104
- const content = (jsxs(Fragment, { children: [layers, text && (jsx("text", { x: ctx.textCenter[0], y: ctx.textCenter[1], textAnchor: "middle", dominantBaseline: "central", fontSize: (_a = ctx.textSize) !== null && _a !== void 0 ? _a : defaultTextSize(text.length), fontWeight: 700, fill: (_b = ctx.textColor) !== null && _b !== void 0 ? _b : insidePrimary, stroke: "none", children: text }))] }));
138
+ const content = (jsxs(Fragment, { children: [layers, text && (jsx("text", { x: perfect.x, y: perfect.y, transform: perfect.rotation ? `rotate(${perfect.rotation} ${perfect.x} ${perfect.y})` : undefined, textAnchor: "middle", dominantBaseline: "central", fontSize: (_a = ctx.textSize) !== null && _a !== void 0 ? _a : defaultTextSize(text.length, perfect.size), fontWeight: 700, fill: (_b = ctx.textColor) !== null && _b !== void 0 ? _b : insidePrimary, stroke: "none", children: text }))] }));
105
139
  return cutout ? jsx("g", { transform: CUTOUT_SHAPE, children: content }) : content;
106
140
  }
107
141
 
108
- export { NTD_ICON_MARK, defaultStackSize, defaultTextSize, isCornerBadge, isFilledVariant, isNtdIconElement, renderStackChildren, stackPlacement };
142
+ export { BOX_PERFECT_STACK, NTD_ICON_MARK, PERFECT_STACK, defaultStackSize, defaultTextSize, isCornerBadge, isFilledVariant, isNtdIconElement, perfectStackOf, renderStackChildren, stackOffset, stackPlacement };
@@ -53,8 +53,11 @@ export interface CreateIconOptions {
53
53
  solid: IconPathRenderer;
54
54
  /** Outlined variant — shapes use `stroke`, `fill="none"`. */
55
55
  outline: IconPathRenderer;
56
- /** Two-tone variant — background fill at reduced opacity + foreground stroke. */
57
- duotone: IconPathRenderer;
56
+ /**
57
+ * Two-tone variant — the larger part primary, the rest secondary. Without it (1.3.8) duotone
58
+ * is the solid with its details (what solid draws in the accent colour) in full secondary.
59
+ */
60
+ duotone?: IconPathRenderer;
58
61
  /** Cutout variant — knockout/cutout: colored background with icon shape cut out. Auto-generated from solid. */
59
62
  cutout?: IconPathRenderer;
60
63
  /** Sharp variant — solid with sharp corners. Falls back to solid if not defined. */
@@ -73,5 +76,16 @@ export interface CreateIconOptions {
73
76
  * for a shape whose middle lies elsewhere (a star, a heart, a triangle).
74
77
  */
75
78
  textCenter?: readonly [number, number];
79
+ /**
80
+ * The spot the icon keeps for what is stacked in it (1.3.8) — where a child without a
81
+ * `stackAlign` goes, and its text: the centre in the 24-unit box (a pin's head, a tag past its
82
+ * hole). Default `textCenter`, else the box centre.
83
+ */
84
+ perfectStackX?: number;
85
+ perfectStackY?: number;
86
+ /** The turn at that spot, degrees clockwise — a child and text there turn with it (along a tag). Default 0. */
87
+ perfectStackRotation?: number;
88
+ /** The share of the icon a child at that spot takes. Default 0.6, as centred. */
89
+ perfectStackSize?: number;
76
90
  }
77
91
  export declare function createIcon(options: CreateIconOptions): import("react").ForwardRefExoticComponent<NtdIconProps & import("react").RefAttributes<SVGSVGElement>>;
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import { createIcon } from './createIcon';
2
+ import { createIcon, type IconPathRenderer } from './createIcon';
3
3
  import type { IconRenderProps } from './types';
4
4
  /**
5
5
  * The colour of a detail drawn in secondary on a filled shape (a floppy's label, a ribbon): the
@@ -7,6 +7,12 @@ import type { IconRenderProps } from './types';
7
7
  * the shape and the detail would vanish, while the accent draws in the cut.
8
8
  */
9
9
  export declare function detailColor({ variant, secondaryColor, accentColor }: IconRenderProps): string;
10
+ /**
11
+ * A duotone renderer with its two colours swapped, at full strength (1.3.8) — for a duotone that
12
+ * drew its larger area in secondary (a pale body under a primary outline): the body turns
13
+ * primary, the outline and the details secondary.
14
+ */
15
+ export declare function swapDuotone(render: IconPathRenderer): IconPathRenderer;
10
16
  /**
11
17
  * `content` drawn only inside `shape` — for accent lines that read as a cut through a shape (a
12
18
  * pencil's band, a calendar's header line, an envelope's flap): clipped, they meet the shape's
@@ -27,6 +33,6 @@ export declare function bellIcon(displayName: string, ringing: boolean): ReturnT
27
33
  * A paper icon — NtdFile, and every document drawn on the same page (NtdFileText, NtdInvoice,
28
34
  * NtdContract, …), so their pages and folds match. The fold is secondary when the page is filled;
29
35
  * `text` is the document's writing, a path of strokes kept below the fold (y ≥ 11, x 7–17),
30
- * drawn in the accent colour on a filled page and in primary on a stroked one.
36
+ * drawn in the accent colour on a filled page (secondary in duotone) and in primary on a stroked one.
31
37
  */
32
38
  export declare function paperIcon(displayName: string, text?: string): ReturnType<typeof createIcon>;
@@ -15,12 +15,27 @@ export interface NiceIconStackLayer {
15
15
  variant?: IconVariant;
16
16
  /** Id of the layer this one sits in (1.3.6). Absent: the base. */
17
17
  parent?: string;
18
- /** Where the layer sits in its parent (not the base). Default `'center'`. */
18
+ /**
19
+ * Where the layer sits in its parent (not the base). Default `'perfect'` — the spot the parent
20
+ * keeps for stacked icons, its centre when it keeps none (1.3.8; it was `'center'`).
21
+ */
19
22
  align?: IconStackAlign;
20
- /** Share of its parent (not the base). Default by `align`: 0.6 centred, 0.5 elsewhere. */
23
+ /**
24
+ * Share of its parent (not the base). Default by `align`: the parent's spot size at `'perfect'`
25
+ * (0.6 when it keeps none), 0.6 centred, 0.5 elsewhere.
26
+ */
21
27
  size?: number;
22
- /** Turn about its own centre, degrees clockwise (not the base, 1.3.6). */
28
+ /**
29
+ * Turn about its own centre, degrees clockwise (not the base, 1.3.6). Default: the turn the
30
+ * parent keeps at its spot when the layer sits there (1.3.8), else none.
31
+ */
23
32
  rotation?: number;
33
+ /**
34
+ * Nudge from where `align` puts it, in percent of its parent: right / down (not the base,
35
+ * 1.3.7) — `stackOffsetX` / `stackOffsetY`.
36
+ */
37
+ offsetX?: number;
38
+ offsetY?: number;
24
39
  /** Colours of its own (1.3.6) — otherwise they follow its parent. */
25
40
  primaryColor?: string;
26
41
  secondaryColor?: string;
@@ -1,6 +1,6 @@
1
1
  export { NtdArrowUp, NtdArrowDown, NtdArrowLeft, NtdArrowRight, NtdChevronUp, NtdChevronDown, NtdChevronLeft, NtdChevronRight, NtdMenu, NtdClose, NtdMoreHorizontal, NtdMoreVertical, NtdExternalLink, NtdRefresh, } from './navigation';
2
2
  export { NtdSearch, NtdEdit, NtdEditDetail, NtdTrash, NtdSave, NtdDownload, NtdUpload, NtdShare, NtdCopy, NtdClipboard, NtdPlus, NtdMinus, NtdCheck, NtdFilter, NtdSort, NtdPrint, NtdZoomIn, NtdZoomOut, NtdUndo, NtdRedo, NtdReply, NtdLink, NtdSettings, NtdLogIn, NtdLogOut, NtdLock, NtdUnlock, NtdGroup, NtdUngroup, } from './actions';
3
- export { NtdHome, NtdUser, NtdAdmin, NtdUsers, NtdHeart, NtdStar, NtdBell, NtdEye, NtdEyeOff, NtdInfo, NtdWarning, NtdError, NtdSuccess, NtdHelp, NtdClock, NtdHourglass, NtdCalendar, NtdTag, NtdBackspace, NtdBookmark, NtdFlag, NtdThumbUp, NtdThumbDown, NtdShield, NtdGlobe, NtdMap, NtdPin, NtdSun, NtdMoon, NtdCursor, NtdWireframe, } from './ui';
3
+ export { NtdHome, NtdUser, NtdAdmin, NtdUsers, NtdHeart, NtdStar, NtdBell, NtdEye, NtdEyeOff, NtdInfo, NtdWarning, NtdError, NtdSuccess, NtdHelp, NtdClock, NtdHourglass, NtdCalendar, NtdTag, NtdBackspace, NtdBookmark, NtdFlag, NtdThumbUp, NtdThumbDown, NtdShield, NtdGlobe, NtdMap, NtdPin, NtdMapPin, NtdSun, NtdMoon, NtdCursor, NtdWireframe, } from './ui';
4
4
  export { NtdRecycle, NtdCompost, NtdTrashSort, NtdSolarPanel, NtdWindTurbine, NtdEvCharger, NtdCarbonFootprint, NtdCo2, NtdNetZero, NtdEcoFriendly, NtdOrganic, NtdBiodegradable, NtdPlantTree, NtdWildlife, sustainabilityIcons, } from './sustainability';
5
5
  export { NtdAccessibility, NtdWheelchair, NtdBlind, NtdDeaf, NtdSignLanguage, NtdBraille, NtdAudioDescription, NtdClosedCaptions, NtdDyslexia, NtdEasyRead, NtdScreenReader, NtdHearingAid, NtdAssistiveTech, accessibilityIcons, } from './accessibility';
6
6
  export { NtdContract, NtdLegalDocument, NtdTermsOfService, NtdPrivacyPolicy, NtdGdpr, NtdCcpa, NtdCookieConsent, NtdCopyright, NtdTrademark, NtdPatent, NtdCompliance, NtdCertified, NtdAudit, legalIcons, } from './legal';
@@ -26,6 +26,7 @@ export declare const NtdShield: import("react").ForwardRefExoticComponent<import
26
26
  export declare const NtdGlobe: import("react").ForwardRefExoticComponent<import("..").NtdIconProps & import("react").RefAttributes<SVGSVGElement>>;
27
27
  export declare const NtdMap: import("react").ForwardRefExoticComponent<import("..").NtdIconProps & import("react").RefAttributes<SVGSVGElement>>;
28
28
  export declare const NtdPin: import("react").ForwardRefExoticComponent<import("..").NtdIconProps & import("react").RefAttributes<SVGSVGElement>>;
29
+ export declare const NtdMapPin: import("react").ForwardRefExoticComponent<import("..").NtdIconProps & import("react").RefAttributes<SVGSVGElement>>;
29
30
  export declare const NtdSun: import("react").ForwardRefExoticComponent<import("..").NtdIconProps & import("react").RefAttributes<SVGSVGElement>>;
30
31
  export declare const NtdMoon: import("react").ForwardRefExoticComponent<import("..").NtdIconProps & import("react").RefAttributes<SVGSVGElement>>;
31
32
  export declare const NtdCursor: import("react").ForwardRefExoticComponent<import("..").NtdIconProps & import("react").RefAttributes<SVGSVGElement>>;
@@ -9,6 +9,23 @@ import type { IconStackAlign, IconVariant, NtdIconProps } from './types';
9
9
  /** Set on every component createIcon makes, so a parent icon tells its icon children apart. */
10
10
  export declare const NTD_ICON_MARK = "ntdIcon";
11
11
  export declare function isNtdIconElement(node: ReactNode): node is ReactElement<NtdIconProps>;
12
+ /**
13
+ * The spot an icon keeps for what is stacked in it (1.3.8) — where a child without a `stackAlign`
14
+ * goes, and its text: the centre `x`, `y` in the 24-unit box, the turn there (degrees, clockwise)
15
+ * and the share of the icon a child takes. `createIcon`'s `perfectStack*` options.
16
+ */
17
+ export interface PerfectStack {
18
+ x: number;
19
+ y: number;
20
+ rotation: number;
21
+ size: number;
22
+ }
23
+ /** Set on every component createIcon makes, next to {@link NTD_ICON_MARK}: its {@link PerfectStack}. */
24
+ export declare const PERFECT_STACK = "perfectStack";
25
+ /** The spot icon component `icon` keeps for stacked icons; `undefined` when it is not an icon. */
26
+ export declare function perfectStackOf(icon: unknown): PerfectStack | undefined;
27
+ /** A child of the spot's default size and no turn, at the box centre — `'center'`. */
28
+ export declare const BOX_PERFECT_STACK: PerfectStack;
12
29
  export declare function isFilledVariant(variant: IconVariant): boolean;
13
30
  /** Default share of the parent: centred children larger, edge and corner badges smaller. */
14
31
  export declare function defaultStackSize(align: IconStackAlign): number;
@@ -17,13 +34,19 @@ export declare function defaultStackSize(align: IconStackAlign): number;
17
34
  * halfway between the centre and the edge or corner it names (1.3.6).
18
35
  */
19
36
  export declare function stackPlacement(align: IconStackAlign, size: number): [number, number];
37
+ /**
38
+ * `at` moved by `percent` of the parent (`stackOffsetX` / `stackOffsetY`, 1.3.7), in the parent's
39
+ * 24 units. Rounded to a thousandth, so the markup reads 7.2, not 7.199999999999999.
40
+ */
41
+ export declare function stackOffset(at: number, percent: number | undefined): number;
20
42
  /** A corner badge — a full corner; `half-` corners sit inside the parent like its centre. */
21
43
  export declare function isCornerBadge(align: IconStackAlign): boolean;
22
44
  /**
23
45
  * Font size of text children by length: one character 9, two 7.5, three 6, more 5 (1.3.6 — three
24
46
  * quarters of the first sizes, so a number sits inside a star or a circle with room round it).
47
+ * In a spot smaller or larger than the default 0.6 (`perfectStackSize`, 1.3.8) it scales with it.
25
48
  */
26
- export declare function defaultTextSize(length: number): number;
49
+ export declare function defaultTextSize(length: number, spot?: number): number;
27
50
  export interface StackContext {
28
51
  variant: IconVariant;
29
52
  /** The parent's primary as drawn (a gradient's `url(#…)` included). */
@@ -32,14 +55,16 @@ export interface StackContext {
32
55
  /** The cutout variant's tile colour — what fills the cut shape's surroundings. */
33
56
  tileColor: string;
34
57
  strokeWidth: number;
35
- /** Where text is centred — the icon's visual centre. */
36
- textCenter: readonly [number, number];
58
+ /** The spot the icon keeps for stacked icons and text (1.3.8). */
59
+ perfect: PerfectStack;
37
60
  textColor?: string;
38
61
  textSize?: number;
39
62
  }
40
63
  /**
41
- * The children of an icon, drawn into it. Colours given on a child win; otherwise:
42
- * - content inside — centred, at an edge or halfway out — is cut out of a filled parent: an icon child takes
64
+ * The children of an icon, drawn into it. A child without a `stackAlign` goes to the spot the icon
65
+ * keeps for it (`ctx.perfect`: its centre, size and turn), and so does text. Colours given on a
66
+ * child win; otherwise:
67
+ * - content inside — at that spot, centred, at an edge or halfway out — is cut out of a filled parent: an icon child takes
43
68
  * the parent's accent as its primary (and the parent's primary as its accent, so its own text
44
69
  * and details read), text the accent; on `outline` / `wireframe` it stays in the parent's
45
70
  * colours; in a cutout it takes the tile's colour, drawn solid in the cut;
@@ -203,7 +203,7 @@ export interface NtdIconProps extends Omit<SVGProps<SVGSVGElement>, 'ref'> {
203
203
  secondaryOpacity?: number;
204
204
  /** Opacity for accent/detail elements (0-1) */
205
205
  accentOpacity?: number;
206
- /** Base stroke width for outline / duotone icons (default 2) */
206
+ /** Base stroke width for outline / duotone icons (default 1) */
207
207
  strokeWidth?: number;
208
208
  /** Stroke line cap style (default 'round') */
209
209
  strokeLinecap?: 'round' | 'square' | 'butt';
@@ -271,14 +271,16 @@ export interface NtdIconProps extends Omit<SVGProps<SVGSVGElement>, 'ref'> {
271
271
  transformOrigin?: string;
272
272
  /**
273
273
  * Where this icon sits when it is a child of another icon (1.3.5):
274
- * `<NtdSquare><NtdStar stackAlign="top-right" /></NtdSquare>`. Default `'center'`; `half-…`
275
- * positions sit halfway from the centre to that edge or corner (1.3.6). Text children
276
- * (`<NtdStar>1</NtdStar>`) are centred on the icon.
274
+ * `<NtdSquare><NtdStar stackAlign="top-right" /></NtdSquare>`. Default `'perfect'` — the spot
275
+ * the parent icon keeps for what is stacked in it (a pin's head, along a tag; 1.3.8), the
276
+ * centre when it keeps none; `'center'` is the middle of the box. `half-…` positions sit
277
+ * halfway from the centre to that edge or corner (1.3.6). Text children
278
+ * (`<NtdStar>1</NtdStar>`) go to the icon's own spot too.
277
279
  */
278
280
  stackAlign?: IconStackAlign;
279
281
  /**
280
282
  * This icon's size as a share of the icon it is stacked in (1.3.5). Default `0.6` centred, `0.5`
281
- * at an edge or a corner.
283
+ * at an edge or a corner, and at the parent's own spot the size it keeps for it (1.3.8).
282
284
  */
283
285
  stackSize?: number;
284
286
  /**
@@ -293,17 +295,29 @@ export interface NtdIconProps extends Omit<SVGProps<SVGSVGElement>, 'ref'> {
293
295
  textSize?: number;
294
296
  /**
295
297
  * Turns this icon, when stacked in another, about its own centre — degrees, clockwise (1.3.6).
296
- * Its own contents and text turn with it.
298
+ * Its own contents and text turn with it. At the parent's own spot it defaults to the turn the
299
+ * parent keeps there (along a tag, 1.3.8); a value given here replaces it.
297
300
  */
298
301
  stackRotation?: number;
302
+ /**
303
+ * Moves this icon, when stacked in another, from where `stackAlign` puts it — in percent of the
304
+ * parent icon's width, positive to the right (1.3.7). `10` = a tenth of the parent across.
305
+ */
306
+ stackOffsetX?: number;
307
+ /**
308
+ * Moves this icon, when stacked in another, from where `stackAlign` puts it — in percent of the
309
+ * parent icon's height, positive downwards (1.3.7).
310
+ */
311
+ stackOffsetY?: number;
299
312
  /** Accessible title for screen readers */
300
313
  title?: string;
301
314
  }
302
315
  /**
303
316
  * Where a stacked icon sits inside the icon it is a child of — the centre, an edge or a corner
304
- * (1.3.5), or halfway from the centre to one (`half-…`, 1.3.6).
317
+ * (1.3.5), halfway from the centre to one (`half-…`, 1.3.6), or the spot the parent keeps for
318
+ * stacked icons (`perfect`, the default, 1.3.8).
305
319
  */
306
- export type IconStackAlign = 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'half-top' | 'half-bottom' | 'half-left' | 'half-right' | 'half-top-left' | 'half-top-right' | 'half-bottom-left' | 'half-bottom-right';
320
+ export type IconStackAlign = 'perfect' | 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'half-top' | 'half-bottom' | 'half-left' | 'half-right' | 'half-top-left' | 'half-top-right' | 'half-bottom-left' | 'half-bottom-right';
307
321
  /**
308
322
  * Props received by icon path renderer functions inside {@link CreateIconOptions.paths}.
309
323
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nice2dev/icons",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "Beautiful, lightweight, multi-color SVG icon library for React with animations",
5
5
  "author": "NiceToDev <contact@nicetodev.com>",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -109,7 +109,7 @@
109
109
  },
110
110
  "devDependencies": {
111
111
  "@chromatic-com/storybook": "^5.3.1",
112
- "@nice2dev/ui-core": "^1.3.6",
112
+ "@nice2dev/ui-core": "^1.3.8",
113
113
  "@rollup/plugin-commonjs": "^29.0.3",
114
114
  "@rollup/plugin-node-resolve": "^16.0.3",
115
115
  "@rollup/plugin-typescript": "^12.3.0",