@nice2dev/icons 1.3.13 → 1.3.14

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.
@@ -1,454 +0,0 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { useRef, useMemo, useCallback, useState } from 'react';
3
-
4
- /* ══════════════════════════════════════════════════════════════════════════════
5
- Constants
6
- ══════════════════════════════════════════════════════════════════════════════ */
7
- const DEFAULT_COLORS = [
8
- '#000000',
9
- '#ffffff',
10
- '#ef4444',
11
- '#f97316',
12
- '#eab308',
13
- '#22c55e',
14
- '#14b8a6',
15
- '#3b82f6',
16
- '#8b5cf6',
17
- '#ec4899',
18
- '#6b7280',
19
- '#0ea5e9',
20
- ];
21
- const DEFAULT_SIZES = [16, 20, 24, 32, 48, 64, 96, 128, 256];
22
- const BADGE_POSITIONS = [
23
- { value: 'top-right', label: 'Top Right' },
24
- { value: 'top-left', label: 'Top Left' },
25
- { value: 'bottom-right', label: 'Bottom Right' },
26
- { value: 'bottom-left', label: 'Bottom Left' },
27
- ];
28
- const DEFAULT_STATE = {
29
- fill: 'currentColor',
30
- stroke: 'none',
31
- strokeWidth: 0,
32
- size: 64,
33
- rotation: 0,
34
- flipX: false,
35
- flipY: false,
36
- opacity: 1,
37
- };
38
- /* ══════════════════════════════════════════════════════════════════════════════
39
- Utility Functions
40
- ══════════════════════════════════════════════════════════════════════════════ */
41
- /**
42
- * Gets badge position coordinates.
43
- */
44
- function getBadgeOffset(position, containerSize, badgeSize) {
45
- const offset = badgeSize * 0.25;
46
- switch (position) {
47
- case 'top-right':
48
- return { x: containerSize - badgeSize + offset, y: -offset };
49
- case 'top-left':
50
- return { x: -offset, y: -offset };
51
- case 'bottom-right':
52
- return { x: containerSize - badgeSize + offset, y: containerSize - badgeSize + offset };
53
- case 'bottom-left':
54
- return { x: -offset, y: containerSize - badgeSize + offset };
55
- }
56
- }
57
- /**
58
- * Converts SVG to PNG data URL.
59
- */
60
- async function svgToPng(svgElement, size, backgroundColor) {
61
- return new Promise((resolve, reject) => {
62
- const canvas = document.createElement('canvas');
63
- canvas.width = size;
64
- canvas.height = size;
65
- const ctx = canvas.getContext('2d');
66
- if (!ctx) {
67
- reject(new Error('Failed to get canvas context'));
68
- return;
69
- }
70
- // Background
71
- if (backgroundColor) {
72
- ctx.fillStyle = backgroundColor;
73
- ctx.fillRect(0, 0, size, size);
74
- }
75
- // SVG to image
76
- const svgData = new XMLSerializer().serializeToString(svgElement);
77
- const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
78
- const url = URL.createObjectURL(svgBlob);
79
- const img = new Image();
80
- img.onload = () => {
81
- ctx.drawImage(img, 0, 0, size, size);
82
- URL.revokeObjectURL(url);
83
- resolve(canvas.toDataURL('image/png'));
84
- };
85
- img.onerror = () => {
86
- URL.revokeObjectURL(url);
87
- reject(new Error('Failed to load SVG'));
88
- };
89
- img.src = url;
90
- });
91
- }
92
- /**
93
- * Converts SVG to ICO format (simplified - creates PNG with .ico header).
94
- */
95
- async function svgToIco(svgElement, sizes = [16, 32, 48]) {
96
- // For a proper ICO, we would need to create the ICO binary format
97
- // For simplicity, we'll create a PNG at the largest size
98
- const largestSize = Math.max(...sizes);
99
- const pngData = await svgToPng(svgElement, largestSize);
100
- const response = await fetch(pngData);
101
- return response.blob();
102
- }
103
- /**
104
- * Generates React component code from state.
105
- */
106
- function generateReactCode(iconName, state) {
107
- const props = [];
108
- if (state.fill !== 'currentColor') {
109
- props.push(`fill="${state.fill}"`);
110
- }
111
- if (state.stroke !== 'none') {
112
- props.push(`stroke="${state.stroke}"`);
113
- }
114
- if (state.strokeWidth > 0) {
115
- props.push(`strokeWidth={${state.strokeWidth}}`);
116
- }
117
- if (state.size !== 24) {
118
- props.push(`size={${state.size}}`);
119
- }
120
- if (state.rotation !== 0) {
121
- props.push(`rotate={${state.rotation}}`);
122
- }
123
- if (state.flipX) {
124
- props.push(`flipX`);
125
- }
126
- if (state.flipY) {
127
- props.push(`flipY`);
128
- }
129
- if (state.opacity !== 1) {
130
- props.push(`opacity={${state.opacity}}`);
131
- }
132
- const propsStr = props.length > 0 ? ` ${props.join(' ')}` : '';
133
- return `<${iconName}${propsStr} />`;
134
- }
135
- /**
136
- * Hook for managing icon editor state.
137
- */
138
- function useIconEditor(options = {}) {
139
- const [state, setState] = useState({
140
- ...DEFAULT_STATE,
141
- ...options.defaultState,
142
- });
143
- const updateState = useCallback((updates) => {
144
- setState((prev) => {
145
- var _a;
146
- const next = { ...prev, ...updates };
147
- (_a = options.onChange) === null || _a === void 0 ? void 0 : _a.call(options, next);
148
- return next;
149
- });
150
- }, [options.onChange]);
151
- return {
152
- state,
153
- setFill: useCallback((fill) => updateState({ fill }), [updateState]),
154
- setStroke: useCallback((stroke) => updateState({ stroke }), [updateState]),
155
- setStrokeWidth: useCallback((strokeWidth) => updateState({ strokeWidth }), [updateState]),
156
- setSize: useCallback((size) => updateState({ size }), [updateState]),
157
- setRotation: useCallback((rotation) => updateState({ rotation }), [updateState]),
158
- setFlipX: useCallback((flipX) => updateState({ flipX }), [updateState]),
159
- setFlipY: useCallback((flipY) => updateState({ flipY }), [updateState]),
160
- setOpacity: useCallback((opacity) => updateState({ opacity }), [updateState]),
161
- setBadge: useCallback((badge) => updateState({ badge }), [updateState]),
162
- reset: useCallback(() => setState({ ...DEFAULT_STATE, ...options.defaultState }), [options.defaultState]),
163
- };
164
- }
165
- /* ══════════════════════════════════════════════════════════════════════════════
166
- Component
167
- ══════════════════════════════════════════════════════════════════════════════ */
168
- /**
169
- * Icon editor component for modifying and exporting icons.
170
- */
171
- function NiceIconEditor({ icon: Icon, iconName = 'Icon', defaultState, onChange, onExport, badges = [], colorPresets = DEFAULT_COLORS, sizePresets = DEFAULT_SIZES, showAdvanced = true, className = '', }) {
172
- const editor = useIconEditor({ defaultState, onChange });
173
- const { state } = editor;
174
- const previewRef = useRef(null);
175
- // Transform style
176
- const transformStyle = useMemo(() => {
177
- const transforms = [];
178
- if (state.rotation !== 0) {
179
- transforms.push(`rotate(${state.rotation}deg)`);
180
- }
181
- if (state.flipX) {
182
- transforms.push('scaleX(-1)');
183
- }
184
- if (state.flipY) {
185
- transforms.push('scaleY(-1)');
186
- }
187
- return transforms.length > 0 ? transforms.join(' ') : undefined;
188
- }, [state.rotation, state.flipX, state.flipY]);
189
- // Export handler
190
- const handleExport = useCallback(async (format, options = {}) => {
191
- var _a;
192
- const svgElement = (_a = previewRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
193
- if (!svgElement) {
194
- return;
195
- }
196
- let data;
197
- switch (format) {
198
- case 'svg':
199
- data = new XMLSerializer().serializeToString(svgElement);
200
- break;
201
- case 'png':
202
- data = await svgToPng(svgElement, options.size || state.size, options.backgroundColor);
203
- break;
204
- case 'base64':
205
- data = await svgToPng(svgElement, options.size || state.size, options.backgroundColor);
206
- break;
207
- case 'react':
208
- data = generateReactCode(iconName, state);
209
- break;
210
- case 'ico': {
211
- const blob = await svgToIco(svgElement);
212
- data = URL.createObjectURL(blob);
213
- break;
214
- }
215
- default:
216
- data = new XMLSerializer().serializeToString(svgElement);
217
- }
218
- onExport === null || onExport === void 0 ? void 0 : onExport(data, format);
219
- }, [state, iconName, onExport]);
220
- // Download handler
221
- const handleDownload = useCallback(async (format) => {
222
- var _a;
223
- const svgElement = (_a = previewRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
224
- if (!svgElement) {
225
- return;
226
- }
227
- let blob;
228
- let filename;
229
- switch (format) {
230
- case 'svg':
231
- blob = new Blob([new XMLSerializer().serializeToString(svgElement)], {
232
- type: 'image/svg+xml',
233
- });
234
- filename = `${iconName}.svg`;
235
- break;
236
- case 'png': {
237
- const pngData = await svgToPng(svgElement, state.size);
238
- const response = await fetch(pngData);
239
- blob = await response.blob();
240
- filename = `${iconName}.png`;
241
- break;
242
- }
243
- default:
244
- return;
245
- }
246
- const url = URL.createObjectURL(blob);
247
- const a = document.createElement('a');
248
- a.href = url;
249
- a.download = filename;
250
- document.body.appendChild(a);
251
- a.click();
252
- document.body.removeChild(a);
253
- URL.revokeObjectURL(url);
254
- }, [state.size, iconName]);
255
- return (jsxs("div", { className: `nice-icon-editor ${className}`, style: styles.container, children: [jsxs("div", { style: styles.previewSection, children: [jsx("div", { ref: previewRef, style: {
256
- ...styles.preview,
257
- backgroundColor: state.fill === '#ffffff' ? '#1e1e1e' : '#f5f5f5',
258
- }, children: jsxs("div", { style: { position: 'relative', display: 'inline-block' }, children: [jsx(Icon, { size: state.size, fill: state.fill, stroke: state.stroke, strokeWidth: state.strokeWidth, style: {
259
- transform: transformStyle,
260
- opacity: state.opacity,
261
- transition: 'all 0.2s ease',
262
- } }), state.badge && (jsx("div", { style: {
263
- position: 'absolute',
264
- ...getBadgeOffset(state.badge.position, state.size, state.badge.size),
265
- }, children: jsx(state.badge.icon, { size: state.badge.size, fill: state.badge.fill }) }))] }) }), jsxs("div", { style: styles.sizeInfo, children: [state.size, "\u00D7", state.size, "px"] })] }), jsxs("div", { style: styles.controls, children: [jsx(ControlGroup, { label: "Fill Color", children: jsx(ColorPicker, { value: state.fill, onChange: editor.setFill, presets: colorPresets }) }), jsx(ControlGroup, { label: "Stroke", children: jsxs("div", { style: styles.row, children: [jsx(ColorPicker, { value: state.stroke, onChange: editor.setStroke, presets: ['none', ...colorPresets] }), jsx(RangeInput, { min: 0, max: 5, step: 0.5, value: state.strokeWidth, onChange: editor.setStrokeWidth, label: "Width" })] }) }), jsx(ControlGroup, { label: "Size", children: jsxs("div", { style: styles.row, children: [jsx("select", { value: state.size, onChange: (e) => editor.setSize(Number(e.target.value)), style: styles.select, children: sizePresets.map((s) => (jsxs("option", { value: s, children: [s, "px"] }, s))) }), jsx("input", { type: "number", value: state.size, onChange: (e) => editor.setSize(Number(e.target.value)), min: 8, max: 512, style: styles.numberInput })] }) }), showAdvanced && (jsxs(Fragment, { children: [jsxs(ControlGroup, { label: "Transform", children: [jsx(RangeInput, { min: 0, max: 360, value: state.rotation, onChange: editor.setRotation, label: `Rotate: ${state.rotation}°` }), jsxs("div", { style: styles.row, children: [jsx(ToggleButton, { active: state.flipX, onClick: () => editor.setFlipX(!state.flipX), label: "Flip X" }), jsx(ToggleButton, { active: state.flipY, onClick: () => editor.setFlipY(!state.flipY), label: "Flip Y" })] })] }), jsx(ControlGroup, { label: "Opacity", children: jsx(RangeInput, { min: 0, max: 1, step: 0.1, value: state.opacity, onChange: editor.setOpacity, label: `${Math.round(state.opacity * 100)}%` }) }), badges.length > 0 && (jsxs(ControlGroup, { label: "Badge", children: [jsxs("select", { value: state.badge ? 'badge' : 'none', onChange: (e) => {
266
- if (e.target.value === 'none') {
267
- editor.setBadge(undefined);
268
- }
269
- else {
270
- const badgeIcon = badges.find((b) => b.name === e.target.value);
271
- if (badgeIcon) {
272
- editor.setBadge({
273
- icon: badgeIcon.icon,
274
- position: 'top-right',
275
- size: Math.max(16, state.size * 0.4),
276
- fill: '#ef4444',
277
- });
278
- }
279
- }
280
- }, style: styles.select, children: [jsx("option", { value: "none", children: "None" }), badges.map((b) => (jsx("option", { value: b.name, children: b.name }, b.name)))] }), state.badge && (jsx("select", { value: state.badge.position, onChange: (e) => {
281
- if (state.badge) {
282
- editor.setBadge({
283
- ...state.badge,
284
- position: e.target.value,
285
- });
286
- }
287
- }, style: styles.select, children: BADGE_POSITIONS.map((p) => (jsx("option", { value: p.value, children: p.label }, p.value))) }))] }))] })), jsx(ControlGroup, { label: "Export", children: jsxs("div", { style: styles.exportButtons, children: [jsx("button", { onClick: () => handleDownload('svg'), style: styles.exportButton, children: "SVG" }), jsx("button", { onClick: () => handleDownload('png'), style: styles.exportButton, children: "PNG" }), jsx("button", { onClick: () => handleExport('react'), style: styles.exportButton, children: "React" })] }) }), jsx("button", { onClick: editor.reset, style: styles.resetButton, children: "Reset" })] })] }));
288
- }
289
- /* ══════════════════════════════════════════════════════════════════════════════
290
- Sub-components
291
- ══════════════════════════════════════════════════════════════════════════════ */
292
- function ControlGroup({ label, children }) {
293
- return (jsxs("div", { style: styles.controlGroup, children: [jsx("label", { style: styles.label, children: label }), children] }));
294
- }
295
- function ColorPicker({ value, onChange, presets, }) {
296
- return (jsxs("div", { style: styles.colorPicker, children: [jsx("input", { type: "color", value: value === 'none' || value === 'currentColor' ? '#000000' : value, onChange: (e) => onChange(e.target.value), style: styles.colorInput }), jsx("div", { style: styles.colorPresets, children: presets.map((color) => (jsx("button", { onClick: () => onChange(color), style: {
297
- ...styles.colorSwatch,
298
- backgroundColor: color === 'none' ? 'transparent' : color,
299
- border: value === color ? '2px solid #3b82f6' : '1px solid #ccc',
300
- }, title: color, children: color === 'none' && '×' }, color))) })] }));
301
- }
302
- function RangeInput({ min, max, step = 1, value, onChange, label, }) {
303
- return (jsxs("div", { style: styles.rangeContainer, children: [label && jsx("span", { style: styles.rangeLabel, children: label }), jsx("input", { type: "range", min: min, max: max, step: step, value: value, onChange: (e) => onChange(Number(e.target.value)), style: styles.rangeInput })] }));
304
- }
305
- function ToggleButton({ active, onClick, label, }) {
306
- return (jsx("button", { onClick: onClick, style: {
307
- ...styles.toggleButton,
308
- backgroundColor: active ? '#3b82f6' : '#e5e7eb',
309
- color: active ? '#fff' : '#374151',
310
- }, children: label }));
311
- }
312
- /* ══════════════════════════════════════════════════════════════════════════════
313
- Styles
314
- ══════════════════════════════════════════════════════════════════════════════ */
315
- const styles = {
316
- container: {
317
- display: 'flex',
318
- gap: '24px',
319
- padding: '16px',
320
- fontFamily: 'system-ui, -apple-system, sans-serif',
321
- fontSize: '14px',
322
- },
323
- previewSection: {
324
- display: 'flex',
325
- flexDirection: 'column',
326
- alignItems: 'center',
327
- gap: '8px',
328
- },
329
- preview: {
330
- display: 'flex',
331
- alignItems: 'center',
332
- justifyContent: 'center',
333
- padding: '32px',
334
- borderRadius: '8px',
335
- border: '1px solid #e5e7eb',
336
- minWidth: '200px',
337
- minHeight: '200px',
338
- },
339
- sizeInfo: {
340
- fontSize: '12px',
341
- color: '#6b7280',
342
- },
343
- controls: {
344
- display: 'flex',
345
- flexDirection: 'column',
346
- gap: '16px',
347
- minWidth: '280px',
348
- },
349
- controlGroup: {
350
- display: 'flex',
351
- flexDirection: 'column',
352
- gap: '8px',
353
- },
354
- label: {
355
- fontWeight: 600,
356
- color: '#374151',
357
- fontSize: '12px',
358
- textTransform: 'uppercase',
359
- letterSpacing: '0.5px',
360
- },
361
- row: {
362
- display: 'flex',
363
- gap: '8px',
364
- alignItems: 'center',
365
- },
366
- colorPicker: {
367
- display: 'flex',
368
- flexDirection: 'column',
369
- gap: '8px',
370
- },
371
- colorInput: {
372
- width: '100%',
373
- height: '32px',
374
- border: 'none',
375
- borderRadius: '4px',
376
- cursor: 'pointer',
377
- },
378
- colorPresets: {
379
- display: 'flex',
380
- flexWrap: 'wrap',
381
- gap: '4px',
382
- },
383
- colorSwatch: {
384
- width: '24px',
385
- height: '24px',
386
- borderRadius: '4px',
387
- cursor: 'pointer',
388
- fontSize: '14px',
389
- display: 'flex',
390
- alignItems: 'center',
391
- justifyContent: 'center',
392
- color: '#999',
393
- },
394
- select: {
395
- flex: 1,
396
- padding: '6px 8px',
397
- borderRadius: '4px',
398
- border: '1px solid #d1d5db',
399
- fontSize: '14px',
400
- },
401
- numberInput: {
402
- width: '70px',
403
- padding: '6px 8px',
404
- borderRadius: '4px',
405
- border: '1px solid #d1d5db',
406
- fontSize: '14px',
407
- },
408
- rangeContainer: {
409
- display: 'flex',
410
- flexDirection: 'column',
411
- gap: '4px',
412
- },
413
- rangeLabel: {
414
- fontSize: '12px',
415
- color: '#6b7280',
416
- },
417
- rangeInput: {
418
- width: '100%',
419
- },
420
- toggleButton: {
421
- flex: 1,
422
- padding: '8px 12px',
423
- borderRadius: '4px',
424
- border: 'none',
425
- cursor: 'pointer',
426
- fontWeight: 500,
427
- transition: 'all 0.2s',
428
- },
429
- exportButtons: {
430
- display: 'flex',
431
- gap: '8px',
432
- },
433
- exportButton: {
434
- flex: 1,
435
- padding: '8px 12px',
436
- borderRadius: '4px',
437
- border: '1px solid #d1d5db',
438
- backgroundColor: '#fff',
439
- cursor: 'pointer',
440
- fontWeight: 500,
441
- transition: 'all 0.2s',
442
- },
443
- resetButton: {
444
- padding: '8px 16px',
445
- borderRadius: '4px',
446
- border: '1px solid #ef4444',
447
- backgroundColor: '#fff',
448
- color: '#ef4444',
449
- cursor: 'pointer',
450
- fontWeight: 500,
451
- },
452
- };
453
-
454
- export { NiceIconEditor, useIconEditor };
@@ -1,97 +0,0 @@
1
- /**
2
- * @file NiceIconEditor.tsx
3
- * @module @nice2dev/icons
4
- * @description PRO-28.4 — Icon Editor Component
5
- *
6
- * Simple editor for modifying existing icons:
7
- * - Change colors (fill, stroke)
8
- * - Combine icons (badge/overlay)
9
- * - Scale / transform
10
- * - Export to multiple formats
11
- */
12
- import React, { type ComponentType } from 'react';
13
- import type { NtdIconProps } from './types';
14
- export interface IconEditorState {
15
- /** Primary fill color */
16
- fill: string;
17
- /** Stroke color */
18
- stroke: string;
19
- /** Stroke width */
20
- strokeWidth: number;
21
- /** Size in pixels */
22
- size: number;
23
- /** Rotation in degrees */
24
- rotation: number;
25
- /** Horizontal flip */
26
- flipX: boolean;
27
- /** Vertical flip */
28
- flipY: boolean;
29
- /** Opacity (0-1) */
30
- opacity: number;
31
- /** Badge/overlay icon */
32
- badge?: {
33
- icon: ComponentType<NtdIconProps>;
34
- position: BadgePosition;
35
- size: number;
36
- fill: string;
37
- };
38
- }
39
- export type BadgePosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
40
- export type ExportFormat = 'svg' | 'png' | 'ico' | 'base64' | 'react';
41
- export interface ExportOptions {
42
- format: ExportFormat;
43
- size?: number;
44
- backgroundColor?: string;
45
- padding?: number;
46
- }
47
- export interface NiceIconEditorProps {
48
- /** Icon to edit */
49
- icon: ComponentType<NtdIconProps>;
50
- /** Icon name */
51
- iconName?: string;
52
- /** Initial editor state */
53
- defaultState?: Partial<IconEditorState>;
54
- /** Called when state changes */
55
- onChange?: (state: IconEditorState) => void;
56
- /** Called on export */
57
- onExport?: (data: string, format: ExportFormat) => void;
58
- /** Available badges */
59
- badges?: {
60
- icon: ComponentType<NtdIconProps>;
61
- name: string;
62
- }[];
63
- /** Custom color presets */
64
- colorPresets?: string[];
65
- /** Custom size presets */
66
- sizePresets?: number[];
67
- /** Show advanced controls */
68
- showAdvanced?: boolean;
69
- /** Custom class */
70
- className?: string;
71
- }
72
- export interface UseIconEditorOptions {
73
- defaultState?: Partial<IconEditorState>;
74
- onChange?: (state: IconEditorState) => void;
75
- }
76
- export interface UseIconEditorReturn {
77
- state: IconEditorState;
78
- setFill: (color: string) => void;
79
- setStroke: (color: string) => void;
80
- setStrokeWidth: (width: number) => void;
81
- setSize: (size: number) => void;
82
- setRotation: (degrees: number) => void;
83
- setFlipX: (flip: boolean) => void;
84
- setFlipY: (flip: boolean) => void;
85
- setOpacity: (opacity: number) => void;
86
- setBadge: (badge: IconEditorState['badge']) => void;
87
- reset: () => void;
88
- }
89
- /**
90
- * Hook for managing icon editor state.
91
- */
92
- export declare function useIconEditor(options?: UseIconEditorOptions): UseIconEditorReturn;
93
- /**
94
- * Icon editor component for modifying and exporting icons.
95
- */
96
- export declare function NiceIconEditor({ icon: Icon, iconName, defaultState, onChange, onExport, badges, colorPresets, sizePresets, showAdvanced, className, }: NiceIconEditorProps): React.ReactElement;
97
- export default NiceIconEditor;
@@ -1,75 +0,0 @@
1
- import React from 'react';
2
- import type { IconVariant, IconAnimation } from './types';
3
- import './NiceVectorEditor.css';
4
- /** Universal library entry — works with NiceToDev icons or any custom components. */
5
- export interface VectorLibraryEntry {
6
- name: string;
7
- category?: string;
8
- Component: React.ComponentType<Record<string, unknown>>;
9
- }
10
- /** Available drawing / interaction tools. */
11
- export type VectorTool = 'select' | 'rect' | 'circle' | 'line' | 'text' | 'pan';
12
- /** Supported layer element types. */
13
- export type VectorLayerType = 'rect' | 'circle' | 'line' | 'text' | 'icon';
14
- /** A single layer in the vector editor canvas. */
15
- export interface VectorEditorLayer {
16
- id: string;
17
- name: string;
18
- type: VectorLayerType;
19
- visible: boolean;
20
- locked: boolean;
21
- fill: string;
22
- fillOpacity: number;
23
- stroke: string;
24
- strokeOpacity: number;
25
- strokeWidth: number;
26
- opacity: number;
27
- blendMode: NonNullable<React.CSSProperties['mixBlendMode']>;
28
- rotate: number;
29
- scaleX: number;
30
- scaleY: number;
31
- x: number;
32
- y: number;
33
- width: number;
34
- height: number;
35
- rx: number;
36
- cx: number;
37
- cy: number;
38
- r: number;
39
- x1: number;
40
- y1: number;
41
- x2: number;
42
- y2: number;
43
- text: string;
44
- fontSize: number;
45
- fontFamily: string;
46
- iconName: string;
47
- iconSize: number;
48
- iconVariant: IconVariant;
49
- iconPrimaryColor: string;
50
- iconSecondaryColor: string;
51
- iconAccentColor: string;
52
- iconAnimation: IconAnimation | 'none';
53
- }
54
- /** Props for the {@link NiceVectorEditor} component. */
55
- export interface NiceVectorEditorProps {
56
- /** Browsable library items (icons, shapes, images). */
57
- library?: VectorLibraryEntry[];
58
- /** Canvas width in SVG units. @defaultValue 800 */
59
- width?: number;
60
- /** Canvas height in SVG units. @defaultValue 600 */
61
- height?: number;
62
- /** Layers to load on mount. */
63
- initialLayers?: VectorEditorLayer[];
64
- /** Fires whenever layers change. */
65
- onChange?: (layers: VectorEditorLayer[]) => void;
66
- /** Additional CSS class on the root element. */
67
- className?: string;
68
- }
69
- /** Imperative handle exposed via `ref`. */
70
- export interface NiceVectorEditorHandle {
71
- getLayers(): VectorEditorLayer[];
72
- exportSvg(): string;
73
- exportJson(): string;
74
- }
75
- export declare const NiceVectorEditor: React.ForwardRefExoticComponent<NiceVectorEditorProps & React.RefAttributes<NiceVectorEditorHandle>>;