@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.
- package/README.md +241 -0
- package/dist/createCursorIcon-CCO9eeBk.mjs +170 -0
- package/dist/createCursorIcon-CCO9eeBk.mjs.map +1 -0
- package/dist/createCursorIcon-Crwdo_Qk.js +169 -0
- package/dist/createCursorIcon-Crwdo_Qk.js.map +1 -0
- package/dist/createCursorIcon.d.ts +11 -0
- package/dist/createCursorIcon.d.ts.map +1 -0
- package/dist/cursorBuilder.d.ts +242 -0
- package/dist/cursorBuilder.d.ts.map +1 -0
- package/dist/index.cjs +288 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +292 -0
- package/dist/index.mjs.map +1 -0
- package/dist/pointers-DW_cbtGT.mjs +90 -0
- package/dist/pointers-DW_cbtGT.mjs.map +1 -0
- package/dist/pointers-DxPqgPxN.js +89 -0
- package/dist/pointers-DxPqgPxN.js.map +1 -0
- package/dist/pointers.cjs +21 -0
- package/dist/pointers.cjs.map +1 -0
- package/dist/pointers.d.ts +36 -0
- package/dist/pointers.d.ts.map +1 -0
- package/dist/pointers.mjs +21 -0
- package/dist/pointers.mjs.map +1 -0
- package/dist/selection-CINU3bsI.js +101 -0
- package/dist/selection-CINU3bsI.js.map +1 -0
- package/dist/selection-W-1ZhqSv.mjs +102 -0
- package/dist/selection-W-1ZhqSv.mjs.map +1 -0
- package/dist/selection.cjs +21 -0
- package/dist/selection.cjs.map +1 -0
- package/dist/selection.d.ts +36 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.mjs +21 -0
- package/dist/selection.mjs.map +1 -0
- package/dist/status-BBrDqBw_.mjs +111 -0
- package/dist/status-BBrDqBw_.mjs.map +1 -0
- package/dist/status-L6N47QMq.js +110 -0
- package/dist/status-L6N47QMq.js.map +1 -0
- package/dist/status.cjs +21 -0
- package/dist/status.cjs.map +1 -0
- package/dist/status.d.ts +36 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.mjs +21 -0
- package/dist/status.mjs.map +1 -0
- package/dist/tools-DbPCbk54.mjs +108 -0
- package/dist/tools-DbPCbk54.mjs.map +1 -0
- package/dist/tools-ttgDzC_5.js +107 -0
- package/dist/tools-ttgDzC_5.js.map +1 -0
- package/dist/tools.cjs +21 -0
- package/dist/tools.cjs.map +1 -0
- package/dist/tools.d.ts +36 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.mjs +21 -0
- package/dist/tools.mjs.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- 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":"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"}
|
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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"}
|