@nice2dev/icons-cursor 1.0.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 (58) hide show
  1. package/README.md +241 -0
  2. package/dist/createCursorIcon-CCO9eeBk.mjs +170 -0
  3. package/dist/createCursorIcon-CCO9eeBk.mjs.map +1 -0
  4. package/dist/createCursorIcon-Crwdo_Qk.js +169 -0
  5. package/dist/createCursorIcon-Crwdo_Qk.js.map +1 -0
  6. package/dist/createCursorIcon.d.ts +11 -0
  7. package/dist/createCursorIcon.d.ts.map +1 -0
  8. package/dist/cursorBuilder.d.ts +242 -0
  9. package/dist/cursorBuilder.d.ts.map +1 -0
  10. package/dist/index.cjs +288 -0
  11. package/dist/index.cjs.map +1 -0
  12. package/dist/index.d.ts +101 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.mjs +292 -0
  15. package/dist/index.mjs.map +1 -0
  16. package/dist/pointers-DW_cbtGT.mjs +90 -0
  17. package/dist/pointers-DW_cbtGT.mjs.map +1 -0
  18. package/dist/pointers-DxPqgPxN.js +89 -0
  19. package/dist/pointers-DxPqgPxN.js.map +1 -0
  20. package/dist/pointers.cjs +21 -0
  21. package/dist/pointers.cjs.map +1 -0
  22. package/dist/pointers.d.ts +36 -0
  23. package/dist/pointers.d.ts.map +1 -0
  24. package/dist/pointers.mjs +21 -0
  25. package/dist/pointers.mjs.map +1 -0
  26. package/dist/selection-CINU3bsI.js +101 -0
  27. package/dist/selection-CINU3bsI.js.map +1 -0
  28. package/dist/selection-W-1ZhqSv.mjs +102 -0
  29. package/dist/selection-W-1ZhqSv.mjs.map +1 -0
  30. package/dist/selection.cjs +21 -0
  31. package/dist/selection.cjs.map +1 -0
  32. package/dist/selection.d.ts +36 -0
  33. package/dist/selection.d.ts.map +1 -0
  34. package/dist/selection.mjs +21 -0
  35. package/dist/selection.mjs.map +1 -0
  36. package/dist/status-BBrDqBw_.mjs +111 -0
  37. package/dist/status-BBrDqBw_.mjs.map +1 -0
  38. package/dist/status-L6N47QMq.js +110 -0
  39. package/dist/status-L6N47QMq.js.map +1 -0
  40. package/dist/status.cjs +21 -0
  41. package/dist/status.cjs.map +1 -0
  42. package/dist/status.d.ts +36 -0
  43. package/dist/status.d.ts.map +1 -0
  44. package/dist/status.mjs +21 -0
  45. package/dist/status.mjs.map +1 -0
  46. package/dist/tools-DbPCbk54.mjs +108 -0
  47. package/dist/tools-DbPCbk54.mjs.map +1 -0
  48. package/dist/tools-ttgDzC_5.js +107 -0
  49. package/dist/tools-ttgDzC_5.js.map +1 -0
  50. package/dist/tools.cjs +21 -0
  51. package/dist/tools.cjs.map +1 -0
  52. package/dist/tools.d.ts +36 -0
  53. package/dist/tools.d.ts.map +1 -0
  54. package/dist/tools.mjs +21 -0
  55. package/dist/tools.mjs.map +1 -0
  56. package/dist/types.d.ts +55 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/package.json +71 -0
@@ -0,0 +1,242 @@
1
+ import { CSSProperties } from 'react';
2
+ import { CursorIcon, CursorIconProps } from './types';
3
+ /**
4
+ * Cursor hotspot position (where the click is registered)
5
+ */
6
+ export interface CursorHotspot {
7
+ /** X coordinate of hotspot (0-based, measured from left) */
8
+ x: number;
9
+ /** Y coordinate of hotspot (0-based, measured from top) */
10
+ y: number;
11
+ }
12
+ /**
13
+ * Options for building a CSS cursor
14
+ */
15
+ export interface CursorBuilderOptions {
16
+ /** Icon size in pixels (default: 32) */
17
+ size?: number;
18
+ /** Icon color (default: #000) */
19
+ color?: string;
20
+ /** Secondary color for duotone variant */
21
+ secondaryColor?: string;
22
+ /** Hotspot position (default: { x: 0, y: 0 }) */
23
+ hotspot?: CursorHotspot;
24
+ /** Fallback CSS cursor value (default: 'auto') */
25
+ fallback?: string;
26
+ /** Icon variant */
27
+ variant?: CursorIconProps['variant'];
28
+ }
29
+ /**
30
+ * Result from building a cursor
31
+ */
32
+ export interface CursorBuilderResult {
33
+ /** The CSS cursor value (data URI + fallback) */
34
+ cursor: string;
35
+ /** The data URI only */
36
+ dataUri: string;
37
+ /** The hotspot used */
38
+ hotspot: CursorHotspot;
39
+ /** The size used */
40
+ size: number;
41
+ }
42
+ /**
43
+ * Default hotspot positions for common cursor types.
44
+ * Values are normalized (0-1), will be multiplied by size.
45
+ */
46
+ export declare const DEFAULT_HOTSPOTS: Record<string, CursorHotspot>;
47
+ /**
48
+ * Get normalized hotspot for an icon by name
49
+ */
50
+ export declare function getDefaultHotspot(iconName: string): CursorHotspot;
51
+ /**
52
+ * Convert an SVG cursor icon to a CSS cursor value.
53
+ *
54
+ * @param IconComponent - The cursor icon React component
55
+ * @param options - Cursor building options
56
+ * @returns CSS cursor value with data URI and fallback
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * import { Pointer, buildCursor } from '@nice2dev/icons-cursor';
61
+ *
62
+ * const { cursor } = buildCursor(Pointer, {
63
+ * size: 32,
64
+ * color: '#333',
65
+ * hotspot: { x: 0, y: 0 }
66
+ * });
67
+ *
68
+ * // Use in styles
69
+ * <div style={{ cursor }} />
70
+ * ```
71
+ */
72
+ export declare function buildCursor(IconComponent: CursorIcon, options?: CursorBuilderOptions): CursorBuilderResult;
73
+ /**
74
+ * Create a pre-configured cursor builder for a specific icon.
75
+ *
76
+ * @param IconComponent - The cursor icon React component
77
+ * @returns Function that takes options and returns cursor CSS
78
+ *
79
+ * @example
80
+ * ```tsx
81
+ * const penCursor = createCursorBuilder(Pen);
82
+ *
83
+ * // Later use with different options
84
+ * const cursor1 = penCursor({ color: 'red' });
85
+ * const cursor2 = penCursor({ color: 'blue', size: 48 });
86
+ * ```
87
+ */
88
+ export declare function createCursorBuilder(IconComponent: CursorIcon): (options?: CursorBuilderOptions) => CursorBuilderResult;
89
+ /**
90
+ * Build multiple cursors at once with shared options.
91
+ *
92
+ * @param icons - Map of cursor names to icon components
93
+ * @param sharedOptions - Options applied to all cursors
94
+ * @returns Map of cursor names to their CSS values
95
+ *
96
+ * @example
97
+ * ```tsx
98
+ * const cursors = buildCursors({
99
+ * pointer: Pointer,
100
+ * pen: Pen,
101
+ * eraser: Eraser,
102
+ * }, { size: 24, color: '#333' });
103
+ *
104
+ * // cursors.pointer => "url(data:...) 0 0, auto"
105
+ * // cursors.pen => "url(data:...) 2 22, auto"
106
+ * ```
107
+ */
108
+ export declare function buildCursors<T extends Record<string, CursorIcon>>(icons: T, sharedOptions?: CursorBuilderOptions): Record<keyof T, string>;
109
+ /**
110
+ * Generate CSS custom properties for cursor icons.
111
+ * Useful for defining cursors once and using them via CSS variables.
112
+ *
113
+ * @param icons - Map of cursor names to icon components
114
+ * @param options - Cursor building options
115
+ * @param prefix - CSS variable prefix (default: '--cursor')
116
+ * @returns CSS string with custom property definitions
117
+ *
118
+ * @example
119
+ * ```tsx
120
+ * const css = generateCursorCSS({
121
+ * pointer: Pointer,
122
+ * pen: Pen,
123
+ * });
124
+ *
125
+ * // Returns:
126
+ * // :root {
127
+ * // --cursor-pointer: url(data:...) 0 0, auto;
128
+ * // --cursor-pen: url(data:...) 2 22, auto;
129
+ * // }
130
+ * ```
131
+ */
132
+ export declare function generateCursorCSS<T extends Record<string, CursorIcon>>(icons: T, options?: CursorBuilderOptions, prefix?: string): string;
133
+ /**
134
+ * Hook to apply a custom cursor to an element.
135
+ * Returns style object and handlers for dynamic cursor changes.
136
+ *
137
+ * @param IconComponent - The cursor icon component
138
+ * @param options - Cursor building options
139
+ * @returns Style object with cursor property
140
+ *
141
+ * @example
142
+ * ```tsx
143
+ * function Canvas() {
144
+ * const cursorStyle = useCursor(Pen, { color: 'blue' });
145
+ *
146
+ * return <div style={cursorStyle}>Draw here</div>;
147
+ * }
148
+ * ```
149
+ */
150
+ export declare function useCursor(IconComponent: CursorIcon | null, options?: CursorBuilderOptions): CSSProperties;
151
+ /**
152
+ * Hook to manage multiple cursors with easy switching.
153
+ *
154
+ * @param cursors - Map of cursor names to icon components
155
+ * @param options - Shared cursor building options
156
+ * @returns Tuple of [currentStyle, setCursor, cursorMap]
157
+ *
158
+ * @example
159
+ * ```tsx
160
+ * function Editor() {
161
+ * const [style, setCursor, cursors] = useCursors({
162
+ * pointer: Pointer,
163
+ * pen: Pen,
164
+ * eraser: Eraser,
165
+ * });
166
+ *
167
+ * return (
168
+ * <div style={style}>
169
+ * <button onClick={() => setCursor('pen')}>Pen</button>
170
+ * <button onClick={() => setCursor('eraser')}>Eraser</button>
171
+ * </div>
172
+ * );
173
+ * }
174
+ * ```
175
+ */
176
+ export declare function useCursors<T extends Record<string, CursorIcon>>(cursors: T, options?: CursorBuilderOptions): [CSSProperties, (name: keyof T | null) => void, Record<keyof T, string>];
177
+ /**
178
+ * Configuration for a complete cursor theme
179
+ */
180
+ export interface CursorTheme {
181
+ default: string;
182
+ pointer: string;
183
+ text: string;
184
+ wait: string;
185
+ help: string;
186
+ notAllowed: string;
187
+ grab: string;
188
+ grabbing: string;
189
+ crosshair: string;
190
+ move: string;
191
+ resizeN: string;
192
+ resizeS: string;
193
+ resizeE: string;
194
+ resizeW: string;
195
+ resizeNE: string;
196
+ resizeNW: string;
197
+ resizeSE: string;
198
+ resizeSW: string;
199
+ resizeHorizontal: string;
200
+ resizeVertical: string;
201
+ }
202
+ /**
203
+ * Create a complete cursor theme from cursor icons.
204
+ *
205
+ * @param theme - Map of cursor type to icon component
206
+ * @param options - Shared building options
207
+ * @returns Complete cursor theme object
208
+ *
209
+ * @example
210
+ * ```tsx
211
+ * import * as cursors from '@nice2dev/icons-cursor';
212
+ *
213
+ * const theme = createCursorTheme({
214
+ * default: cursors.Pointer,
215
+ * pointer: cursors.PointerFinger,
216
+ * text: cursors.TextCursor,
217
+ * // ...
218
+ * }, { size: 24 });
219
+ *
220
+ * // Apply to CSS
221
+ * document.body.style.cursor = theme.default;
222
+ * ```
223
+ */
224
+ export declare function createCursorTheme(theme: Partial<Record<keyof CursorTheme, CursorIcon>>, options?: CursorBuilderOptions): Partial<CursorTheme>;
225
+ /**
226
+ * Apply a cursor theme to the document's CSS custom properties.
227
+ * This allows using the cursors via CSS: `cursor: var(--cursor-pointer)`
228
+ *
229
+ * @param theme - Cursor theme to apply
230
+ * @param prefix - CSS variable prefix (default: '--cursor')
231
+ *
232
+ * @example
233
+ * ```tsx
234
+ * const theme = createCursorTheme({ ... });
235
+ * applyCursorTheme(theme);
236
+ *
237
+ * // In CSS:
238
+ * // .button:hover { cursor: var(--cursor-pointer); }
239
+ * ```
240
+ */
241
+ export declare function applyCursorTheme(theme: Partial<CursorTheme>, prefix?: string): void;
242
+ //# sourceMappingURL=cursorBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursorBuilder.d.ts","sourceRoot":"","sources":["../src/cursorBuilder.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,OAAO,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA0B3D;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,CAAC,EAAE,MAAM,CAAC;IACV,2DAA2D;IAC3D,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAID;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAmC1D,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CA4CjE;AAID;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CACzB,aAAa,EAAE,UAAU,EACzB,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CAoDrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,UAAU,GACxB,CAAC,OAAO,CAAC,EAAE,oBAAoB,KAAK,mBAAmB,CAEzD;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EAC/D,KAAK,EAAE,CAAC,EACR,aAAa,GAAE,oBAAyB,GACvC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAQzB;AAID;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EACpE,KAAK,EAAE,CAAC,EACR,OAAO,GAAE,oBAAyB,EAClC,MAAM,SAAa,GAClB,MAAM,CAOR;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CACvB,aAAa,EAAE,UAAU,GAAG,IAAI,EAChC,OAAO,GAAE,oBAAyB,GACjC,aAAa,CAkBf;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7D,OAAO,EAAE,CAAC,EACV,OAAO,GAAE,oBAAyB,GACjC,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,KAAK,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAgB1E;AAID;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,WAAW,EAAE,UAAU,CAAC,CAAC,EACrD,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,WAAW,CAAC,CAUtB;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,SAAa,GAAG,IAAI,CAUvF"}
package/dist/index.cjs ADDED
@@ -0,0 +1,288 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const createCursorIcon = require("./createCursorIcon-Crwdo_Qk.js");
4
+ const React = require("react");
5
+ const pointers = require("./pointers-DxPqgPxN.js");
6
+ const selection = require("./selection-CINU3bsI.js");
7
+ const status = require("./status-L6N47QMq.js");
8
+ const tools = require("./tools-ttgDzC_5.js");
9
+ let cachedRenderer = null;
10
+ function getRenderer() {
11
+ if (cachedRenderer) {
12
+ return cachedRenderer;
13
+ }
14
+ const reactDomServer = require("react-dom/server");
15
+ cachedRenderer = reactDomServer.renderToStaticMarkup;
16
+ return cachedRenderer;
17
+ }
18
+ const DEFAULT_HOTSPOTS = {
19
+ // Pointer at tip (top-left)
20
+ pointer: { x: 0, y: 0 },
21
+ pointerFinger: { x: 0.35, y: 0 },
22
+ // Crosshair at center
23
+ crosshair: { x: 0.5, y: 0.5 },
24
+ // Move cursor at center
25
+ move: { x: 0.5, y: 0.5 },
26
+ // Resize cursors at center
27
+ resize: { x: 0.5, y: 0.5 },
28
+ // Text cursor at center-bottom
29
+ text: { x: 0.5, y: 0.9 },
30
+ // Grab/grabbing at palm center
31
+ grab: { x: 0.5, y: 0.4 },
32
+ // Drawing tools at tool tip
33
+ pen: { x: 0.1, y: 0.9 },
34
+ brush: { x: 0.15, y: 0.85 },
35
+ eraser: { x: 0.15, y: 0.85 },
36
+ eyedropper: { x: 0.05, y: 0.95 },
37
+ bucket: { x: 0.1, y: 0.85 },
38
+ // Zoom at center of glass
39
+ zoom: { x: 0.35, y: 0.35 },
40
+ // Pan at center
41
+ pan: { x: 0.5, y: 0.5 },
42
+ // Default fallback
43
+ default: { x: 0, y: 0 }
44
+ };
45
+ function getDefaultHotspot(iconName) {
46
+ const name = iconName.toLowerCase();
47
+ if (name.includes("pointer") || name.includes("finger")) {
48
+ return name.includes("finger") ? DEFAULT_HOTSPOTS.pointerFinger : DEFAULT_HOTSPOTS.pointer;
49
+ }
50
+ if (name.includes("crosshair")) {
51
+ return DEFAULT_HOTSPOTS.crosshair;
52
+ }
53
+ if (name.includes("move")) {
54
+ return DEFAULT_HOTSPOTS.move;
55
+ }
56
+ if (name.includes("resize")) {
57
+ return DEFAULT_HOTSPOTS.resize;
58
+ }
59
+ if (name.includes("text") || name.includes("cursor")) {
60
+ return DEFAULT_HOTSPOTS.text;
61
+ }
62
+ if (name.includes("grab")) {
63
+ return DEFAULT_HOTSPOTS.grab;
64
+ }
65
+ if (name.includes("pen") || name.includes("line")) {
66
+ return DEFAULT_HOTSPOTS.pen;
67
+ }
68
+ if (name.includes("brush") || name.includes("draw")) {
69
+ return DEFAULT_HOTSPOTS.brush;
70
+ }
71
+ if (name.includes("eraser")) {
72
+ return DEFAULT_HOTSPOTS.eraser;
73
+ }
74
+ if (name.includes("eyedropper") || name.includes("picker")) {
75
+ return DEFAULT_HOTSPOTS.eyedropper;
76
+ }
77
+ if (name.includes("bucket") || name.includes("fill")) {
78
+ return DEFAULT_HOTSPOTS.bucket;
79
+ }
80
+ if (name.includes("zoom")) {
81
+ return DEFAULT_HOTSPOTS.zoom;
82
+ }
83
+ if (name.includes("pan")) {
84
+ return DEFAULT_HOTSPOTS.pan;
85
+ }
86
+ return DEFAULT_HOTSPOTS.default;
87
+ }
88
+ function buildCursor(IconComponent, options = {}) {
89
+ const {
90
+ size = 32,
91
+ color = "#000",
92
+ secondaryColor,
93
+ hotspot,
94
+ fallback = "auto",
95
+ variant = "filled"
96
+ } = options;
97
+ const renderToMarkup = getRenderer();
98
+ const element = React.createElement(IconComponent, {
99
+ size,
100
+ color,
101
+ secondaryColor,
102
+ variant
103
+ });
104
+ const svgMarkup = renderToMarkup(element);
105
+ const base64 = typeof btoa === "function" ? btoa(unescape(encodeURIComponent(svgMarkup))) : Buffer.from(svgMarkup, "utf8").toString("base64");
106
+ const dataUri = `data:image/svg+xml;base64,${base64}`;
107
+ const componentName = IconComponent.displayName || IconComponent.name || "default";
108
+ const normalizedHotspot = hotspot || getDefaultHotspot(componentName);
109
+ const actualHotspot = {
110
+ x: Math.round(normalizedHotspot.x * size),
111
+ y: Math.round(normalizedHotspot.y * size)
112
+ };
113
+ if (hotspot && (hotspot.x > 1 || hotspot.y > 1)) {
114
+ actualHotspot.x = Math.round(hotspot.x);
115
+ actualHotspot.y = Math.round(hotspot.y);
116
+ }
117
+ const cursor = `url(${dataUri}) ${actualHotspot.x} ${actualHotspot.y}, ${fallback}`;
118
+ return {
119
+ cursor,
120
+ dataUri,
121
+ hotspot: actualHotspot,
122
+ size
123
+ };
124
+ }
125
+ function createCursorBuilder(IconComponent) {
126
+ return (options) => buildCursor(IconComponent, options);
127
+ }
128
+ function buildCursors(icons, sharedOptions = {}) {
129
+ const result = {};
130
+ for (const [name, IconComponent] of Object.entries(icons)) {
131
+ result[name] = buildCursor(IconComponent, sharedOptions).cursor;
132
+ }
133
+ return result;
134
+ }
135
+ function generateCursorCSS(icons, options = {}, prefix = "--cursor") {
136
+ const cursors = buildCursors(icons, options);
137
+ const properties = Object.entries(cursors).map(([name, value]) => ` ${prefix}-${name}: ${value};`).join("\n");
138
+ return `:root {
139
+ ${properties}
140
+ }`;
141
+ }
142
+ function useCursor(IconComponent, options = {}) {
143
+ var _a, _b;
144
+ const cursor = React.useMemo(() => {
145
+ if (!IconComponent) {
146
+ return "auto";
147
+ }
148
+ return buildCursor(IconComponent, options).cursor;
149
+ }, [
150
+ IconComponent,
151
+ options.size,
152
+ options.color,
153
+ (_a = options.hotspot) == null ? void 0 : _a.x,
154
+ (_b = options.hotspot) == null ? void 0 : _b.y,
155
+ options.fallback,
156
+ options.variant,
157
+ options.secondaryColor
158
+ ]);
159
+ return { cursor };
160
+ }
161
+ function useCursors(cursors, options = {}) {
162
+ const cursorMap = React.useMemo(
163
+ () => buildCursors(cursors, options),
164
+ [cursors, options.size, options.color, options.variant]
165
+ );
166
+ const [activeCursor, setActiveCursor] = React.useState(null);
167
+ const style = React.useMemo(
168
+ () => ({
169
+ cursor: activeCursor ? cursorMap[activeCursor] : "auto"
170
+ }),
171
+ [activeCursor, cursorMap]
172
+ );
173
+ return [style, setActiveCursor, cursorMap];
174
+ }
175
+ function createCursorTheme(theme, options = {}) {
176
+ const result = {};
177
+ for (const [key, IconComponent] of Object.entries(theme)) {
178
+ if (IconComponent) {
179
+ result[key] = buildCursor(IconComponent, options).cursor;
180
+ }
181
+ }
182
+ return result;
183
+ }
184
+ function applyCursorTheme(theme, prefix = "--cursor") {
185
+ if (typeof document === "undefined") {
186
+ return;
187
+ }
188
+ const root = document.documentElement;
189
+ for (const [name, value] of Object.entries(theme)) {
190
+ root.style.setProperty(`${prefix}-${name}`, value);
191
+ }
192
+ }
193
+ const allCursorIcons = {
194
+ ...pointers.pointerIcons,
195
+ ...selection.selectionIcons,
196
+ ...tools.toolIcons,
197
+ ...status.statusIcons
198
+ };
199
+ const CURSOR_ICON_COUNTS = {
200
+ pointers: 15,
201
+ selection: 15,
202
+ tools: 15,
203
+ status: 15,
204
+ total: 60
205
+ };
206
+ exports.createCursorIcon = createCursorIcon.createCursorIcon;
207
+ exports.getCursorAnimation = createCursorIcon.getCursorAnimation;
208
+ exports.Crosshair = pointers.Crosshair;
209
+ exports.Move = pointers.Move;
210
+ exports.Pointer = pointers.Pointer;
211
+ exports.PointerFinger = pointers.PointerFinger;
212
+ exports.ResizeAll = pointers.ResizeAll;
213
+ exports.ResizeE = pointers.ResizeE;
214
+ exports.ResizeHorizontal = pointers.ResizeHorizontal;
215
+ exports.ResizeN = pointers.ResizeN;
216
+ exports.ResizeNE = pointers.ResizeNE;
217
+ exports.ResizeNW = pointers.ResizeNW;
218
+ exports.ResizeS = pointers.ResizeS;
219
+ exports.ResizeSE = pointers.ResizeSE;
220
+ exports.ResizeSW = pointers.ResizeSW;
221
+ exports.ResizeVertical = pointers.ResizeVertical;
222
+ exports.ResizeW = pointers.ResizeW;
223
+ exports.pointerIcons = pointers.pointerIcons;
224
+ exports.pointers = pointers.pointers;
225
+ exports.CellSelection = selection.CellSelection;
226
+ exports.ColumnSelect = selection.ColumnSelect;
227
+ exports.Deselect = selection.Deselect;
228
+ exports.Drag = selection.Drag;
229
+ exports.DragHandle = selection.DragHandle;
230
+ exports.Grab = selection.Grab;
231
+ exports.Grabbing = selection.Grabbing;
232
+ exports.InvertSelection = selection.InvertSelection;
233
+ exports.Lasso = selection.Lasso;
234
+ exports.MagicWand = selection.MagicWand;
235
+ exports.RangeSelect = selection.RangeSelect;
236
+ exports.RowSelect = selection.RowSelect;
237
+ exports.SelectAll = selection.SelectAll;
238
+ exports.TextCursor = selection.TextCursor;
239
+ exports.TextSelect = selection.TextSelect;
240
+ exports.selection = selection.selection;
241
+ exports.selectionIcons = selection.selectionIcons;
242
+ exports.Alias = status.Alias;
243
+ exports.Auto = status.Auto;
244
+ exports.Busy = status.Busy;
245
+ exports.ContextMenu = status.ContextMenu;
246
+ exports.Copy = status.Copy;
247
+ exports.Default = status.Default;
248
+ exports.Forbidden = status.Forbidden;
249
+ exports.Help = status.Help;
250
+ exports.Inherit = status.Inherit;
251
+ exports.Loading = status.Loading;
252
+ exports.NoDrop = status.NoDrop;
253
+ exports.None = status.None;
254
+ exports.NotAllowed = status.NotAllowed;
255
+ exports.Progress = status.Progress;
256
+ exports.Wait = status.Wait;
257
+ exports.status = status.status;
258
+ exports.statusIcons = status.statusIcons;
259
+ exports.Brush = tools.Brush;
260
+ exports.Bucket = tools.Bucket;
261
+ exports.Crop = tools.Crop;
262
+ exports.Draw = tools.Draw;
263
+ exports.Ellipse = tools.Ellipse;
264
+ exports.Eraser = tools.Eraser;
265
+ exports.Eyedropper = tools.Eyedropper;
266
+ exports.Line = tools.Line;
267
+ exports.Pan = tools.Pan;
268
+ exports.Pen = tools.Pen;
269
+ exports.Polygon = tools.Polygon;
270
+ exports.Rectangle = tools.Rectangle;
271
+ exports.Rotate = tools.Rotate;
272
+ exports.ZoomIn = tools.ZoomIn;
273
+ exports.ZoomOut = tools.ZoomOut;
274
+ exports.toolIcons = tools.toolIcons;
275
+ exports.tools = tools.tools;
276
+ exports.CURSOR_ICON_COUNTS = CURSOR_ICON_COUNTS;
277
+ exports.DEFAULT_HOTSPOTS = DEFAULT_HOTSPOTS;
278
+ exports.allCursorIcons = allCursorIcons;
279
+ exports.applyCursorTheme = applyCursorTheme;
280
+ exports.buildCursor = buildCursor;
281
+ exports.buildCursors = buildCursors;
282
+ exports.createCursorBuilder = createCursorBuilder;
283
+ exports.createCursorTheme = createCursorTheme;
284
+ exports.generateCursorCSS = generateCursorCSS;
285
+ exports.getDefaultHotspot = getDefaultHotspot;
286
+ exports.useCursor = useCursor;
287
+ exports.useCursors = useCursors;
288
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/cursorBuilder.tsx","../src/index.ts"],"sourcesContent":["/**\r\n * @file cursorBuilder.tsx\r\n * @description Utilities to convert cursor icons to CSS cursor values\r\n *\r\n * This module provides functions to transform SVG cursor icons into\r\n * usable CSS cursor definitions with customizable hotspots.\r\n */\r\n\r\nimport { createElement, useMemo, useState } from 'react';\r\nimport type { CSSProperties, FC, ReactNode } from 'react';\r\n\r\nimport type { CursorIcon, CursorIconProps } from './types';\r\n\r\n// Type for renderToStaticMarkup function\r\ntype RenderFn = (element: ReactNode) => string;\r\n\r\n// Lazy loaded renderer\r\nlet cachedRenderer: RenderFn | null = null;\r\n\r\n/**\r\n * Get the react-dom/server renderer.\r\n * Uses dynamic require for compatibility with bundlers.\r\n */\r\nfunction getRenderer(): RenderFn {\r\n if (cachedRenderer) {\r\n return cachedRenderer;\r\n }\r\n\r\n // Dynamic import at runtime\r\n // eslint-disable-next-line @typescript-eslint/no-require-imports\r\n const reactDomServer = require('react-dom/server') as { renderToStaticMarkup: RenderFn };\r\n cachedRenderer = reactDomServer.renderToStaticMarkup;\r\n return cachedRenderer;\r\n}\r\n\r\n/* ─── Types ─── */\r\n\r\n/**\r\n * Cursor hotspot position (where the click is registered)\r\n */\r\nexport interface CursorHotspot {\r\n /** X coordinate of hotspot (0-based, measured from left) */\r\n x: number;\r\n /** Y coordinate of hotspot (0-based, measured from top) */\r\n y: number;\r\n}\r\n\r\n/**\r\n * Options for building a CSS cursor\r\n */\r\nexport interface CursorBuilderOptions {\r\n /** Icon size in pixels (default: 32) */\r\n size?: number;\r\n /** Icon color (default: #000) */\r\n color?: string;\r\n /** Secondary color for duotone variant */\r\n secondaryColor?: string;\r\n /** Hotspot position (default: { x: 0, y: 0 }) */\r\n hotspot?: CursorHotspot;\r\n /** Fallback CSS cursor value (default: 'auto') */\r\n fallback?: string;\r\n /** Icon variant */\r\n variant?: CursorIconProps['variant'];\r\n}\r\n\r\n/**\r\n * Result from building a cursor\r\n */\r\nexport interface CursorBuilderResult {\r\n /** The CSS cursor value (data URI + fallback) */\r\n cursor: string;\r\n /** The data URI only */\r\n dataUri: string;\r\n /** The hotspot used */\r\n hotspot: CursorHotspot;\r\n /** The size used */\r\n size: number;\r\n}\r\n\r\n/* ─── Default Hotspots ─── */\r\n\r\n/**\r\n * Default hotspot positions for common cursor types.\r\n * Values are normalized (0-1), will be multiplied by size.\r\n */\r\nexport const DEFAULT_HOTSPOTS: Record<string, CursorHotspot> = {\r\n // Pointer at tip (top-left)\r\n pointer: { x: 0, y: 0 },\r\n pointerFinger: { x: 0.35, y: 0 },\r\n\r\n // Crosshair at center\r\n crosshair: { x: 0.5, y: 0.5 },\r\n\r\n // Move cursor at center\r\n move: { x: 0.5, y: 0.5 },\r\n\r\n // Resize cursors at center\r\n resize: { x: 0.5, y: 0.5 },\r\n\r\n // Text cursor at center-bottom\r\n text: { x: 0.5, y: 0.9 },\r\n\r\n // Grab/grabbing at palm center\r\n grab: { x: 0.5, y: 0.4 },\r\n\r\n // Drawing tools at tool tip\r\n pen: { x: 0.1, y: 0.9 },\r\n brush: { x: 0.15, y: 0.85 },\r\n eraser: { x: 0.15, y: 0.85 },\r\n eyedropper: { x: 0.05, y: 0.95 },\r\n bucket: { x: 0.1, y: 0.85 },\r\n\r\n // Zoom at center of glass\r\n zoom: { x: 0.35, y: 0.35 },\r\n\r\n // Pan at center\r\n pan: { x: 0.5, y: 0.5 },\r\n\r\n // Default fallback\r\n default: { x: 0, y: 0 },\r\n};\r\n\r\n/**\r\n * Get normalized hotspot for an icon by name\r\n */\r\nexport function getDefaultHotspot(iconName: string): CursorHotspot {\r\n const name = iconName.toLowerCase();\r\n\r\n if (name.includes('pointer') || name.includes('finger')) {\r\n return name.includes('finger') ? DEFAULT_HOTSPOTS.pointerFinger : DEFAULT_HOTSPOTS.pointer;\r\n }\r\n if (name.includes('crosshair')) {\r\n return DEFAULT_HOTSPOTS.crosshair;\r\n }\r\n if (name.includes('move')) {\r\n return DEFAULT_HOTSPOTS.move;\r\n }\r\n if (name.includes('resize')) {\r\n return DEFAULT_HOTSPOTS.resize;\r\n }\r\n if (name.includes('text') || name.includes('cursor')) {\r\n return DEFAULT_HOTSPOTS.text;\r\n }\r\n if (name.includes('grab')) {\r\n return DEFAULT_HOTSPOTS.grab;\r\n }\r\n if (name.includes('pen') || name.includes('line')) {\r\n return DEFAULT_HOTSPOTS.pen;\r\n }\r\n if (name.includes('brush') || name.includes('draw')) {\r\n return DEFAULT_HOTSPOTS.brush;\r\n }\r\n if (name.includes('eraser')) {\r\n return DEFAULT_HOTSPOTS.eraser;\r\n }\r\n if (name.includes('eyedropper') || name.includes('picker')) {\r\n return DEFAULT_HOTSPOTS.eyedropper;\r\n }\r\n if (name.includes('bucket') || name.includes('fill')) {\r\n return DEFAULT_HOTSPOTS.bucket;\r\n }\r\n if (name.includes('zoom')) {\r\n return DEFAULT_HOTSPOTS.zoom;\r\n }\r\n if (name.includes('pan')) {\r\n return DEFAULT_HOTSPOTS.pan;\r\n }\r\n\r\n return DEFAULT_HOTSPOTS.default;\r\n}\r\n\r\n/* ─── Core Builder Function ─── */\r\n\r\n/**\r\n * Convert an SVG cursor icon to a CSS cursor value.\r\n *\r\n * @param IconComponent - The cursor icon React component\r\n * @param options - Cursor building options\r\n * @returns CSS cursor value with data URI and fallback\r\n *\r\n * @example\r\n * ```tsx\r\n * import { Pointer, buildCursor } from '@nice2dev/icons-cursor';\r\n *\r\n * const { cursor } = buildCursor(Pointer, {\r\n * size: 32,\r\n * color: '#333',\r\n * hotspot: { x: 0, y: 0 }\r\n * });\r\n *\r\n * // Use in styles\r\n * <div style={{ cursor }} />\r\n * ```\r\n */\r\nexport function buildCursor(\r\n IconComponent: CursorIcon,\r\n options: CursorBuilderOptions = {},\r\n): CursorBuilderResult {\r\n const {\r\n size = 32,\r\n color = '#000',\r\n secondaryColor,\r\n hotspot,\r\n fallback = 'auto',\r\n variant = 'filled',\r\n } = options;\r\n\r\n // Render the icon to static SVG markup\r\n const renderToMarkup = getRenderer();\r\n const element = createElement(IconComponent, {\r\n size,\r\n color,\r\n secondaryColor,\r\n variant,\r\n });\r\n const svgMarkup = renderToMarkup(element);\r\n\r\n // Convert to data URI (use base64 for better compatibility)\r\n const base64 =\r\n typeof btoa === 'function'\r\n ? btoa(unescape(encodeURIComponent(svgMarkup)))\r\n : Buffer.from(svgMarkup, 'utf8').toString('base64');\r\n\r\n const dataUri = `data:image/svg+xml;base64,${base64}`;\r\n\r\n // Calculate hotspot (use default based on component name if not provided)\r\n const componentName =\r\n (IconComponent as FC & { displayName?: string }).displayName || IconComponent.name || 'default';\r\n const normalizedHotspot = hotspot || getDefaultHotspot(componentName);\r\n const actualHotspot: CursorHotspot = {\r\n x: Math.round(normalizedHotspot.x * size),\r\n y: Math.round(normalizedHotspot.y * size),\r\n };\r\n\r\n // If hotspot was provided without normalization (values > 1), use as-is\r\n if (hotspot && (hotspot.x > 1 || hotspot.y > 1)) {\r\n actualHotspot.x = Math.round(hotspot.x);\r\n actualHotspot.y = Math.round(hotspot.y);\r\n }\r\n\r\n // Build the CSS cursor value\r\n const cursor = `url(${dataUri}) ${actualHotspot.x} ${actualHotspot.y}, ${fallback}`;\r\n\r\n return {\r\n cursor,\r\n dataUri,\r\n hotspot: actualHotspot,\r\n size,\r\n };\r\n}\r\n\r\n/**\r\n * Create a pre-configured cursor builder for a specific icon.\r\n *\r\n * @param IconComponent - The cursor icon React component\r\n * @returns Function that takes options and returns cursor CSS\r\n *\r\n * @example\r\n * ```tsx\r\n * const penCursor = createCursorBuilder(Pen);\r\n *\r\n * // Later use with different options\r\n * const cursor1 = penCursor({ color: 'red' });\r\n * const cursor2 = penCursor({ color: 'blue', size: 48 });\r\n * ```\r\n */\r\nexport function createCursorBuilder(\r\n IconComponent: CursorIcon,\r\n): (options?: CursorBuilderOptions) => CursorBuilderResult {\r\n return (options?: CursorBuilderOptions) => buildCursor(IconComponent, options);\r\n}\r\n\r\n/* ─── Batch Builder ─── */\r\n\r\n/**\r\n * Build multiple cursors at once with shared options.\r\n *\r\n * @param icons - Map of cursor names to icon components\r\n * @param sharedOptions - Options applied to all cursors\r\n * @returns Map of cursor names to their CSS values\r\n *\r\n * @example\r\n * ```tsx\r\n * const cursors = buildCursors({\r\n * pointer: Pointer,\r\n * pen: Pen,\r\n * eraser: Eraser,\r\n * }, { size: 24, color: '#333' });\r\n *\r\n * // cursors.pointer => \"url(data:...) 0 0, auto\"\r\n * // cursors.pen => \"url(data:...) 2 22, auto\"\r\n * ```\r\n */\r\nexport function buildCursors<T extends Record<string, CursorIcon>>(\r\n icons: T,\r\n sharedOptions: CursorBuilderOptions = {},\r\n): Record<keyof T, string> {\r\n const result = {} as Record<keyof T, string>;\r\n\r\n for (const [name, IconComponent] of Object.entries(icons)) {\r\n result[name as keyof T] = buildCursor(IconComponent, sharedOptions).cursor;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/* ─── CSS Custom Property Generator ─── */\r\n\r\n/**\r\n * Generate CSS custom properties for cursor icons.\r\n * Useful for defining cursors once and using them via CSS variables.\r\n *\r\n * @param icons - Map of cursor names to icon components\r\n * @param options - Cursor building options\r\n * @param prefix - CSS variable prefix (default: '--cursor')\r\n * @returns CSS string with custom property definitions\r\n *\r\n * @example\r\n * ```tsx\r\n * const css = generateCursorCSS({\r\n * pointer: Pointer,\r\n * pen: Pen,\r\n * });\r\n *\r\n * // Returns:\r\n * // :root {\r\n * // --cursor-pointer: url(data:...) 0 0, auto;\r\n * // --cursor-pen: url(data:...) 2 22, auto;\r\n * // }\r\n * ```\r\n */\r\nexport function generateCursorCSS<T extends Record<string, CursorIcon>>(\r\n icons: T,\r\n options: CursorBuilderOptions = {},\r\n prefix = '--cursor',\r\n): string {\r\n const cursors = buildCursors(icons, options);\r\n const properties = Object.entries(cursors)\r\n .map(([name, value]) => ` ${prefix}-${name}: ${value};`)\r\n .join('\\n');\r\n\r\n return `:root {\\n${properties}\\n}`;\r\n}\r\n\r\n/* ─── React Hook ─── */\r\n\r\n/**\r\n * Hook to apply a custom cursor to an element.\r\n * Returns style object and handlers for dynamic cursor changes.\r\n *\r\n * @param IconComponent - The cursor icon component\r\n * @param options - Cursor building options\r\n * @returns Style object with cursor property\r\n *\r\n * @example\r\n * ```tsx\r\n * function Canvas() {\r\n * const cursorStyle = useCursor(Pen, { color: 'blue' });\r\n *\r\n * return <div style={cursorStyle}>Draw here</div>;\r\n * }\r\n * ```\r\n */\r\nexport function useCursor(\r\n IconComponent: CursorIcon | null,\r\n options: CursorBuilderOptions = {},\r\n): CSSProperties {\r\n const cursor = useMemo(() => {\r\n if (!IconComponent) {\r\n return 'auto';\r\n }\r\n return buildCursor(IconComponent, options).cursor;\r\n }, [\r\n IconComponent,\r\n options.size,\r\n options.color,\r\n options.hotspot?.x,\r\n options.hotspot?.y,\r\n options.fallback,\r\n options.variant,\r\n options.secondaryColor,\r\n ]);\r\n\r\n return { cursor };\r\n}\r\n\r\n/**\r\n * Hook to manage multiple cursors with easy switching.\r\n *\r\n * @param cursors - Map of cursor names to icon components\r\n * @param options - Shared cursor building options\r\n * @returns Tuple of [currentStyle, setCursor, cursorMap]\r\n *\r\n * @example\r\n * ```tsx\r\n * function Editor() {\r\n * const [style, setCursor, cursors] = useCursors({\r\n * pointer: Pointer,\r\n * pen: Pen,\r\n * eraser: Eraser,\r\n * });\r\n *\r\n * return (\r\n * <div style={style}>\r\n * <button onClick={() => setCursor('pen')}>Pen</button>\r\n * <button onClick={() => setCursor('eraser')}>Eraser</button>\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport function useCursors<T extends Record<string, CursorIcon>>(\r\n cursors: T,\r\n options: CursorBuilderOptions = {},\r\n): [CSSProperties, (name: keyof T | null) => void, Record<keyof T, string>] {\r\n const cursorMap = useMemo(\r\n () => buildCursors(cursors, options),\r\n [cursors, options.size, options.color, options.variant],\r\n );\r\n\r\n const [activeCursor, setActiveCursor] = useState<keyof T | null>(null);\r\n\r\n const style = useMemo(\r\n (): CSSProperties => ({\r\n cursor: activeCursor ? cursorMap[activeCursor] : 'auto',\r\n }),\r\n [activeCursor, cursorMap],\r\n );\r\n\r\n return [style, setActiveCursor, cursorMap];\r\n}\r\n\r\n/* ─── Prebuilt Cursor Sets ─── */\r\n\r\n/**\r\n * Configuration for a complete cursor theme\r\n */\r\nexport interface CursorTheme {\r\n default: string;\r\n pointer: string;\r\n text: string;\r\n wait: string;\r\n help: string;\r\n notAllowed: string;\r\n grab: string;\r\n grabbing: string;\r\n crosshair: string;\r\n move: string;\r\n resizeN: string;\r\n resizeS: string;\r\n resizeE: string;\r\n resizeW: string;\r\n resizeNE: string;\r\n resizeNW: string;\r\n resizeSE: string;\r\n resizeSW: string;\r\n resizeHorizontal: string;\r\n resizeVertical: string;\r\n}\r\n\r\n/**\r\n * Create a complete cursor theme from cursor icons.\r\n *\r\n * @param theme - Map of cursor type to icon component\r\n * @param options - Shared building options\r\n * @returns Complete cursor theme object\r\n *\r\n * @example\r\n * ```tsx\r\n * import * as cursors from '@nice2dev/icons-cursor';\r\n *\r\n * const theme = createCursorTheme({\r\n * default: cursors.Pointer,\r\n * pointer: cursors.PointerFinger,\r\n * text: cursors.TextCursor,\r\n * // ...\r\n * }, { size: 24 });\r\n *\r\n * // Apply to CSS\r\n * document.body.style.cursor = theme.default;\r\n * ```\r\n */\r\nexport function createCursorTheme(\r\n theme: Partial<Record<keyof CursorTheme, CursorIcon>>,\r\n options: CursorBuilderOptions = {},\r\n): Partial<CursorTheme> {\r\n const result: Partial<CursorTheme> = {};\r\n\r\n for (const [key, IconComponent] of Object.entries(theme)) {\r\n if (IconComponent) {\r\n result[key as keyof CursorTheme] = buildCursor(IconComponent, options).cursor;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/* ─── Utility: Apply Theme to Document ─── */\r\n\r\n/**\r\n * Apply a cursor theme to the document's CSS custom properties.\r\n * This allows using the cursors via CSS: `cursor: var(--cursor-pointer)`\r\n *\r\n * @param theme - Cursor theme to apply\r\n * @param prefix - CSS variable prefix (default: '--cursor')\r\n *\r\n * @example\r\n * ```tsx\r\n * const theme = createCursorTheme({ ... });\r\n * applyCursorTheme(theme);\r\n *\r\n * // In CSS:\r\n * // .button:hover { cursor: var(--cursor-pointer); }\r\n * ```\r\n */\r\nexport function applyCursorTheme(theme: Partial<CursorTheme>, prefix = '--cursor'): void {\r\n if (typeof document === 'undefined') {\r\n return;\r\n }\r\n\r\n const root = document.documentElement;\r\n\r\n for (const [name, value] of Object.entries(theme)) {\r\n root.style.setProperty(`${prefix}-${name}`, value);\r\n }\r\n}\r\n","/**\r\n * @nice2dev/icons-cursor\r\n * Cursor and pointer icons for NiceToDev UI\r\n *\r\n * Provides 60 cursor-related icons organized into 4 categories:\r\n * - Pointers: Basic cursor shapes and resize handles (15 icons)\r\n * - Selection: Text/cell selection and drag cursors (15 icons)\r\n * - Tools: Drawing and editing tool cursors (15 icons)\r\n * - Status: System state indicators (15 icons)\r\n *\r\n * @packageDocumentation\r\n */\r\n\r\n// Export types\r\nexport type {\r\n CursorIconProps,\r\n CursorIconAnimation,\r\n CursorIconVariant,\r\n CursorIcon,\r\n CursorIconName,\r\n PointerIconName,\r\n SelectionIconName,\r\n ToolIconName,\r\n StatusIconName,\r\n} from './types';\r\n\r\n// Export factory and utilities\r\nexport { createCursorIcon, getCursorAnimation } from './createCursorIcon';\r\n\r\n// Export cursor builder utilities\r\nexport {\r\n buildCursor,\r\n buildCursors,\r\n createCursorBuilder,\r\n generateCursorCSS,\r\n useCursor,\r\n useCursors,\r\n createCursorTheme,\r\n applyCursorTheme,\r\n getDefaultHotspot,\r\n DEFAULT_HOTSPOTS,\r\n} from './cursorBuilder';\r\n\r\nexport type {\r\n CursorHotspot,\r\n CursorBuilderOptions,\r\n CursorBuilderResult,\r\n CursorTheme,\r\n} from './cursorBuilder';\r\n\r\n// Export all icons by category with namespaces\r\nimport * as pointers from './pointers';\r\nimport * as selection from './selection';\r\nimport * as status from './status';\r\nimport * as tools from './tools';\r\n\r\nexport { pointers, selection, tools, status };\r\n\r\n// Re-export individual icons from each category\r\nexport {\r\n Pointer,\r\n PointerFinger,\r\n Crosshair,\r\n Move,\r\n ResizeN,\r\n ResizeS,\r\n ResizeE,\r\n ResizeW,\r\n ResizeNE,\r\n ResizeNW,\r\n ResizeSE,\r\n ResizeSW,\r\n ResizeHorizontal,\r\n ResizeVertical,\r\n ResizeAll,\r\n pointerIcons,\r\n} from './pointers';\r\n\r\nexport {\r\n TextCursor,\r\n TextSelect,\r\n CellSelection,\r\n ColumnSelect,\r\n RowSelect,\r\n RangeSelect,\r\n Grab,\r\n Grabbing,\r\n Drag,\r\n DragHandle,\r\n Lasso,\r\n MagicWand,\r\n SelectAll,\r\n Deselect,\r\n InvertSelection,\r\n selectionIcons,\r\n} from './selection';\r\n\r\nexport {\r\n ZoomIn,\r\n ZoomOut,\r\n Rotate,\r\n Pan,\r\n Draw,\r\n Brush,\r\n Eraser,\r\n Eyedropper,\r\n Bucket,\r\n Pen,\r\n Line,\r\n Rectangle,\r\n Ellipse,\r\n Polygon,\r\n Crop,\r\n toolIcons,\r\n} from './tools';\r\n\r\nexport {\r\n Wait,\r\n Progress,\r\n Forbidden,\r\n NotAllowed,\r\n Help,\r\n ContextMenu,\r\n Alias,\r\n Copy,\r\n NoDrop,\r\n Loading,\r\n Busy,\r\n Default,\r\n Auto,\r\n None,\r\n Inherit,\r\n statusIcons,\r\n} from './status';\r\n\r\n/**\r\n * All cursor icons in a single object\r\n */\r\nexport const allCursorIcons = {\r\n ...pointers.pointerIcons,\r\n ...selection.selectionIcons,\r\n ...tools.toolIcons,\r\n ...status.statusIcons,\r\n} as const;\r\n\r\n/**\r\n * Icon count by category\r\n */\r\nexport const CURSOR_ICON_COUNTS = {\r\n pointers: 15,\r\n selection: 15,\r\n tools: 15,\r\n status: 15,\r\n total: 60,\r\n} as const;\r\n"],"names":["createElement","useMemo","useState","pointers.pointerIcons","selection.selectionIcons","tools.toolIcons","status.statusIcons"],"mappings":"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"}