@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,81 @@
1
+ /**
2
+ * useSceneActions Hook
3
+ * Single Responsibility: Scene action handlers
4
+ */
5
+
6
+ import { useCallback } from "react";
7
+ import { AudioEditor } from "../presentation/components/AudioEditor";
8
+ import { SceneActionsMenu } from "../presentation/components/SceneActionsMenu";
9
+ import type { UseEditorScenesReturn } from "./useEditorScenes";
10
+ import type { UseEditorBottomSheetReturn } from "./useEditorBottomSheet";
11
+
12
+ export interface UseSceneActionsParams {
13
+ currentScene: any;
14
+ scenes: UseEditorScenesReturn;
15
+ bottomSheet: UseEditorBottomSheetReturn;
16
+ }
17
+
18
+ export interface UseSceneActionsReturn {
19
+ handleAudio: () => void;
20
+ handleSceneLongPress: (index: number, canDelete: boolean) => void;
21
+ }
22
+
23
+ export function useSceneActions({
24
+ currentScene,
25
+ scenes,
26
+ bottomSheet,
27
+ }: UseSceneActionsParams): UseSceneActionsReturn {
28
+ const { openBottomSheet, closeBottomSheet } = bottomSheet;
29
+
30
+ const handleAudio = useCallback(() => {
31
+ if (!currentScene) return;
32
+ openBottomSheet({
33
+ title: currentScene.audio ? "Edit Audio" : "Add Audio",
34
+ children: (
35
+ <AudioEditor
36
+ audio={currentScene.audio}
37
+ onSave={scenes.updateSceneAudio}
38
+ onRemove={
39
+ currentScene.audio
40
+ ? () => scenes.updateSceneAudio(undefined)
41
+ : undefined
42
+ }
43
+ onCancel={closeBottomSheet}
44
+ />
45
+ ),
46
+ });
47
+ }, [
48
+ currentScene,
49
+ scenes.updateSceneAudio,
50
+ openBottomSheet,
51
+ closeBottomSheet,
52
+ ]);
53
+
54
+ const handleSceneLongPress = useCallback(
55
+ (index: number, canDelete: boolean) => {
56
+ openBottomSheet({
57
+ title: `Scene ${index + 1} Actions`,
58
+ children: (
59
+ <SceneActionsMenu
60
+ sceneIndex={index}
61
+ canDelete={canDelete}
62
+ onDuplicate={() => {
63
+ closeBottomSheet();
64
+ scenes.duplicateScene(index);
65
+ }}
66
+ onDelete={() => {
67
+ closeBottomSheet();
68
+ scenes.deleteScene(index);
69
+ }}
70
+ />
71
+ ),
72
+ });
73
+ },
74
+ [scenes, openBottomSheet, closeBottomSheet],
75
+ );
76
+
77
+ return {
78
+ handleAudio,
79
+ handleSceneLongPress,
80
+ };
81
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * useShapeLayerForm Hook
3
+ * Manages form state for shape layer editor
4
+ */
5
+
6
+ import { useState, useCallback } from "react";
7
+ import { useAppDesignTokens } from "@umituz/react-native-design-system";
8
+ import type { ShapeLayer } from "@domains/video";
9
+ import type { ShapeType } from "../constants/shape-layer.constants";
10
+
11
+ export interface ShapeLayerFormState {
12
+ shape: ShapeType;
13
+ fillColor: string;
14
+ borderColor: string;
15
+ borderWidth: number;
16
+ opacity: number;
17
+ }
18
+
19
+ export interface UseShapeLayerFormReturn {
20
+ formState: ShapeLayerFormState;
21
+ setShape: (shape: ShapeType) => void;
22
+ setFillColor: (color: string) => void;
23
+ setBorderColor: (color: string) => void;
24
+ setBorderWidth: (width: number) => void;
25
+ setOpacity: (opacity: number) => void;
26
+ buildLayerData: () => Partial<ShapeLayer>;
27
+ }
28
+
29
+ /**
30
+ * Hook for managing shape layer form state
31
+ */
32
+ export function useShapeLayerForm(
33
+ initialLayer?: ShapeLayer,
34
+ ): UseShapeLayerFormReturn {
35
+ const tokens = useAppDesignTokens();
36
+
37
+ const [formState, setFormState] = useState<ShapeLayerFormState>({
38
+ shape: initialLayer?.shape || "rectangle",
39
+ fillColor: initialLayer?.fillColor || "#3B82F6",
40
+ borderColor: initialLayer?.borderColor || tokens.colors.textPrimary,
41
+ borderWidth: initialLayer?.borderWidth || 0,
42
+ opacity: initialLayer?.opacity || 1,
43
+ });
44
+
45
+ const setShape = useCallback((shape: ShapeType) => {
46
+ setFormState((prev) => ({ ...prev, shape }));
47
+ }, []);
48
+
49
+ const setFillColor = useCallback((color: string) => {
50
+ setFormState((prev) => ({ ...prev, fillColor: color }));
51
+ }, []);
52
+
53
+ const setBorderColor = useCallback((color: string) => {
54
+ setFormState((prev) => ({ ...prev, borderColor: color }));
55
+ }, []);
56
+
57
+ const setBorderWidth = useCallback((width: number) => {
58
+ setFormState((prev) => ({ ...prev, borderWidth: width }));
59
+ }, []);
60
+
61
+ const setOpacity = useCallback((opacity: number) => {
62
+ setFormState((prev) => ({ ...prev, opacity }));
63
+ }, []);
64
+
65
+ const buildLayerData = useCallback((): Partial<ShapeLayer> => {
66
+ return {
67
+ shape: formState.shape,
68
+ fillColor: formState.fillColor,
69
+ borderColor: formState.borderColor,
70
+ borderWidth: formState.borderWidth,
71
+ opacity: formState.opacity,
72
+ };
73
+ }, [formState]);
74
+
75
+ return {
76
+ formState,
77
+ setShape,
78
+ setFillColor,
79
+ setBorderColor,
80
+ setBorderWidth,
81
+ setOpacity,
82
+ buildLayerData,
83
+ };
84
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * useShapeLayerOperations Hook
3
+ * Single Responsibility: Shape layer operations (add)
4
+ */
5
+
6
+ import { useCallback } from "react";
7
+ import { Alert } from "react-native";
8
+ import { layerOperationsService } from "../infrastructure/services/layer-operations.service";
9
+ import type { AddShapeLayerData } from "../types";
10
+
11
+ export interface UseShapeLayerOperationsParams {
12
+ scenes: any[];
13
+ sceneIndex: number;
14
+ onUpdateScenes: (scenes: any[]) => void;
15
+ onCloseBottomSheet: () => void;
16
+ defaultColor: string;
17
+ }
18
+
19
+ export interface UseShapeLayerOperationsReturn {
20
+ addShapeLayer: (data: AddShapeLayerData) => void;
21
+ }
22
+
23
+ export function useShapeLayerOperations({
24
+ scenes,
25
+ sceneIndex,
26
+ onUpdateScenes,
27
+ onCloseBottomSheet,
28
+ defaultColor,
29
+ }: UseShapeLayerOperationsParams): UseShapeLayerOperationsReturn {
30
+ const addShapeLayer = useCallback(
31
+ (data: AddShapeLayerData) => {
32
+ const result = layerOperationsService.addShapeLayer(
33
+ scenes,
34
+ sceneIndex,
35
+ data,
36
+ defaultColor,
37
+ );
38
+ if (result.success) {
39
+ onUpdateScenes(result.updatedScenes);
40
+ onCloseBottomSheet();
41
+ Alert.alert("Success", "Shape layer added!");
42
+ } else {
43
+ Alert.alert("Error", result.error || "Failed to add shape layer");
44
+ }
45
+ },
46
+ [scenes, sceneIndex, onUpdateScenes, onCloseBottomSheet, defaultColor],
47
+ );
48
+
49
+ return {
50
+ addShapeLayer,
51
+ };
52
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * useTextLayerForm Hook
3
+ * Manages form state for text layer editor
4
+ */
5
+
6
+ import { useState, useCallback } from "react";
7
+ import { useAppDesignTokens } from "@umituz/react-native-design-system";
8
+ import type { TextLayer } from "@domains/video";
9
+
10
+ export interface TextLayerFormState {
11
+ text: string;
12
+ fontSize: number;
13
+ fontFamily: string;
14
+ fontWeight: "normal" | "bold" | "300" | "700";
15
+ color: string;
16
+ textAlign: "left" | "center" | "right";
17
+ }
18
+
19
+ export interface UseTextLayerFormReturn {
20
+ formState: TextLayerFormState;
21
+ setText: (text: string) => void;
22
+ setFontSize: (size: number) => void;
23
+ setFontFamily: (family: string) => void;
24
+ setFontWeight: (weight: "normal" | "bold" | "300" | "700") => void;
25
+ setColor: (color: string) => void;
26
+ setTextAlign: (align: "left" | "center" | "right") => void;
27
+ buildLayerData: () => Partial<TextLayer>;
28
+ isValid: boolean;
29
+ }
30
+
31
+ /**
32
+ * Hook for managing text layer form state
33
+ */
34
+ export function useTextLayerForm(
35
+ initialLayer?: TextLayer,
36
+ ): UseTextLayerFormReturn {
37
+ const tokens = useAppDesignTokens();
38
+
39
+ const [formState, setFormState] = useState<TextLayerFormState>({
40
+ text: initialLayer?.content || "",
41
+ fontSize: initialLayer?.fontSize || 48,
42
+ fontFamily: initialLayer?.fontFamily || "System",
43
+ fontWeight:
44
+ (initialLayer?.fontWeight as "normal" | "bold" | "300" | "700") || "bold",
45
+ color: initialLayer?.color || tokens.colors.textInverse,
46
+ textAlign: initialLayer?.textAlign || "center",
47
+ });
48
+
49
+ const setText = useCallback((text: string) => {
50
+ setFormState((prev) => ({ ...prev, text }));
51
+ }, []);
52
+
53
+ const setFontSize = useCallback((size: number) => {
54
+ setFormState((prev) => ({ ...prev, fontSize: size }));
55
+ }, []);
56
+
57
+ const setFontFamily = useCallback((family: string) => {
58
+ setFormState((prev) => ({ ...prev, fontFamily: family }));
59
+ }, []);
60
+
61
+ const setFontWeight = useCallback(
62
+ (weight: "normal" | "bold" | "300" | "700") => {
63
+ setFormState((prev) => ({ ...prev, fontWeight: weight }));
64
+ },
65
+ [],
66
+ );
67
+
68
+ const setColor = useCallback((color: string) => {
69
+ setFormState((prev) => ({ ...prev, color }));
70
+ }, []);
71
+
72
+ const setTextAlign = useCallback((align: "left" | "center" | "right") => {
73
+ setFormState((prev) => ({ ...prev, textAlign: align }));
74
+ }, []);
75
+
76
+ const buildLayerData = useCallback((): Partial<TextLayer> => {
77
+ return {
78
+ content: formState.text,
79
+ fontSize: formState.fontSize,
80
+ fontFamily: formState.fontFamily,
81
+ fontWeight: formState.fontWeight,
82
+ color: formState.color,
83
+ textAlign: formState.textAlign,
84
+ };
85
+ }, [formState]);
86
+
87
+ const isValid = formState.text.trim().length > 0;
88
+
89
+ return {
90
+ formState,
91
+ setText,
92
+ setFontSize,
93
+ setFontFamily,
94
+ setFontWeight,
95
+ setColor,
96
+ setTextAlign,
97
+ buildLayerData,
98
+ isValid,
99
+ };
100
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * useTextLayerOperations Hook
3
+ * Single Responsibility: Text layer operations (add, edit)
4
+ */
5
+
6
+ import { useCallback } from "react";
7
+ import { Alert } from "react-native";
8
+ import { layerOperationsService } from "../infrastructure/services/layer-operations.service";
9
+ import type { AddTextLayerData } from "../types";
10
+ import type { TextLayer } from "@domains/video";
11
+
12
+ export interface UseTextLayerOperationsParams {
13
+ scenes: any[];
14
+ sceneIndex: number;
15
+ onUpdateScenes: (scenes: any[]) => void;
16
+ onCloseBottomSheet: () => void;
17
+ defaultColor: string;
18
+ }
19
+
20
+ export interface UseTextLayerOperationsReturn {
21
+ addTextLayer: (data: AddTextLayerData) => void;
22
+ editTextLayer: (layerId: string, data: Partial<TextLayer>) => void;
23
+ }
24
+
25
+ export function useTextLayerOperations({
26
+ scenes,
27
+ sceneIndex,
28
+ onUpdateScenes,
29
+ onCloseBottomSheet,
30
+ defaultColor,
31
+ }: UseTextLayerOperationsParams): UseTextLayerOperationsReturn {
32
+ const addTextLayer = useCallback(
33
+ (data: AddTextLayerData) => {
34
+ const result = layerOperationsService.addTextLayer(
35
+ scenes,
36
+ sceneIndex,
37
+ data,
38
+ defaultColor,
39
+ );
40
+ if (result.success) {
41
+ onUpdateScenes(result.updatedScenes);
42
+ onCloseBottomSheet();
43
+ Alert.alert("Success", "Text layer added!");
44
+ } else {
45
+ Alert.alert("Error", result.error || "Failed to add text layer");
46
+ }
47
+ },
48
+ [scenes, sceneIndex, onUpdateScenes, onCloseBottomSheet, defaultColor],
49
+ );
50
+
51
+ const editTextLayer = useCallback(
52
+ (layerId: string, data: Partial<TextLayer>) => {
53
+ const result = layerOperationsService.editTextLayer(
54
+ scenes,
55
+ sceneIndex,
56
+ layerId,
57
+ data,
58
+ );
59
+ if (result.success) {
60
+ onUpdateScenes(result.updatedScenes);
61
+ onCloseBottomSheet();
62
+ Alert.alert("Success", "Text layer updated!");
63
+ } else {
64
+ Alert.alert("Error", result.error || "Failed to update text layer");
65
+ }
66
+ },
67
+ [scenes, sceneIndex, onUpdateScenes, onCloseBottomSheet],
68
+ );
69
+
70
+ return {
71
+ addTextLayer,
72
+ editTextLayer,
73
+ };
74
+ }