@umituz/react-native-image 1.3.9 → 1.3.11

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.
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Presentation - Sticker Picker Sheet
3
+ */
4
+
5
+ import React, { forwardRef } from 'react';
6
+ import { View, TouchableOpacity, ScrollView, Image, Dimensions } from 'react-native';
7
+ import {
8
+ BottomSheetModal,
9
+ AtomicText,
10
+ useAppDesignTokens,
11
+ BottomSheetModalRef
12
+ } from '@umituz/react-native-design-system';
13
+
14
+ const { width: SCREEN_WIDTH } = Dimensions.get('window');
15
+
16
+ export interface StickerPickerSheetProps {
17
+ stickers: string[];
18
+ onSelectSticker: (uri: string) => void;
19
+ onDismiss: () => void;
20
+ title?: string;
21
+ snapPoints?: string[];
22
+ }
23
+
24
+ export const StickerPickerSheet = forwardRef<BottomSheetModalRef, StickerPickerSheetProps>(
25
+ ({ stickers, onSelectSticker, onDismiss, title = 'Select Sticker', snapPoints = ['60%'] }, ref) => {
26
+ const tokens = useAppDesignTokens();
27
+
28
+ return (
29
+ <BottomSheetModal ref={ref} snapPoints={snapPoints} onDismiss={onDismiss}>
30
+ <View style={{ padding: tokens.spacing.lg, flex: 1 }}>
31
+ <AtomicText style={{ ...tokens.typography.headingSmall, marginBottom: tokens.spacing.md }}>
32
+ {title}
33
+ </AtomicText>
34
+
35
+ <ScrollView showsVerticalScrollIndicator={false}>
36
+ <View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: tokens.spacing.md }}>
37
+ {stickers.map((uri, index) => (
38
+ <TouchableOpacity
39
+ key={index}
40
+ onPress={() => onSelectSticker(uri)}
41
+ style={{
42
+ width: (SCREEN_WIDTH - 64) / 3,
43
+ aspectRatio: 1,
44
+ backgroundColor: tokens.colors.surfaceVariant,
45
+ borderRadius: tokens.borderRadius.md,
46
+ padding: tokens.spacing.sm,
47
+ alignItems: 'center',
48
+ justifyContent: 'center',
49
+ }}
50
+ >
51
+ <Image source={{ uri }} style={{ width: '100%', height: '100%' }} resizeMode="contain" />
52
+ </TouchableOpacity>
53
+ ))}
54
+ </View>
55
+ </ScrollView>
56
+ </View>
57
+ </BottomSheetModal>
58
+ );
59
+ }
60
+ );
61
+
62
+ StickerPickerSheet.displayName = 'StickerPickerSheet';
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Presentation - Text Editor Sheet
3
+ */
4
+
5
+ import React, { forwardRef, useState } from 'react';
6
+ import { View, TouchableOpacity, ScrollView } from 'react-native';
7
+ import {
8
+ BottomSheetModal,
9
+ AtomicText,
10
+ AtomicIcon,
11
+ useAppDesignTokens,
12
+ BottomSheetModalRef
13
+ } from '@umituz/react-native-design-system';
14
+ import { TextContentTab, TextStyleTab, TextTransformTab } from './TextEditorTabs';
15
+
16
+ export interface TextEditorSheetProps {
17
+ text: string;
18
+ onTextChange: (text: string) => void;
19
+ color: string;
20
+ onColorChange: (color: string) => void;
21
+ fontSize: number;
22
+ onFontSizeChange: (size: number) => void;
23
+ fontFamily: string;
24
+ onFontFamilyChange: (font: string) => void;
25
+ scale: number;
26
+ onScaleChange: (scale: number) => void;
27
+ rotation: number;
28
+ onRotationChange: (rotation: number) => void;
29
+ opacity: number;
30
+ onOpacityChange: (opacity: number) => void;
31
+ onDelete?: () => void;
32
+ onDismiss: () => void;
33
+ snapPoints?: string[];
34
+ t: (key: string) => string;
35
+ }
36
+
37
+ export const TextEditorSheet = forwardRef<BottomSheetModalRef, TextEditorSheetProps>((props, ref) => {
38
+ const tokens = useAppDesignTokens();
39
+ const [activeTab, setActiveTab] = useState<'content' | 'style' | 'transform'>('content');
40
+ const { onDismiss, snapPoints = ['75%'], t } = props;
41
+
42
+ const tabs = [
43
+ { id: 'content', label: 'Text', icon: 'text' },
44
+ { id: 'style', label: 'Style', icon: 'color-palette' },
45
+ { id: 'transform', label: 'Edit', icon: 'options' },
46
+ ];
47
+
48
+ return (
49
+ <BottomSheetModal ref={ref} snapPoints={snapPoints} onDismiss={onDismiss}>
50
+ <View style={{ padding: tokens.spacing.lg, flex: 1 }}>
51
+ <View style={{ flexDirection: 'row', gap: tokens.spacing.md, marginBottom: tokens.spacing.lg }}>
52
+ {tabs.map(tab => (
53
+ <TouchableOpacity
54
+ key={tab.id}
55
+ onPress={() => setActiveTab(tab.id as any)}
56
+ style={{
57
+ flex: 1, alignItems: 'center', paddingVertical: tokens.spacing.sm,
58
+ borderBottomWidth: 3, borderBottomColor: activeTab === tab.id ? tokens.colors.primary : 'transparent'
59
+ }}
60
+ >
61
+ <AtomicIcon name={tab.icon as any} size={20} color={activeTab === tab.id ? 'primary' : 'secondary'} />
62
+ <AtomicText style={{
63
+ ...tokens.typography.labelSmall,
64
+ color: activeTab === tab.id ? tokens.colors.primary : tokens.colors.textSecondary,
65
+ marginTop: 4
66
+ }}>
67
+ {tab.label}
68
+ </AtomicText>
69
+ </TouchableOpacity>
70
+ ))}
71
+ </View>
72
+
73
+ <ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={{ paddingBottom: 60 }}>
74
+ {activeTab === 'content' && <TextContentTab text={props.text} onTextChange={props.onTextChange} t={t} />}
75
+ {activeTab === 'style' && (
76
+ <TextStyleTab
77
+ fontSize={props.fontSize} setFontSize={props.onFontSizeChange}
78
+ color={props.color} setColor={props.onColorChange}
79
+ fontFamily={props.fontFamily} setFontFamily={props.onFontFamilyChange}
80
+ t={t}
81
+ />
82
+ )}
83
+ {activeTab === 'transform' && (
84
+ <TextTransformTab
85
+ scale={props.scale} setScale={props.onScaleChange}
86
+ rotation={props.rotation} setRotation={props.onRotationChange}
87
+ opacity={props.opacity} setOpacity={props.onOpacityChange}
88
+ onDelete={props.onDelete}
89
+ t={t}
90
+ />
91
+ )}
92
+ </ScrollView>
93
+ </View>
94
+ </BottomSheetModal>
95
+ );
96
+ });
97
+
98
+ TextEditorSheet.displayName = 'TextEditorSheet';
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Presentation - Text Editor Tabs
3
+ */
4
+
5
+ import React from 'react';
6
+ import { View, TextInput, ScrollView, TouchableOpacity } from 'react-native';
7
+ import Slider from '@react-native-community/slider';
8
+ import { AtomicText, AtomicIcon, useAppDesignTokens } from '@umituz/react-native-design-system';
9
+
10
+ interface TabProps {
11
+ t: (key: string) => string;
12
+ }
13
+
14
+ export const TextContentTab: React.FC<TabProps & { text: string; onTextChange: (t: string) => void }> = ({ text, onTextChange, t }) => {
15
+ const tokens = useAppDesignTokens();
16
+ return (
17
+ <View style={{ gap: tokens.spacing.lg }}>
18
+ <TextInput
19
+ value={text}
20
+ onChangeText={onTextChange}
21
+ placeholder={t('editor.text_placeholder')}
22
+ style={{
23
+ ...tokens.typography.bodyLarge,
24
+ borderWidth: 1,
25
+ borderColor: tokens.colors.border,
26
+ borderRadius: tokens.borderRadius.md,
27
+ padding: tokens.spacing.md,
28
+ minHeight: 120,
29
+ textAlignVertical: 'top',
30
+ }}
31
+ multiline
32
+ />
33
+ </View>
34
+ );
35
+ };
36
+
37
+ export const TextStyleTab: React.FC<TabProps & {
38
+ fontSize: number; setFontSize: (s: number) => void;
39
+ color: string; setColor: (c: string) => void;
40
+ fontFamily: string; setFontFamily: (f: string) => void;
41
+ }> = ({ fontSize, setFontSize, color, setColor, fontFamily, setFontFamily, t }) => {
42
+ const tokens = useAppDesignTokens();
43
+ const colors = ['#FFFFFF', '#000000', '#FF0000', '#FFFF00', '#0000FF', '#00FF00', '#FF00FF', '#FFA500'];
44
+ const fonts = ['System', 'serif', 'sans-serif', 'monospace'];
45
+
46
+ return (
47
+ <View style={{ gap: tokens.spacing.xl }}>
48
+ <View>
49
+ <AtomicText style={{ ...tokens.typography.labelMedium, marginBottom: tokens.spacing.sm }}>Font</AtomicText>
50
+ <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ gap: tokens.spacing.sm }}>
51
+ {fonts.map(f => (
52
+ <TouchableOpacity key={f} onPress={() => setFontFamily(f)} style={{
53
+ paddingHorizontal: tokens.spacing.md, paddingVertical: tokens.spacing.xs, borderRadius: tokens.borderRadius.full,
54
+ borderWidth: 1, borderColor: fontFamily === f ? tokens.colors.primary : tokens.colors.border,
55
+ backgroundColor: fontFamily === f ? tokens.colors.primaryContainer : tokens.colors.surface
56
+ }}>
57
+ <AtomicText style={{ fontFamily: f }}>{f}</AtomicText>
58
+ </TouchableOpacity>
59
+ ))}
60
+ </ScrollView>
61
+ </View>
62
+
63
+ <View>
64
+ <AtomicText style={{ ...tokens.typography.labelMedium, marginBottom: tokens.spacing.sm }}>Color</AtomicText>
65
+ <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ gap: tokens.spacing.sm }}>
66
+ {colors.map(c => (
67
+ <TouchableOpacity key={c} onPress={() => setColor(c)} style={{
68
+ width: 40, height: 40, borderRadius: 20, backgroundColor: c,
69
+ borderWidth: color === c ? 3 : 1, borderColor: tokens.colors.primary
70
+ }} />
71
+ ))}
72
+ </ScrollView>
73
+ </View>
74
+
75
+ <View>
76
+ <AtomicText style={{ ...tokens.typography.labelMedium, marginBottom: tokens.spacing.xs }}>Size: {fontSize}px</AtomicText>
77
+ <Slider value={fontSize} onValueChange={setFontSize} minimumValue={12} maximumValue={100} step={1} minimumTrackTintColor={tokens.colors.primary} />
78
+ </View>
79
+ </View>
80
+ );
81
+ };
82
+
83
+ export const TextTransformTab: React.FC<TabProps & {
84
+ scale: number; setScale: (s: number) => void;
85
+ rotation: number; setRotation: (r: number) => void;
86
+ opacity: number; setOpacity: (o: number) => void;
87
+ onDelete?: () => void;
88
+ }> = ({ scale, setScale, rotation, setRotation, opacity, setOpacity, onDelete, t }) => {
89
+ const tokens = useAppDesignTokens();
90
+ return (
91
+ <View style={{ gap: tokens.spacing.xl }}>
92
+ <View>
93
+ <AtomicText style={{ ...tokens.typography.labelMedium, marginBottom: tokens.spacing.xs }}>Scale: {scale.toFixed(2)}x</AtomicText>
94
+ <Slider value={scale} onValueChange={setScale} minimumValue={0.2} maximumValue={3} step={0.1} minimumTrackTintColor={tokens.colors.primary} />
95
+ </View>
96
+ <View>
97
+ <AtomicText style={{ ...tokens.typography.labelMedium, marginBottom: tokens.spacing.xs }}>Rotation: {Math.round(rotation)}°</AtomicText>
98
+ <Slider value={rotation} onValueChange={setRotation} minimumValue={0} maximumValue={360} step={1} minimumTrackTintColor={tokens.colors.primary} />
99
+ </View>
100
+ {onDelete && (
101
+ <TouchableOpacity onPress={onDelete} style={{
102
+ flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: tokens.spacing.sm,
103
+ padding: tokens.spacing.md, borderRadius: tokens.borderRadius.md, borderWidth: 1, borderColor: tokens.colors.error
104
+ }}>
105
+ <AtomicIcon name="trash" size={20} color="error" />
106
+ <AtomicText style={{ ...tokens.typography.labelMedium, color: tokens.colors.error }}>Delete Layer</AtomicText>
107
+ </TouchableOpacity>
108
+ )}
109
+ </View>
110
+ );
111
+ };
@@ -7,36 +7,33 @@
7
7
  import { useImageTransform } from './useImageTransform';
8
8
  import { useImageConversion } from './useImageConversion';
9
9
  import { useImageBatch } from './useImageBatch';
10
- import { useImageAIEnhancement } from './useImageAIEnhancement';
10
+ import { useImageEnhance } from './useImageEnhance';
11
11
  import { useImageMetadata } from './useImageMetadata';
12
12
 
13
13
  export const useImage = () => {
14
14
  const transform = useImageTransform();
15
15
  const conversion = useImageConversion();
16
16
  const batch = useImageBatch();
17
- const aiEnhancement = useImageAIEnhancement();
17
+ const enhance = useImageEnhance();
18
18
  const metadata = useImageMetadata();
19
19
 
20
20
  return {
21
- // Basic operations
22
21
  ...transform,
23
22
  ...conversion,
24
- // Advanced operations
25
23
  ...batch,
26
- ...aiEnhancement,
24
+ ...enhance,
27
25
  ...metadata,
28
- // Combined state
29
26
  isProcessing:
30
27
  transform.isTransforming ||
31
28
  conversion.isConverting ||
32
29
  batch.isBatchProcessing ||
33
- aiEnhancement.isEnhancing ||
30
+ enhance.isEnhancing ||
34
31
  metadata.isExtracting,
35
32
  error:
36
33
  transform.transformError ||
37
34
  conversion.conversionError ||
38
35
  batch.batchError ||
39
- aiEnhancement.enhancementError ||
36
+ enhance.enhancementError ||
40
37
  metadata.metadataError,
41
38
  };
42
39
  };