@umituz/react-native-video-editor 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +92 -0
  2. package/package.json +48 -0
  3. package/src/domain/entities/index.ts +50 -0
  4. package/src/domain/entities/video-project.types.ts +153 -0
  5. package/src/index.ts +100 -0
  6. package/src/infrastructure/constants/animation-layer.constants.ts +32 -0
  7. package/src/infrastructure/constants/audio-layer.constants.ts +14 -0
  8. package/src/infrastructure/constants/export.constants.ts +28 -0
  9. package/src/infrastructure/constants/image-layer.constants.ts +12 -0
  10. package/src/infrastructure/constants/index.ts +11 -0
  11. package/src/infrastructure/constants/shape-layer.constants.ts +29 -0
  12. package/src/infrastructure/constants/text-layer.constants.ts +40 -0
  13. package/src/infrastructure/services/export-orchestrator.service.ts +122 -0
  14. package/src/infrastructure/services/image-layer-operations.service.ts +108 -0
  15. package/src/infrastructure/services/layer-manipulation.service.ts +93 -0
  16. package/src/infrastructure/services/layer-operations/index.ts +9 -0
  17. package/src/infrastructure/services/layer-operations/layer-delete.service.ts +47 -0
  18. package/src/infrastructure/services/layer-operations/layer-duplicate.service.ts +66 -0
  19. package/src/infrastructure/services/layer-operations/layer-order.service.ts +82 -0
  20. package/src/infrastructure/services/layer-operations/layer-transform.service.ts +160 -0
  21. package/src/infrastructure/services/layer-operations.service.ts +198 -0
  22. package/src/infrastructure/services/scene-operations.service.ts +166 -0
  23. package/src/infrastructure/services/shape-layer-operations.service.ts +65 -0
  24. package/src/infrastructure/services/text-layer-operations.service.ts +114 -0
  25. package/src/presentation/components/AnimationEditor.tsx +103 -0
  26. package/src/presentation/components/AudioEditor.tsx +144 -0
  27. package/src/presentation/components/DraggableLayer.tsx +110 -0
  28. package/src/presentation/components/EditorHeader.tsx +107 -0
  29. package/src/presentation/components/EditorPreviewArea.tsx +221 -0
  30. package/src/presentation/components/EditorTimeline.tsx +136 -0
  31. package/src/presentation/components/EditorToolPanel.tsx +180 -0
  32. package/src/presentation/components/ExportDialog.tsx +135 -0
  33. package/src/presentation/components/ImageLayerEditor.tsx +95 -0
  34. package/src/presentation/components/LayerActionsMenu.tsx +197 -0
  35. package/src/presentation/components/SceneActionsMenu.tsx +69 -0
  36. package/src/presentation/components/ShapeLayerEditor.tsx +108 -0
  37. package/src/presentation/components/TextLayerEditor.tsx +104 -0
  38. package/src/presentation/components/animation-layer/AnimationEditorActions.tsx +104 -0
  39. package/src/presentation/components/animation-layer/AnimationInfoBanner.tsx +43 -0
  40. package/src/presentation/components/animation-layer/AnimationTypeSelector.tsx +105 -0
  41. package/src/presentation/components/animation-layer/index.ts +8 -0
  42. package/src/presentation/components/audio-layer/AudioEditorActions.tsx +115 -0
  43. package/src/presentation/components/audio-layer/AudioFileSelector.tsx +126 -0
  44. package/src/presentation/components/audio-layer/FadeEffectsSelector.tsx +151 -0
  45. package/src/presentation/components/audio-layer/InfoBanner.tsx +43 -0
  46. package/src/presentation/components/audio-layer/VolumeSelector.tsx +98 -0
  47. package/src/presentation/components/audio-layer/index.ts +10 -0
  48. package/src/presentation/components/draggable-layer/LayerContent.tsx +106 -0
  49. package/src/presentation/components/draggable-layer/ResizeHandles.tsx +97 -0
  50. package/src/presentation/components/draggable-layer/index.ts +7 -0
  51. package/src/presentation/components/export/ExportActions.tsx +101 -0
  52. package/src/presentation/components/export/ExportInfoBanner.tsx +44 -0
  53. package/src/presentation/components/export/ExportProgress.tsx +114 -0
  54. package/src/presentation/components/export/OptionSelectorRow.tsx +101 -0
  55. package/src/presentation/components/export/ProjectInfoBox.tsx +61 -0
  56. package/src/presentation/components/export/WatermarkToggle.tsx +87 -0
  57. package/src/presentation/components/export/index.ts +11 -0
  58. package/src/presentation/components/image-layer/ImagePreview.tsx +70 -0
  59. package/src/presentation/components/image-layer/ImageSelectionButtons.tsx +82 -0
  60. package/src/presentation/components/image-layer/OpacitySelector.tsx +91 -0
  61. package/src/presentation/components/image-layer/index.ts +8 -0
  62. package/src/presentation/components/index.ts +17 -0
  63. package/src/presentation/components/shape-layer/ColorPickerHorizontal.tsx +92 -0
  64. package/src/presentation/components/shape-layer/ShapePreview.tsx +57 -0
  65. package/src/presentation/components/shape-layer/ShapeTypeSelector.tsx +102 -0
  66. package/src/presentation/components/shape-layer/ValueSelector.tsx +106 -0
  67. package/src/presentation/components/shape-layer/index.ts +9 -0
  68. package/src/presentation/components/text-layer/ColorPicker.tsx +91 -0
  69. package/src/presentation/components/text-layer/EditorActions.tsx +95 -0
  70. package/src/presentation/components/text-layer/FontSizeSelector.tsx +86 -0
  71. package/src/presentation/components/text-layer/OptionSelector.tsx +98 -0
  72. package/src/presentation/components/text-layer/TextAlignSelector.tsx +87 -0
  73. package/src/presentation/components/text-layer/TextInputSection.tsx +70 -0
  74. package/src/presentation/components/text-layer/TextPreview.tsx +71 -0
  75. package/src/presentation/components/text-layer/index.ts +12 -0
  76. package/src/presentation/hooks/useAnimationLayerForm.ts +72 -0
  77. package/src/presentation/hooks/useAudioLayerForm.ts +76 -0
  78. package/src/presentation/hooks/useDraggableLayerGestures.ts +166 -0
  79. package/src/presentation/hooks/useEditorActions.tsx +93 -0
  80. package/src/presentation/hooks/useEditorBottomSheet.ts +43 -0
  81. package/src/presentation/hooks/useEditorHistory.ts +80 -0
  82. package/src/presentation/hooks/useEditorLayers.ts +97 -0
  83. package/src/presentation/hooks/useEditorPlayback.ts +90 -0
  84. package/src/presentation/hooks/useEditorScenes.ts +106 -0
  85. package/src/presentation/hooks/useExport.ts +67 -0
  86. package/src/presentation/hooks/useExportActions.tsx +51 -0
  87. package/src/presentation/hooks/useExportForm.ts +96 -0
  88. package/src/presentation/hooks/useImageLayerForm.ts +57 -0
  89. package/src/presentation/hooks/useImageLayerOperations.ts +71 -0
  90. package/src/presentation/hooks/useLayerActions.tsx +162 -0
  91. package/src/presentation/hooks/useLayerManipulation.ts +178 -0
  92. package/src/presentation/hooks/useMenuActions.tsx +92 -0
  93. package/src/presentation/hooks/useSceneActions.tsx +81 -0
  94. package/src/presentation/hooks/useShapeLayerForm.ts +84 -0
  95. package/src/presentation/hooks/useShapeLayerOperations.ts +52 -0
  96. package/src/presentation/hooks/useTextLayerForm.ts +100 -0
  97. package/src/presentation/hooks/useTextLayerOperations.ts +74 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * ColorPickerHorizontal Component
3
+ * Horizontal scrolling color picker for shape layer
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, ScrollView, StyleSheet, TouchableOpacity } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicIcon,
11
+ useAppDesignTokens,
12
+ } from "@umituz/react-native-design-system";
13
+ import { SHAPE_COLORS } from "../../../constants/shape-layer.constants";
14
+
15
+ interface ColorPickerHorizontalProps {
16
+ title: string;
17
+ selectedColor: string;
18
+ onColorChange: (color: string) => void;
19
+ }
20
+
21
+ export const ColorPickerHorizontal: React.FC<ColorPickerHorizontalProps> = ({
22
+ title,
23
+ selectedColor,
24
+ onColorChange,
25
+ }) => {
26
+ const tokens = useAppDesignTokens();
27
+
28
+ return (
29
+ <View style={styles.section}>
30
+ <AtomicText
31
+ type="bodyMedium"
32
+ style={{
33
+ color: tokens.colors.textPrimary,
34
+ fontWeight: "600",
35
+ marginBottom: 12,
36
+ }}
37
+ >
38
+ {title}
39
+ </AtomicText>
40
+
41
+ <ScrollView
42
+ horizontal
43
+ showsHorizontalScrollIndicator={false}
44
+ style={styles.colorsScroll}
45
+ >
46
+ {SHAPE_COLORS.map((color) => (
47
+ <TouchableOpacity
48
+ key={color.value}
49
+ style={[
50
+ styles.colorButton,
51
+ {
52
+ backgroundColor: color.value,
53
+ borderColor:
54
+ selectedColor === color.value
55
+ ? tokens.colors.primary
56
+ : "#E5E7EB",
57
+ borderWidth: selectedColor === color.value ? 3 : 2,
58
+ },
59
+ ]}
60
+ onPress={() => onColorChange(color.value)}
61
+ >
62
+ {selectedColor === color.value && (
63
+ <AtomicIcon
64
+ name="Check"
65
+ size="sm"
66
+ color={color.value === "#FFFFFF" ? "primary" : "onSurface"}
67
+ />
68
+ )}
69
+ </TouchableOpacity>
70
+ ))}
71
+ </ScrollView>
72
+ </View>
73
+ );
74
+ };
75
+
76
+ const styles = StyleSheet.create({
77
+ section: {
78
+ marginBottom: 24,
79
+ },
80
+ colorsScroll: {
81
+ marginHorizontal: -16,
82
+ paddingHorizontal: 16,
83
+ },
84
+ colorButton: {
85
+ width: 50,
86
+ height: 50,
87
+ borderRadius: 25,
88
+ marginRight: 12,
89
+ alignItems: "center",
90
+ justifyContent: "center",
91
+ },
92
+ });
@@ -0,0 +1,57 @@
1
+ /**
2
+ * ShapePreview Component
3
+ * Preview section for shape layer
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, StyleSheet } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ useAppDesignTokens,
11
+ } from "@umituz/react-native-design-system";
12
+ import type { ShapeType } from "../../../constants/shape-layer.constants";
13
+ import type { ShapeLayerFormState } from "../../../hooks/useShapeLayerForm";
14
+
15
+ interface ShapePreviewProps {
16
+ formState: ShapeLayerFormState;
17
+ }
18
+
19
+ export const ShapePreview: React.FC<ShapePreviewProps> = ({ formState }) => {
20
+ const tokens = useAppDesignTokens();
21
+
22
+ return (
23
+ <View style={[styles.preview, { backgroundColor: tokens.colors.surface }]}>
24
+ <AtomicText
25
+ type="labelSmall"
26
+ style={{ color: tokens.colors.textSecondary, marginBottom: 12 }}
27
+ >
28
+ Preview
29
+ </AtomicText>
30
+ <View
31
+ style={[
32
+ styles.previewShape,
33
+ {
34
+ backgroundColor: formState.fillColor,
35
+ borderColor: formState.borderColor,
36
+ borderWidth: formState.borderWidth,
37
+ borderRadius: formState.shape === "circle" ? 50 : 0,
38
+ opacity: formState.opacity,
39
+ },
40
+ ]}
41
+ />
42
+ </View>
43
+ );
44
+ };
45
+
46
+ const styles = StyleSheet.create({
47
+ preview: {
48
+ padding: 16,
49
+ borderRadius: 12,
50
+ alignItems: "center",
51
+ marginBottom: 16,
52
+ },
53
+ previewShape: {
54
+ width: 100,
55
+ height: 100,
56
+ },
57
+ });
@@ -0,0 +1,102 @@
1
+ /**
2
+ * ShapeTypeSelector Component
3
+ * Shape type selector for shape layer
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, StyleSheet, TouchableOpacity } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicIcon,
11
+ useAppDesignTokens,
12
+ } from "@umituz/react-native-design-system";
13
+ import {
14
+ SHAPES,
15
+ type ShapeType,
16
+ } from "../../../constants/shape-layer.constants";
17
+
18
+ interface ShapeTypeSelectorProps {
19
+ selectedShape: ShapeType;
20
+ onShapeChange: (shape: ShapeType) => void;
21
+ }
22
+
23
+ export const ShapeTypeSelector: React.FC<ShapeTypeSelectorProps> = ({
24
+ selectedShape,
25
+ onShapeChange,
26
+ }) => {
27
+ const tokens = useAppDesignTokens();
28
+
29
+ return (
30
+ <View style={styles.section}>
31
+ <AtomicText
32
+ type="bodyMedium"
33
+ style={{
34
+ color: tokens.colors.textPrimary,
35
+ fontWeight: "600",
36
+ marginBottom: 12,
37
+ }}
38
+ >
39
+ Shape Type
40
+ </AtomicText>
41
+
42
+ <View style={styles.shapesRow}>
43
+ {SHAPES.map((s) => (
44
+ <TouchableOpacity
45
+ key={s.type}
46
+ style={[
47
+ styles.shapeCard,
48
+ {
49
+ backgroundColor:
50
+ selectedShape === s.type
51
+ ? tokens.colors.primary
52
+ : tokens.colors.surface,
53
+ borderColor:
54
+ selectedShape === s.type
55
+ ? tokens.colors.primary
56
+ : tokens.colors.borderLight,
57
+ },
58
+ ]}
59
+ onPress={() => onShapeChange(s.type)}
60
+ >
61
+ <AtomicIcon
62
+ name={s.icon as any}
63
+ size="lg"
64
+ color={selectedShape === s.type ? "onSurface" : "primary"}
65
+ />
66
+ <AtomicText
67
+ type="labelSmall"
68
+ style={{
69
+ color:
70
+ selectedShape === s.type
71
+ ? "#FFFFFF"
72
+ : tokens.colors.textPrimary,
73
+ marginTop: 8,
74
+ fontWeight: selectedShape === s.type ? "600" : "400",
75
+ }}
76
+ >
77
+ {s.label}
78
+ </AtomicText>
79
+ </TouchableOpacity>
80
+ ))}
81
+ </View>
82
+ </View>
83
+ );
84
+ };
85
+
86
+ const styles = StyleSheet.create({
87
+ section: {
88
+ marginBottom: 24,
89
+ },
90
+ shapesRow: {
91
+ flexDirection: "row",
92
+ gap: 12,
93
+ },
94
+ shapeCard: {
95
+ flex: 1,
96
+ padding: 16,
97
+ borderRadius: 12,
98
+ borderWidth: 2,
99
+ alignItems: "center",
100
+ justifyContent: "center",
101
+ },
102
+ });
@@ -0,0 +1,106 @@
1
+ /**
2
+ * ValueSelector Component
3
+ * Reusable selector for border width, opacity, etc.
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, StyleSheet, TouchableOpacity } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ useAppDesignTokens,
11
+ } from "@umituz/react-native-design-system";
12
+
13
+ interface ValueSelectorProps {
14
+ title: string;
15
+ value: number;
16
+ options: number[];
17
+ formatValue: (value: number) => string;
18
+ onValueChange: (value: number) => void;
19
+ }
20
+
21
+ export const ValueSelector: React.FC<ValueSelectorProps> = ({
22
+ title,
23
+ value,
24
+ options,
25
+ formatValue,
26
+ onValueChange,
27
+ }) => {
28
+ const tokens = useAppDesignTokens();
29
+
30
+ return (
31
+ <View style={styles.section}>
32
+ <View style={styles.sectionHeader}>
33
+ <AtomicText
34
+ type="bodyMedium"
35
+ style={{ color: tokens.colors.textPrimary, fontWeight: "600" }}
36
+ >
37
+ {title}
38
+ </AtomicText>
39
+ <AtomicText
40
+ type="bodyMedium"
41
+ style={{ color: tokens.colors.primary, fontWeight: "600" }}
42
+ >
43
+ {formatValue(value)}
44
+ </AtomicText>
45
+ </View>
46
+
47
+ <View style={styles.optionsGrid}>
48
+ {options.map((option) => (
49
+ <TouchableOpacity
50
+ key={option}
51
+ style={[
52
+ styles.optionButton,
53
+ {
54
+ backgroundColor:
55
+ value === option
56
+ ? tokens.colors.primary
57
+ : tokens.colors.surface,
58
+ borderColor:
59
+ value === option
60
+ ? tokens.colors.primary
61
+ : tokens.colors.borderLight,
62
+ },
63
+ ]}
64
+ onPress={() => onValueChange(option)}
65
+ >
66
+ <AtomicText
67
+ type="labelSmall"
68
+ style={{
69
+ color: value === option ? "#FFFFFF" : tokens.colors.textPrimary,
70
+ fontWeight: value === option ? "600" : "400",
71
+ }}
72
+ >
73
+ {formatValue(option)}
74
+ </AtomicText>
75
+ </TouchableOpacity>
76
+ ))}
77
+ </View>
78
+ </View>
79
+ );
80
+ };
81
+
82
+ const styles = StyleSheet.create({
83
+ section: {
84
+ marginBottom: 24,
85
+ },
86
+ sectionHeader: {
87
+ flexDirection: "row",
88
+ justifyContent: "space-between",
89
+ marginBottom: 12,
90
+ },
91
+ optionsGrid: {
92
+ flexDirection: "row",
93
+ flexWrap: "wrap",
94
+ gap: 8,
95
+ },
96
+ optionButton: {
97
+ flex: 1,
98
+ minWidth: "30%",
99
+ paddingVertical: 12,
100
+ paddingHorizontal: 8,
101
+ borderRadius: 8,
102
+ borderWidth: 1,
103
+ alignItems: "center",
104
+ justifyContent: "center",
105
+ },
106
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shape Layer Editor Components
3
+ * Barrel file for shape layer editor components
4
+ */
5
+
6
+ export { ShapeTypeSelector } from "./ShapeTypeSelector";
7
+ export { ColorPickerHorizontal } from "./ColorPickerHorizontal";
8
+ export { ValueSelector } from "./ValueSelector";
9
+ export { ShapePreview } from "./ShapePreview";
@@ -0,0 +1,91 @@
1
+ /**
2
+ * ColorPicker Component
3
+ * Color picker for text layer
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, StyleSheet, TouchableOpacity } from "react-native";
8
+ import { useLocalization } from "@umituz/react-native-localization";
9
+ import {
10
+ AtomicText,
11
+ AtomicIcon,
12
+ useAppDesignTokens,
13
+ } from "@umituz/react-native-design-system";
14
+ import { TEXT_COLORS } from "../../../constants/text-layer.constants";
15
+
16
+ interface ColorPickerProps {
17
+ selectedColor: string;
18
+ onColorChange: (color: string) => void;
19
+ }
20
+
21
+ export const ColorPicker: React.FC<ColorPickerProps> = ({
22
+ selectedColor,
23
+ onColorChange,
24
+ }) => {
25
+ const { t } = useLocalization();
26
+ const tokens = useAppDesignTokens();
27
+
28
+ return (
29
+ <View style={styles.section}>
30
+ <AtomicText
31
+ type="bodyMedium"
32
+ style={{
33
+ color: tokens.colors.textPrimary,
34
+ fontWeight: "600",
35
+ marginBottom: 8,
36
+ }}
37
+ >
38
+ {t("editor.properties.color")}
39
+ </AtomicText>
40
+ <View style={styles.colorGrid}>
41
+ {TEXT_COLORS.map((color) => (
42
+ <TouchableOpacity
43
+ key={color}
44
+ style={[
45
+ styles.colorButton,
46
+ {
47
+ backgroundColor: color,
48
+ borderColor:
49
+ selectedColor === color
50
+ ? tokens.colors.primary
51
+ : tokens.colors.borderLight,
52
+ borderWidth: selectedColor === color ? 3 : 1,
53
+ },
54
+ ]}
55
+ onPress={() => onColorChange(color)}
56
+ >
57
+ {selectedColor === color && (
58
+ <AtomicIcon
59
+ name="Check"
60
+ size="sm"
61
+ color={
62
+ color === "#FFFFFF" || color === "#FCD34D"
63
+ ? "primary"
64
+ : "onSurface"
65
+ }
66
+ />
67
+ )}
68
+ </TouchableOpacity>
69
+ ))}
70
+ </View>
71
+ </View>
72
+ );
73
+ };
74
+
75
+ const styles = StyleSheet.create({
76
+ section: {
77
+ marginBottom: 24,
78
+ },
79
+ colorGrid: {
80
+ flexDirection: "row",
81
+ flexWrap: "wrap",
82
+ gap: 12,
83
+ },
84
+ colorButton: {
85
+ width: 50,
86
+ height: 50,
87
+ borderRadius: 25,
88
+ alignItems: "center",
89
+ justifyContent: "center",
90
+ },
91
+ });
@@ -0,0 +1,95 @@
1
+ /**
2
+ * EditorActions Component
3
+ * Action buttons for layer editors
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, StyleSheet, TouchableOpacity } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicIcon,
11
+ useAppDesignTokens,
12
+ } from "@umituz/react-native-design-system";
13
+ import { useLocalization } from "@umituz/react-native-localization";
14
+
15
+ interface EditorActionsProps {
16
+ onCancel: () => void;
17
+ onSave: () => void;
18
+ saveLabel: string;
19
+ isValid: boolean;
20
+ }
21
+
22
+ export const EditorActions: React.FC<EditorActionsProps> = ({
23
+ onCancel,
24
+ onSave,
25
+ saveLabel,
26
+ isValid,
27
+ }) => {
28
+ const tokens = useAppDesignTokens();
29
+ const { t } = useLocalization();
30
+
31
+ return (
32
+ <View
33
+ style={[styles.actions, { borderTopColor: tokens.colors.borderLight }]}
34
+ >
35
+ <TouchableOpacity
36
+ style={[
37
+ styles.actionButton,
38
+ styles.cancelButton,
39
+ { borderColor: tokens.colors.borderLight },
40
+ ]}
41
+ onPress={onCancel}
42
+ >
43
+ <AtomicText
44
+ type="bodyMedium"
45
+ style={{ color: tokens.colors.textSecondary }}
46
+ >
47
+ {t("common.buttons.cancel", "Cancel")}
48
+ </AtomicText>
49
+ </TouchableOpacity>
50
+
51
+ <TouchableOpacity
52
+ style={[
53
+ styles.actionButton,
54
+ styles.saveButton,
55
+ {
56
+ backgroundColor: isValid
57
+ ? tokens.colors.primary
58
+ : tokens.colors.borderLight,
59
+ },
60
+ ]}
61
+ onPress={onSave}
62
+ disabled={!isValid}
63
+ >
64
+ <AtomicText
65
+ type="bodyMedium"
66
+ style={{ color: tokens.colors.onPrimary, fontWeight: "600" }}
67
+ >
68
+ {saveLabel}
69
+ </AtomicText>
70
+ </TouchableOpacity>
71
+ </View>
72
+ );
73
+ };
74
+
75
+ const styles = StyleSheet.create({
76
+ actions: {
77
+ flexDirection: "row",
78
+ gap: 12,
79
+ paddingTop: 16,
80
+ borderTopWidth: 1,
81
+ },
82
+ actionButton: {
83
+ flex: 1,
84
+ paddingVertical: 14,
85
+ borderRadius: 12,
86
+ alignItems: "center",
87
+ justifyContent: "center",
88
+ },
89
+ cancelButton: {
90
+ borderWidth: 1,
91
+ },
92
+ saveButton: {
93
+ // backgroundColor set dynamically
94
+ },
95
+ });
@@ -0,0 +1,86 @@
1
+ /**
2
+ * FontSizeSelector Component
3
+ * Font size selector for text layer
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, ScrollView, TouchableOpacity, StyleSheet } from "react-native";
8
+ import { useLocalization } from "@umituz/react-native-localization";
9
+ import {
10
+ AtomicText,
11
+ useAppDesignTokens,
12
+ } from "@umituz/react-native-design-system";
13
+ import { FONT_SIZES } from "../../../constants/text-layer.constants";
14
+
15
+ interface FontSizeSelectorProps {
16
+ fontSize: number;
17
+ onFontSizeChange: (size: number) => void;
18
+ }
19
+
20
+ export const FontSizeSelector: React.FC<FontSizeSelectorProps> = ({
21
+ fontSize,
22
+ onFontSizeChange,
23
+ }) => {
24
+ const { t } = useLocalization();
25
+ const tokens = useAppDesignTokens();
26
+
27
+ return (
28
+ <View style={styles.section}>
29
+ <AtomicText
30
+ type="bodyMedium"
31
+ style={{
32
+ color: tokens.colors.textPrimary,
33
+ fontWeight: "600",
34
+ marginBottom: 8,
35
+ }}
36
+ >
37
+ {t("editor.properties.font_size")}: {fontSize}px
38
+ </AtomicText>
39
+ <ScrollView horizontal showsHorizontalScrollIndicator={false}>
40
+ {FONT_SIZES.map((size) => (
41
+ <TouchableOpacity
42
+ key={size}
43
+ style={[
44
+ styles.sizeButton,
45
+ {
46
+ backgroundColor:
47
+ fontSize === size
48
+ ? tokens.colors.primary
49
+ : tokens.colors.surface,
50
+ borderColor:
51
+ fontSize === size
52
+ ? tokens.colors.primary
53
+ : tokens.colors.borderLight,
54
+ },
55
+ ]}
56
+ onPress={() => onFontSizeChange(size)}
57
+ >
58
+ <AtomicText
59
+ type="bodySmall"
60
+ style={{
61
+ color:
62
+ fontSize === size ? "#FFFFFF" : tokens.colors.textPrimary,
63
+ fontWeight: fontSize === size ? "600" : "400",
64
+ }}
65
+ >
66
+ {size}
67
+ </AtomicText>
68
+ </TouchableOpacity>
69
+ ))}
70
+ </ScrollView>
71
+ </View>
72
+ );
73
+ };
74
+
75
+ const styles = StyleSheet.create({
76
+ section: {
77
+ marginBottom: 24,
78
+ },
79
+ sizeButton: {
80
+ paddingHorizontal: 16,
81
+ paddingVertical: 10,
82
+ borderRadius: 8,
83
+ borderWidth: 1,
84
+ marginRight: 8,
85
+ },
86
+ });