@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,151 @@
1
+ /**
2
+ * FadeEffectsSelector Component
3
+ * Fade in/out effects selector for audio layer
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
+ import {
13
+ FADE_IN_OPTIONS,
14
+ FADE_OUT_OPTIONS,
15
+ } from "../../../constants/audio-layer.constants";
16
+
17
+ interface FadeEffectsSelectorProps {
18
+ fadeIn: number;
19
+ fadeOut: number;
20
+ onFadeInChange: (fadeIn: number) => void;
21
+ onFadeOutChange: (fadeOut: number) => void;
22
+ }
23
+
24
+ export const FadeEffectsSelector: React.FC<FadeEffectsSelectorProps> = ({
25
+ fadeIn,
26
+ fadeOut,
27
+ onFadeInChange,
28
+ onFadeOutChange,
29
+ }) => {
30
+ const tokens = useAppDesignTokens();
31
+
32
+ return (
33
+ <View style={styles.section}>
34
+ <AtomicText
35
+ type="bodyMedium"
36
+ style={{
37
+ color: tokens.colors.textPrimary,
38
+ fontWeight: "600",
39
+ marginBottom: 8,
40
+ }}
41
+ >
42
+ Fade Effects (ms)
43
+ </AtomicText>
44
+
45
+ <View style={styles.fadeRow}>
46
+ <View style={{ flex: 1 }}>
47
+ <AtomicText
48
+ type="labelSmall"
49
+ style={{ color: tokens.colors.textSecondary, marginBottom: 6 }}
50
+ >
51
+ Fade In
52
+ </AtomicText>
53
+ <View style={styles.fadeButtons}>
54
+ {FADE_IN_OPTIONS.map((val) => (
55
+ <TouchableOpacity
56
+ key={`in-${val}`}
57
+ style={[
58
+ styles.fadeButton,
59
+ {
60
+ backgroundColor:
61
+ fadeIn === val
62
+ ? tokens.colors.primary
63
+ : tokens.colors.surface,
64
+ borderColor:
65
+ fadeIn === val
66
+ ? tokens.colors.primary
67
+ : tokens.colors.borderLight,
68
+ },
69
+ ]}
70
+ onPress={() => onFadeInChange(val)}
71
+ >
72
+ <AtomicText
73
+ type="labelSmall"
74
+ style={{
75
+ color:
76
+ fadeIn === val ? "#FFFFFF" : tokens.colors.textPrimary,
77
+ fontSize: 11,
78
+ }}
79
+ >
80
+ {val}
81
+ </AtomicText>
82
+ </TouchableOpacity>
83
+ ))}
84
+ </View>
85
+ </View>
86
+
87
+ <View style={{ flex: 1, marginLeft: 12 }}>
88
+ <AtomicText
89
+ type="labelSmall"
90
+ style={{ color: tokens.colors.textSecondary, marginBottom: 6 }}
91
+ >
92
+ Fade Out
93
+ </AtomicText>
94
+ <View style={styles.fadeButtons}>
95
+ {FADE_OUT_OPTIONS.map((val) => (
96
+ <TouchableOpacity
97
+ key={`out-${val}`}
98
+ style={[
99
+ styles.fadeButton,
100
+ {
101
+ backgroundColor:
102
+ fadeOut === val
103
+ ? tokens.colors.primary
104
+ : tokens.colors.surface,
105
+ borderColor:
106
+ fadeOut === val
107
+ ? tokens.colors.primary
108
+ : tokens.colors.borderLight,
109
+ },
110
+ ]}
111
+ onPress={() => onFadeOutChange(val)}
112
+ >
113
+ <AtomicText
114
+ type="labelSmall"
115
+ style={{
116
+ color:
117
+ fadeOut === val ? "#FFFFFF" : tokens.colors.textPrimary,
118
+ fontSize: 11,
119
+ }}
120
+ >
121
+ {val}
122
+ </AtomicText>
123
+ </TouchableOpacity>
124
+ ))}
125
+ </View>
126
+ </View>
127
+ </View>
128
+ </View>
129
+ );
130
+ };
131
+
132
+ const styles = StyleSheet.create({
133
+ section: {
134
+ marginBottom: 24,
135
+ },
136
+ fadeRow: {
137
+ flexDirection: "row",
138
+ },
139
+ fadeButtons: {
140
+ flexDirection: "row",
141
+ gap: 6,
142
+ },
143
+ fadeButton: {
144
+ flex: 1,
145
+ paddingVertical: 8,
146
+ borderRadius: 6,
147
+ borderWidth: 1,
148
+ alignItems: "center",
149
+ justifyContent: "center",
150
+ },
151
+ });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * InfoBanner Component
3
+ * Info banner for audio layer editor
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, StyleSheet } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicIcon,
11
+ useAppDesignTokens,
12
+ } from "@umituz/react-native-design-system";
13
+
14
+ export const InfoBanner: React.FC = () => {
15
+ const tokens = useAppDesignTokens();
16
+
17
+ return (
18
+ <View
19
+ style={[
20
+ styles.infoBanner,
21
+ { backgroundColor: tokens.colors.primary + "20" },
22
+ ]}
23
+ >
24
+ <AtomicIcon name="Info" size="sm" color="primary" />
25
+ <AtomicText
26
+ type="labelSmall"
27
+ style={{ color: tokens.colors.primary, marginLeft: 8, flex: 1 }}
28
+ >
29
+ Audio will play as background music for this scene
30
+ </AtomicText>
31
+ </View>
32
+ );
33
+ };
34
+
35
+ const styles = StyleSheet.create({
36
+ infoBanner: {
37
+ flexDirection: "row",
38
+ alignItems: "center",
39
+ padding: 12,
40
+ borderRadius: 8,
41
+ marginBottom: 16,
42
+ },
43
+ });
@@ -0,0 +1,98 @@
1
+ /**
2
+ * VolumeSelector Component
3
+ * Volume control for audio layer
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
+ import { VOLUME_OPTIONS } from "../../../constants/audio-layer.constants";
13
+
14
+ interface VolumeSelectorProps {
15
+ volume: number;
16
+ onVolumeChange: (volume: number) => void;
17
+ }
18
+
19
+ export const VolumeSelector: React.FC<VolumeSelectorProps> = ({
20
+ volume,
21
+ onVolumeChange,
22
+ }) => {
23
+ const tokens = useAppDesignTokens();
24
+
25
+ return (
26
+ <View style={styles.section}>
27
+ <View style={styles.sliderHeader}>
28
+ <AtomicText
29
+ type="bodyMedium"
30
+ style={{ color: tokens.colors.textPrimary, fontWeight: "600" }}
31
+ >
32
+ Volume
33
+ </AtomicText>
34
+ <AtomicText
35
+ type="bodyMedium"
36
+ style={{ color: tokens.colors.primary, fontWeight: "600" }}
37
+ >
38
+ {Math.round(volume * 100)}%
39
+ </AtomicText>
40
+ </View>
41
+
42
+ <View style={styles.volumeButtons}>
43
+ {VOLUME_OPTIONS.map((val) => (
44
+ <TouchableOpacity
45
+ key={val}
46
+ style={[
47
+ styles.volumeButton,
48
+ {
49
+ backgroundColor:
50
+ volume === val
51
+ ? tokens.colors.primary
52
+ : tokens.colors.surface,
53
+ borderColor:
54
+ volume === val
55
+ ? tokens.colors.primary
56
+ : tokens.colors.borderLight,
57
+ },
58
+ ]}
59
+ onPress={() => onVolumeChange(val)}
60
+ >
61
+ <AtomicText
62
+ type="labelSmall"
63
+ style={{
64
+ color: volume === val ? "#FFFFFF" : tokens.colors.textPrimary,
65
+ fontWeight: volume === val ? "600" : "400",
66
+ }}
67
+ >
68
+ {Math.round(val * 100)}%
69
+ </AtomicText>
70
+ </TouchableOpacity>
71
+ ))}
72
+ </View>
73
+ </View>
74
+ );
75
+ };
76
+
77
+ const styles = StyleSheet.create({
78
+ section: {
79
+ marginBottom: 24,
80
+ },
81
+ sliderHeader: {
82
+ flexDirection: "row",
83
+ justifyContent: "space-between",
84
+ marginBottom: 12,
85
+ },
86
+ volumeButtons: {
87
+ flexDirection: "row",
88
+ gap: 8,
89
+ },
90
+ volumeButton: {
91
+ flex: 1,
92
+ paddingVertical: 10,
93
+ borderRadius: 8,
94
+ borderWidth: 1,
95
+ alignItems: "center",
96
+ justifyContent: "center",
97
+ },
98
+ });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Audio Layer Editor Components
3
+ * Barrel file for audio layer editor components
4
+ */
5
+
6
+ export { AudioFileSelector } from "./AudioFileSelector";
7
+ export { VolumeSelector } from "./VolumeSelector";
8
+ export { FadeEffectsSelector } from "./FadeEffectsSelector";
9
+ export { InfoBanner } from "./InfoBanner";
10
+ export { AudioEditorActions } from "./AudioEditorActions";
@@ -0,0 +1,106 @@
1
+ /**
2
+ * LayerContent Component
3
+ * Renders different layer types (text, image, shape)
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, Image, Text as RNText, StyleSheet } from "react-native";
8
+ import {
9
+ AtomicIcon,
10
+ useAppDesignTokens,
11
+ } from "@umituz/react-native-design-system";
12
+ import type { Layer, TextLayer, ImageLayer, ShapeLayer } from "@domains/video";
13
+
14
+ interface LayerContentProps {
15
+ layer: Layer;
16
+ }
17
+
18
+ export const LayerContent: React.FC<LayerContentProps> = ({ layer }) => {
19
+ const tokens = useAppDesignTokens();
20
+
21
+ switch (layer.type) {
22
+ case "text": {
23
+ const textLayer = layer as TextLayer;
24
+ return (
25
+ <View style={styles.textContainer}>
26
+ <RNText
27
+ adjustsFontSizeToFit
28
+ minimumFontScale={0.3}
29
+ style={{
30
+ fontSize: textLayer.fontSize,
31
+ color: textLayer.color,
32
+ fontWeight: textLayer.fontWeight,
33
+ textAlign: textLayer.textAlign,
34
+ width: "100%",
35
+ height: "100%",
36
+ textAlignVertical: "center",
37
+ }}
38
+ >
39
+ {textLayer.content}
40
+ </RNText>
41
+ </View>
42
+ );
43
+ }
44
+
45
+ case "image": {
46
+ const imageLayer = layer as ImageLayer;
47
+ return imageLayer.uri ? (
48
+ <Image
49
+ source={{ uri: imageLayer.uri }}
50
+ style={styles.layerImage}
51
+ resizeMode="cover"
52
+ />
53
+ ) : (
54
+ <View style={styles.imagePlaceholder}>
55
+ <AtomicIcon name="image-outline" size="md" color="secondary" />
56
+ </View>
57
+ );
58
+ }
59
+
60
+ case "shape": {
61
+ const shapeLayer = layer as ShapeLayer;
62
+ return (
63
+ <View
64
+ style={[
65
+ styles.shapeLayer,
66
+ {
67
+ backgroundColor: shapeLayer.fillColor,
68
+ borderRadius: shapeLayer.shape === "circle" ? 9999 : 0,
69
+ borderColor: shapeLayer.borderColor,
70
+ borderWidth: shapeLayer.borderWidth || 0,
71
+ },
72
+ ]}
73
+ />
74
+ );
75
+ }
76
+
77
+ default:
78
+ return null;
79
+ }
80
+ };
81
+
82
+ const styles = StyleSheet.create({
83
+ textContainer: {
84
+ width: "100%",
85
+ height: "100%",
86
+ justifyContent: "center",
87
+ alignItems: "center",
88
+ padding: 4,
89
+ overflow: "hidden",
90
+ },
91
+ layerImage: {
92
+ width: "100%",
93
+ height: "100%",
94
+ },
95
+ imagePlaceholder: {
96
+ width: "100%",
97
+ height: "100%",
98
+ backgroundColor: "rgba(0,0,0,0.1)",
99
+ alignItems: "center",
100
+ justifyContent: "center",
101
+ },
102
+ shapeLayer: {
103
+ width: "100%",
104
+ height: "100%",
105
+ },
106
+ });
@@ -0,0 +1,97 @@
1
+ /**
2
+ * ResizeHandles Component
3
+ * Resize handles for draggable layers
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, StyleSheet } from "react-native";
8
+ import { Gesture, GestureDetector } from "react-native-gesture-handler";
9
+ import Animated from "react-native-reanimated";
10
+ import { useAppDesignTokens } from "@umituz/react-native-design-system";
11
+
12
+ interface ResizeHandlesProps {
13
+ topLeftGesture: ReturnType<typeof Gesture.Pan>;
14
+ topRightGesture: ReturnType<typeof Gesture.Pan>;
15
+ bottomLeftGesture: ReturnType<typeof Gesture.Pan>;
16
+ bottomRightGesture: ReturnType<typeof Gesture.Pan>;
17
+ }
18
+
19
+ export const ResizeHandles: React.FC<ResizeHandlesProps> = ({
20
+ topLeftGesture,
21
+ topRightGesture,
22
+ bottomLeftGesture,
23
+ bottomRightGesture,
24
+ }) => {
25
+ const tokens = useAppDesignTokens();
26
+
27
+ return (
28
+ <>
29
+ <GestureDetector gesture={topLeftGesture}>
30
+ <Animated.View
31
+ style={[
32
+ styles.handle,
33
+ styles.handleTopLeft,
34
+ { backgroundColor: tokens.colors.primary },
35
+ ]}
36
+ />
37
+ </GestureDetector>
38
+
39
+ <GestureDetector gesture={topRightGesture}>
40
+ <Animated.View
41
+ style={[
42
+ styles.handle,
43
+ styles.handleTopRight,
44
+ { backgroundColor: tokens.colors.primary },
45
+ ]}
46
+ />
47
+ </GestureDetector>
48
+
49
+ <GestureDetector gesture={bottomLeftGesture}>
50
+ <Animated.View
51
+ style={[
52
+ styles.handle,
53
+ styles.handleBottomLeft,
54
+ { backgroundColor: tokens.colors.primary },
55
+ ]}
56
+ />
57
+ </GestureDetector>
58
+
59
+ <GestureDetector gesture={bottomRightGesture}>
60
+ <Animated.View
61
+ style={[
62
+ styles.handle,
63
+ styles.handleBottomRight,
64
+ { backgroundColor: tokens.colors.primary },
65
+ ]}
66
+ />
67
+ </GestureDetector>
68
+ </>
69
+ );
70
+ };
71
+
72
+ const styles = StyleSheet.create({
73
+ handle: {
74
+ position: "absolute",
75
+ width: 12,
76
+ height: 12,
77
+ borderRadius: 6,
78
+ borderWidth: 2,
79
+ borderColor: "#FFFFFF",
80
+ },
81
+ handleTopLeft: {
82
+ top: -6,
83
+ left: -6,
84
+ },
85
+ handleTopRight: {
86
+ top: -6,
87
+ right: -6,
88
+ },
89
+ handleBottomLeft: {
90
+ bottom: -6,
91
+ left: -6,
92
+ },
93
+ handleBottomRight: {
94
+ bottom: -6,
95
+ right: -6,
96
+ },
97
+ });
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Draggable Layer Components
3
+ * Barrel file for draggable layer components
4
+ */
5
+
6
+ export { LayerContent } from "./LayerContent";
7
+ export { ResizeHandles } from "./ResizeHandles";
@@ -0,0 +1,101 @@
1
+ /**
2
+ * ExportActions Component
3
+ * Action buttons for export dialog
4
+ */
5
+
6
+ import React from "react";
7
+ import {
8
+ View,
9
+ StyleSheet,
10
+ TouchableOpacity,
11
+ ActivityIndicator,
12
+ } from "react-native";
13
+ import {
14
+ AtomicText,
15
+ AtomicIcon,
16
+ useAppDesignTokens,
17
+ } from "@umituz/react-native-design-system";
18
+
19
+ interface ExportActionsProps {
20
+ isExporting: boolean;
21
+ onCancel: () => void;
22
+ onExport: () => void;
23
+ }
24
+
25
+ export const ExportActions: React.FC<ExportActionsProps> = ({
26
+ isExporting,
27
+ onCancel,
28
+ onExport,
29
+ }) => {
30
+ const tokens = useAppDesignTokens();
31
+
32
+ return (
33
+ <View style={styles.actions}>
34
+ <TouchableOpacity
35
+ style={[
36
+ styles.actionButton,
37
+ styles.cancelButton,
38
+ {
39
+ borderColor: tokens.colors.borderLight,
40
+ opacity: isExporting ? 0.5 : 1,
41
+ },
42
+ ]}
43
+ onPress={onCancel}
44
+ disabled={isExporting}
45
+ >
46
+ <AtomicText
47
+ type="bodyMedium"
48
+ style={{ color: tokens.colors.textSecondary }}
49
+ >
50
+ Cancel
51
+ </AtomicText>
52
+ </TouchableOpacity>
53
+
54
+ <TouchableOpacity
55
+ style={[
56
+ styles.actionButton,
57
+ styles.exportButton,
58
+ {
59
+ backgroundColor: tokens.colors.primary,
60
+ opacity: isExporting ? 0.7 : 1,
61
+ },
62
+ ]}
63
+ onPress={onExport}
64
+ disabled={isExporting}
65
+ >
66
+ {isExporting ? (
67
+ <ActivityIndicator color="#FFFFFF" size="small" />
68
+ ) : (
69
+ <AtomicIcon name="Download" size="sm" color="onSurface" />
70
+ )}
71
+ <AtomicText
72
+ type="bodyMedium"
73
+ style={{ color: "#FFFFFF", fontWeight: "600", marginLeft: 8 }}
74
+ >
75
+ {isExporting ? "Exporting..." : "Export Video"}
76
+ </AtomicText>
77
+ </TouchableOpacity>
78
+ </View>
79
+ );
80
+ };
81
+
82
+ const styles = StyleSheet.create({
83
+ actions: {
84
+ flexDirection: "row",
85
+ gap: 12,
86
+ },
87
+ actionButton: {
88
+ flex: 1,
89
+ flexDirection: "row",
90
+ paddingVertical: 14,
91
+ borderRadius: 12,
92
+ alignItems: "center",
93
+ justifyContent: "center",
94
+ },
95
+ cancelButton: {
96
+ borderWidth: 1,
97
+ },
98
+ exportButton: {
99
+ // backgroundColor set dynamically
100
+ },
101
+ });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ExportInfoBanner Component
3
+ * Info banner for export dialog
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, StyleSheet } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicIcon,
11
+ useAppDesignTokens,
12
+ } from "@umituz/react-native-design-system";
13
+
14
+ export const ExportInfoBanner: React.FC = () => {
15
+ const tokens = useAppDesignTokens();
16
+
17
+ return (
18
+ <View
19
+ style={[
20
+ styles.infoBanner,
21
+ { backgroundColor: tokens.colors.primary + "20" },
22
+ ]}
23
+ >
24
+ <AtomicIcon name="Info" size="sm" color="primary" />
25
+ <AtomicText
26
+ type="labelSmall"
27
+ style={{ color: tokens.colors.primary, marginLeft: 8, flex: 1 }}
28
+ >
29
+ Note: Full video encoding with frame rendering is a foundational
30
+ feature. This demo simulates the export process.
31
+ </AtomicText>
32
+ </View>
33
+ );
34
+ };
35
+
36
+ const styles = StyleSheet.create({
37
+ infoBanner: {
38
+ flexDirection: "row",
39
+ alignItems: "center",
40
+ padding: 12,
41
+ borderRadius: 8,
42
+ marginBottom: 24,
43
+ },
44
+ });