@umituz/react-native-image 1.2.5 → 1.3.2

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,135 +0,0 @@
1
- /**
2
- * Presentation - Editor Canvas Component
3
- *
4
- * Main canvas component for image editing
5
- */
6
-
7
- import React, { useRef, useEffect, useCallback } from 'react';
8
- import { View, StyleSheet } from 'react-native';
9
- import { useEditorTools } from '../hooks/useEditorTools';
10
-
11
- import { EditorTool } from '../../domain/entities/EditorTypes';
12
-
13
- interface EditorCanvasProps {
14
- width: number;
15
- height: number;
16
- onCanvasReady?: (canvas: HTMLCanvasElement) => void;
17
- onToolChange?: (tool: EditorTool) => void;
18
- onStateChange?: (state: any) => void;
19
- backgroundColor?: string;
20
- }
21
-
22
- export function EditorCanvas({
23
- width,
24
- height,
25
- onCanvasReady,
26
- onToolChange,
27
- onStateChange,
28
- backgroundColor = '#ffffff',
29
- }: EditorCanvasProps) {
30
- const canvasRef = useRef<any>(null);
31
- const {
32
- setTool,
33
- startDrawing,
34
- draw,
35
- stopDrawing,
36
- setCropArea,
37
- } = useEditorTools({
38
- onStateChange,
39
- canvas: canvasRef.current,
40
- });
41
-
42
- useEffect(() => {
43
- if (canvasRef.current && onCanvasReady) {
44
- onCanvasReady(canvasRef.current);
45
- }
46
- }, [canvasRef.current, onCanvasReady]);
47
-
48
- const handleTouchStart = useCallback((event: any) => {
49
- const touch = event.nativeEvent.touches[0];
50
- const point = { x: touch.pageX, y: touch.pageY };
51
- setTool(EditorTool.BRUSH);
52
- startDrawing(point);
53
- onToolChange?.(EditorTool.BRUSH);
54
- }, [setTool, startDrawing, onToolChange]);
55
-
56
- const handleTouchMove = useCallback((event: any) => {
57
- const touch = event.nativeEvent.touches[0];
58
- const point = { x: touch.pageX, y: touch.pageY };
59
- draw(point);
60
- }, [draw]);
61
-
62
- const handleTouchEnd = useCallback(() => {
63
- stopDrawing();
64
- }, [stopDrawing]);
65
-
66
- // For React Native Web, we need to handle this differently
67
- useEffect(() => {
68
- const canvas = canvasRef.current;
69
- if (!canvas) return;
70
-
71
- // Touch events for mobile
72
- canvas.addEventListener('touchstart', handleTouchStart);
73
- canvas.addEventListener('touchmove', handleTouchMove);
74
- canvas.addEventListener('touchend', handleTouchEnd);
75
-
76
- // Mouse events for desktop
77
- const handleMouseDown = (e: MouseEvent) => {
78
- const point = { x: e.offsetX, y: e.offsetY };
79
- setTool(EditorTool.BRUSH);
80
- startDrawing(point);
81
- onToolChange?.(EditorTool.BRUSH);
82
- };
83
-
84
- const handleMouseMove = (e: MouseEvent) => {
85
- const point = { x: e.offsetX, y: e.offsetY };
86
- draw(point);
87
- };
88
-
89
- const handleMouseUp = () => {
90
- stopDrawing();
91
- };
92
-
93
- canvas.addEventListener('mousedown', handleMouseDown);
94
- canvas.addEventListener('mousemove', handleMouseMove);
95
- canvas.addEventListener('mouseup', handleMouseUp);
96
-
97
- return () => {
98
- canvas.removeEventListener('touchstart', handleTouchStart);
99
- canvas.removeEventListener('touchmove', handleTouchMove);
100
- canvas.removeEventListener('touchend', handleTouchEnd);
101
- canvas.removeEventListener('mousedown', handleMouseDown);
102
- canvas.removeEventListener('mousemove', handleMouseMove);
103
- canvas.removeEventListener('mouseup', handleMouseUp);
104
- };
105
- }, [setTool, startDrawing, draw, stopDrawing, onToolChange]);
106
-
107
- // For React Native, we'll need to use a different approach
108
- if (typeof window === 'undefined') {
109
- return (
110
- <View style={[styles.container, { width, height, backgroundColor }]} />
111
- );
112
- }
113
-
114
- return (
115
- <View style={[styles.container, { width, height }]}>
116
- <canvas
117
- ref={canvasRef}
118
- width={width}
119
- height={height}
120
- style={{
121
- width,
122
- height,
123
- backgroundColor,
124
- }}
125
- />
126
- </View>
127
- );
128
- }
129
-
130
- const styles = StyleSheet.create({
131
- container: {
132
- position: 'relative',
133
- overflow: 'hidden',
134
- },
135
- });
@@ -1,321 +0,0 @@
1
- /**
2
- * Presentation - Editor Panel Component
3
- *
4
- * Configuration panel for selected tools
5
- */
6
-
7
- import React, { useState, useCallback } from 'react';
8
- import { View, StyleSheet, TouchableOpacity, Text } from 'react-native';
9
- import Slider from '@react-native-community/slider';
10
- import { EditorTool } from '../../domain/entities/EditorTypes';
11
-
12
- interface EditorPanelProps {
13
- selectedTool: EditorTool;
14
- onToolConfigChange?: (config: any) => void;
15
- backgroundColor?: string;
16
- }
17
-
18
- export function EditorPanel({ selectedTool, onToolConfigChange, backgroundColor = '#f8f9fa' }: EditorPanelProps) {
19
- const [brushSize, setBrushSize] = useState(5);
20
- const [brushOpacity, setBrushOpacity] = useState(1);
21
- const [brushColor, setBrushColor] = useState('#000000');
22
- const [brushStyle, setBrushStyle] = useState('normal');
23
-
24
- const [fontSize, setFontSize] = useState(16);
25
- const [textColor, setTextColor] = useState('#000000');
26
-
27
- const [cropAspectRatio, setCropAspectRatio] = useState(0);
28
- const [cropGrid, setCropGrid] = useState(true);
29
-
30
- const handleConfigChange = useCallback((config: any) => {
31
- onToolConfigChange?.(config);
32
- }, [onToolConfigChange]);
33
-
34
- const renderBrushPanel = () => (
35
- <View style={styles.panel}>
36
- <View style={styles.configRow}>
37
- <Text style={styles.label}>Size</Text>
38
- <Slider
39
- style={styles.slider}
40
- minimumValue={1}
41
- maximumValue={50}
42
- value={brushSize}
43
- onValueChange={setBrushSize}
44
- onSlidingComplete={() => handleConfigChange({
45
- size: brushSize,
46
- opacity: brushOpacity,
47
- color: brushColor,
48
- style: brushStyle
49
- })}
50
- />
51
- <Text style={styles.value}>{Math.round(brushSize)}</Text>
52
- </View>
53
-
54
- <View style={styles.configRow}>
55
- <Text style={styles.label}>Opacity</Text>
56
- <Slider
57
- style={styles.slider}
58
- minimumValue={0}
59
- maximumValue={1}
60
- value={brushOpacity}
61
- onValueChange={setBrushOpacity}
62
- onSlidingComplete={() => handleConfigChange({
63
- size: brushSize,
64
- opacity: brushOpacity,
65
- color: brushColor,
66
- style: brushStyle
67
- })}
68
- />
69
- <Text style={styles.value}>{Math.round(brushOpacity * 100)}%</Text>
70
- </View>
71
-
72
- <View style={styles.configRow}>
73
- <Text style={styles.label}>Color</Text>
74
- <View style={styles.colorRow}>
75
- {['#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff', '#ffff00'].map(color => (
76
- <TouchableOpacity
77
- key={color}
78
- style={[styles.colorButton, { backgroundColor: color }]}
79
- onPress={() => {
80
- setBrushColor(color);
81
- handleConfigChange({
82
- size: brushSize,
83
- opacity: brushOpacity,
84
- color,
85
- style: brushStyle
86
- });
87
- }}
88
- />
89
- ))}
90
- </View>
91
- </View>
92
-
93
- <View style={styles.configRow}>
94
- <Text style={styles.label}>Style</Text>
95
- <View style={styles.styleRow}>
96
- {['normal', 'marker', 'spray'].map(style => (
97
- <TouchableOpacity
98
- key={style}
99
- style={[styles.styleButton, brushStyle === style && styles.selectedStyle]}
100
- onPress={() => {
101
- setBrushStyle(style);
102
- handleConfigChange({
103
- size: brushSize,
104
- opacity: brushOpacity,
105
- color: brushColor,
106
- style
107
- });
108
- }}
109
- >
110
- <Text style={styles.styleText}>{style}</Text>
111
- </TouchableOpacity>
112
- ))}
113
- </View>
114
- </View>
115
- </View>
116
- );
117
-
118
- const renderTextPanel = () => (
119
- <View style={styles.panel}>
120
- <View style={styles.configRow}>
121
- <Text style={styles.label}>Font Size</Text>
122
- <Slider
123
- style={styles.slider}
124
- minimumValue={8}
125
- maximumValue={72}
126
- value={fontSize}
127
- onValueChange={setFontSize}
128
- onSlidingComplete={() => handleConfigChange({ fontSize, color: textColor })}
129
- />
130
- <Text style={styles.value}>{Math.round(fontSize)}</Text>
131
- </View>
132
-
133
- <View style={styles.configRow}>
134
- <Text style={styles.label}>Color</Text>
135
- <View style={styles.colorRow}>
136
- {['#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff', '#ffff00'].map(color => (
137
- <TouchableOpacity
138
- key={color}
139
- style={[styles.colorButton, { backgroundColor: color }]}
140
- onPress={() => {
141
- setTextColor(color);
142
- handleConfigChange({ fontSize, color });
143
- }}
144
- />
145
- ))}
146
- </View>
147
- </View>
148
- </View>
149
- );
150
-
151
- const renderCropPanel = () => (
152
- <View style={styles.panel}>
153
- <View style={styles.configRow}>
154
- <Text style={styles.label}>Aspect Ratio</Text>
155
- <View style={styles.ratioRow}>
156
- {[
157
- { label: 'Free', value: 0 },
158
- { label: '1:1', value: 1 },
159
- { label: '4:3', value: 1.333333333 },
160
- { label: '16:9', value: 1.777777777 },
161
- ].map(ratio => (
162
- <TouchableOpacity
163
- key={ratio.value}
164
- style={[styles.ratioButton, cropAspectRatio === ratio.value && styles.selectedRatio]}
165
- onPress={() => {
166
- setCropAspectRatio(ratio.value);
167
- handleConfigChange({ aspectRatio: ratio.value, grid: cropGrid });
168
- }}
169
- >
170
- <Text style={styles.ratioText}>{ratio.label}</Text>
171
- </TouchableOpacity>
172
- ))}
173
- </View>
174
- </View>
175
-
176
- <View style={styles.configRow}>
177
- <Text style={styles.label}>Show Grid</Text>
178
- <TouchableOpacity
179
- style={[styles.toggleButton, cropGrid && styles.selectedToggle]}
180
- onPress={() => {
181
- setCropGrid(!cropGrid);
182
- handleConfigChange({ aspectRatio: cropAspectRatio, grid: !cropGrid });
183
- }}
184
- >
185
- <Text style={styles.toggleText}>{cropGrid ? 'ON' : 'OFF'}</Text>
186
- </TouchableOpacity>
187
- </View>
188
- </View>
189
- );
190
-
191
- const renderPanel = () => {
192
- switch (selectedTool) {
193
- case EditorTool.BRUSH:
194
- case EditorTool.ERASER:
195
- return renderBrushPanel();
196
- case EditorTool.TEXT:
197
- return renderTextPanel();
198
- case EditorTool.CROP:
199
- return renderCropPanel();
200
- default:
201
- return null;
202
- }
203
- };
204
-
205
- return (
206
- <View style={[styles.container, { backgroundColor }]}>
207
- {renderPanel()}
208
- </View>
209
- );
210
- }
211
-
212
- const styles = StyleSheet.create({
213
- container: {
214
- padding: 16,
215
- minHeight: 200,
216
- borderTopWidth: 1,
217
- borderTopColor: '#e0e0e0',
218
- },
219
- panel: {
220
- gap: 16,
221
- },
222
- configRow: {
223
- gap: 8,
224
- },
225
- label: {
226
- fontSize: 14,
227
- fontWeight: '600',
228
- color: '#333333',
229
- marginBottom: 8,
230
- },
231
- value: {
232
- fontSize: 12,
233
- color: '#666666',
234
- textAlign: 'center',
235
- minWidth: 40,
236
- },
237
- slider: {
238
- flex: 1,
239
- height: 40,
240
- },
241
- colorRow: {
242
- flexDirection: 'row',
243
- gap: 8,
244
- flexWrap: 'wrap',
245
- },
246
- colorButton: {
247
- width: 30,
248
- height: 30,
249
- borderRadius: 6,
250
- borderWidth: 2,
251
- borderColor: '#d0d0d0',
252
- },
253
- styleRow: {
254
- flexDirection: 'row',
255
- gap: 8,
256
- },
257
- styleButton: {
258
- paddingVertical: 8,
259
- paddingHorizontal: 12,
260
- borderRadius: 6,
261
- borderWidth: 1,
262
- borderColor: '#d0d0d0',
263
- backgroundColor: '#ffffff',
264
- },
265
- selectedStyle: {
266
- backgroundColor: '#007bff',
267
- borderColor: '#007bff',
268
- },
269
- styleText: {
270
- fontSize: 12,
271
- fontWeight: '500',
272
- color: '#333333',
273
- },
274
- styleTextSelected: {
275
- color: '#ffffff',
276
- },
277
- ratioRow: {
278
- flexDirection: 'row',
279
- gap: 8,
280
- },
281
- ratioButton: {
282
- paddingVertical: 8,
283
- paddingHorizontal: 12,
284
- borderRadius: 6,
285
- borderWidth: 1,
286
- borderColor: '#d0d0d0',
287
- backgroundColor: '#ffffff',
288
- },
289
- selectedRatio: {
290
- backgroundColor: '#007bff',
291
- borderColor: '#007bff',
292
- },
293
- ratioText: {
294
- fontSize: 12,
295
- fontWeight: '500',
296
- color: '#333333',
297
- },
298
- ratioTextSelected: {
299
- color: '#ffffff',
300
- },
301
- toggleButton: {
302
- paddingVertical: 8,
303
- paddingHorizontal: 16,
304
- borderRadius: 6,
305
- borderWidth: 1,
306
- borderColor: '#d0d0d0',
307
- backgroundColor: '#ffffff',
308
- },
309
- selectedToggle: {
310
- backgroundColor: '#007bff',
311
- borderColor: '#007bff',
312
- },
313
- toggleText: {
314
- fontSize: 12,
315
- fontWeight: '500',
316
- color: '#333333',
317
- },
318
- toggleTextSelected: {
319
- color: '#ffffff',
320
- },
321
- });
@@ -1,180 +0,0 @@
1
- /**
2
- * Presentation - Editor Toolbar Component
3
- *
4
- * Toolbar with tools and configuration options
5
- */
6
-
7
- import React from 'react';
8
- import { View, TouchableOpacity, StyleSheet, ScrollView, Text } from 'react-native';
9
- import { EditorTool, ShapeType } from '../../domain/entities/EditorTypes';
10
-
11
- interface EditorToolbarProps {
12
- selectedTool: EditorTool;
13
- onToolSelect: (tool: EditorTool) => void;
14
- onShapeSelect?: (shape: ShapeType) => void;
15
- showShapes?: boolean;
16
- backgroundColor?: string;
17
- }
18
-
19
- interface ToolButtonProps {
20
- tool: EditorTool;
21
- icon: string;
22
- label: string;
23
- isSelected: boolean;
24
- onPress: () => void;
25
- }
26
-
27
- function ToolButton({ tool, icon, label, isSelected, onPress }: ToolButtonProps) {
28
- return (
29
- <TouchableOpacity
30
- style={[styles.toolButton, isSelected && styles.selectedTool]}
31
- onPress={onPress}
32
- activeOpacity={0.7}
33
- >
34
- <View style={styles.toolIcon}>
35
- <Text style={[styles.iconText, isSelected && styles.iconTextSelected]}>{icon}</Text>
36
- </View>
37
- <Text style={[styles.toolLabel, isSelected && styles.toolLabelSelected]}>{label}</Text>
38
- </TouchableOpacity>
39
- );
40
- }
41
-
42
- export function EditorToolbar({
43
- selectedTool,
44
- onToolSelect,
45
- onShapeSelect,
46
- showShapes = false,
47
- backgroundColor = '#f8f9fa',
48
- }: EditorToolbarProps) {
49
- const mainTools = [
50
- { tool: EditorTool.MOVE as EditorTool, icon: '↔', label: 'Move' },
51
- { tool: EditorTool.BRUSH as EditorTool, icon: '✏', label: 'Brush' },
52
- { tool: EditorTool.ERASER as EditorTool, icon: '⌫', label: 'Eraser' },
53
- { tool: EditorTool.TEXT as EditorTool, icon: 'T', label: 'Text' },
54
- { tool: EditorTool.SHAPE as EditorTool, icon: '◇', label: 'Shape' },
55
- { tool: EditorTool.CROP as EditorTool, icon: '✂', label: 'Crop' },
56
- { tool: EditorTool.FILTER as EditorTool, icon: '🎨', label: 'Filter' },
57
- ];
58
-
59
- const shapeTools = [
60
- { shape: ShapeType.RECTANGLE, icon: '▢', label: 'Rectangle' },
61
- { shape: ShapeType.CIRCLE, icon: '○', label: 'Circle' },
62
- { shape: ShapeType.LINE, icon: '╱', label: 'Line' },
63
- { shape: ShapeType.ARROW, icon: '→', label: 'Arrow' },
64
- { shape: ShapeType.TRIANGLE, icon: '△', label: 'Triangle' },
65
- { shape: ShapeType.STAR, icon: '★', label: 'Star' },
66
- { shape: ShapeType.HEART, icon: '♥', label: 'Heart' },
67
- ];
68
-
69
- return (
70
- <View style={[styles.container, { backgroundColor }]}>
71
- <ScrollView
72
- horizontal
73
- showsHorizontalScrollIndicator={false}
74
- style={styles.scrollContainer}
75
- >
76
- <View style={styles.toolGroup}>
77
- {mainTools.map(({ tool, icon, label }) => (
78
- <ToolButton
79
- key={tool}
80
- tool={tool}
81
- icon={icon}
82
- label={label}
83
- isSelected={selectedTool === tool}
84
- onPress={() => onToolSelect(tool)}
85
- />
86
- ))}
87
- </View>
88
-
89
- {showShapes && onShapeSelect && (
90
- <View style={[styles.toolGroup, styles.shapeGroup]}>
91
- {shapeTools.map(({ shape, icon, label }) => (
92
- <TouchableOpacity
93
- key={shape}
94
- style={styles.shapeButton}
95
- onPress={() => onShapeSelect(shape)}
96
- activeOpacity={0.7}
97
- >
98
- <View style={styles.toolIcon}>
99
- <Text style={styles.iconText}>{icon}</Text>
100
- </View>
101
- <Text style={styles.toolLabel}>{label}</Text>
102
- </TouchableOpacity>
103
- ))}
104
- </View>
105
- )}
106
- </ScrollView>
107
- </View>
108
- );
109
- }
110
-
111
- const styles = StyleSheet.create({
112
- container: {
113
- paddingVertical: 8,
114
- paddingHorizontal: 4,
115
- borderBottomWidth: 1,
116
- borderBottomColor: '#e0e0e0',
117
- backgroundColor: '#f8f9fa',
118
- },
119
- scrollContainer: {
120
- flex: 1,
121
- },
122
- toolGroup: {
123
- flexDirection: 'row',
124
- alignItems: 'center',
125
- paddingHorizontal: 8,
126
- },
127
- shapeGroup: {
128
- borderLeftWidth: 1,
129
- borderLeftColor: '#e0e0e0',
130
- marginLeft: 16,
131
- },
132
- toolButton: {
133
- alignItems: 'center',
134
- justifyContent: 'center',
135
- paddingVertical: 8,
136
- paddingHorizontal: 12,
137
- marginHorizontal: 2,
138
- borderRadius: 8,
139
- backgroundColor: '#ffffff',
140
- borderWidth: 1,
141
- borderColor: '#d0d0d0',
142
- minWidth: 60,
143
- },
144
- selectedTool: {
145
- backgroundColor: '#007bff',
146
- borderColor: '#007bff',
147
- },
148
- shapeButton: {
149
- alignItems: 'center',
150
- justifyContent: 'center',
151
- paddingVertical: 6,
152
- paddingHorizontal: 8,
153
- marginHorizontal: 2,
154
- borderRadius: 6,
155
- backgroundColor: '#ffffff',
156
- borderWidth: 1,
157
- borderColor: '#d0d0d0',
158
- minWidth: 50,
159
- },
160
- toolIcon: {
161
- marginBottom: 2,
162
- },
163
- iconText: {
164
- fontSize: 16,
165
- fontWeight: '600',
166
- color: '#333333',
167
- },
168
- iconTextSelected: {
169
- color: '#ffffff',
170
- },
171
- toolLabel: {
172
- fontSize: 10,
173
- fontWeight: '500',
174
- color: '#666666',
175
- textAlign: 'center',
176
- },
177
- toolLabelSelected: {
178
- color: '#ffffff',
179
- },
180
- });