@umituz/react-native-video-editor 1.0.32 → 1.0.34

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 (24) hide show
  1. package/package.json +12 -5
  2. package/src/infrastructure/services/image-layer-operations.service.ts +1 -1
  3. package/src/infrastructure/services/layer-operations/layer-duplicate.service.ts +1 -1
  4. package/src/infrastructure/services/scene-operations.service.ts +1 -1
  5. package/src/infrastructure/services/shape-layer-operations.service.ts +1 -1
  6. package/src/infrastructure/services/text-layer-operations.service.ts +1 -1
  7. package/src/player/infrastructure/services/player-control.service.ts +2 -2
  8. package/src/player/infrastructure/services/video-cache.service.ts +1 -1
  9. package/src/player/presentation/hooks/useVideoPlayerControl.ts +2 -2
  10. package/src/presentation/components/AnimationEditor.tsx +1 -1
  11. package/src/presentation/components/AudioEditor.tsx +1 -1
  12. package/src/presentation/components/DraggableLayer.tsx +2 -3
  13. package/src/presentation/components/EditorHeader.tsx +0 -1
  14. package/src/presentation/components/EditorPreviewArea.styles.ts +1 -1
  15. package/src/presentation/components/EditorToolPanel.tsx +0 -1
  16. package/src/presentation/components/ExportDialog.tsx +0 -3
  17. package/src/presentation/components/LayerActionsMenu.tsx +1 -1
  18. package/src/presentation/components/SceneActionsMenu.tsx +1 -1
  19. package/src/presentation/components/ShapeLayerEditor.tsx +0 -6
  20. package/src/presentation/components/draggable-layer/ResizeHandles.tsx +1 -1
  21. package/src/presentation/components/shape-layer/ShapePreview.tsx +0 -1
  22. package/src/presentation/components/text-layer/EditorActions.tsx +0 -1
  23. package/src/presentation/hooks/useEditorBottomSheet.ts +0 -1
  24. package/src/presentation/hooks/useEditorHistory.ts +35 -40
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-video-editor",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "Professional video editor with layer-based timeline, text/image/shape/audio/animation layers, and export functionality",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -10,7 +10,8 @@
10
10
  },
11
11
  "scripts": {
12
12
  "typecheck": "npx tsc --noEmit",
13
- "lint": "echo 'Lint passed'",
13
+ "lint": "eslint src",
14
+ "lint:fix": "eslint src --fix",
14
15
  "version:patch": "npm version patch -m 'chore: release v%s'",
15
16
  "version:minor": "npm version minor -m 'chore: release v%s'",
16
17
  "version:major": "npm version major -m 'chore: release v%s'"
@@ -30,7 +31,6 @@
30
31
  "url": "https://github.com/umituz/react-native-video-editor"
31
32
  },
32
33
  "dependencies": {
33
- "@umituz/react-native-filesystem": "latest",
34
34
  "expo-document-picker": ">=14.0.0"
35
35
  },
36
36
  "peerDependencies": {
@@ -47,18 +47,25 @@
47
47
  "@gorhom/bottom-sheet": "^5.2.8",
48
48
  "@types/react": "~19.1.10",
49
49
  "@umituz/react-native-design-system": "latest",
50
- "@umituz/react-native-filesystem": "latest",
50
+ "@umituz/react-native-localization": "latest",
51
+ "@umituz/react-native-uuid": "latest",
51
52
  "expo-application": "^7.0.8",
53
+ "expo-crypto": "^13.0.2",
52
54
  "expo-device": "^8.0.10",
53
55
  "expo-document-picker": "^14.0.8",
54
56
  "expo-file-system": "^19.0.0",
55
57
  "expo-image": "^3.0.11",
58
+ "expo-sharing": "^14.0.8",
56
59
  "expo-video": "^3.0.15",
57
60
  "react": "19.1.0",
58
61
  "react-native": "0.81.5",
59
62
  "react-native-gesture-handler": "^2.30.0",
60
63
  "react-native-reanimated": "^4.2.1",
61
- "typescript": "~5.9.2"
64
+ "typescript": "~5.9.2",
65
+ "@types/react-native": "*",
66
+ "@typescript-eslint/parser": "*",
67
+ "@typescript-eslint/eslint-plugin": "*",
68
+ "eslint": "*"
62
69
  },
63
70
  "publishConfig": {
64
71
  "access": "public"
@@ -3,7 +3,7 @@
3
3
  * Single Responsibility: Image layer business logic
4
4
  */
5
5
 
6
- import { generateUUID } from "@umituz/react-native-design-system";
6
+ import { generateUUID } from "@umituz/react-native-uuid";
7
7
  import type { Scene, ImageLayer } from "../../domain/entities";
8
8
  import type { LayerOperationResult, AddImageLayerData } from "../../domain/entities";
9
9
 
@@ -3,7 +3,7 @@
3
3
  * Single Responsibility: Handle layer duplication operations
4
4
  */
5
5
 
6
- import { generateUUID } from "@umituz/react-native-design-system";
6
+ import { generateUUID } from "@umituz/react-native-uuid";
7
7
  import type { Scene } from "../../../domain/entities";
8
8
  import type { LayerOperationResult } from "../../../domain/entities";
9
9
 
@@ -3,7 +3,7 @@
3
3
  * Single Responsibility: Business logic for scene operations
4
4
  */
5
5
 
6
- import { generateUUID } from "@umituz/react-native-design-system";
6
+ import { generateUUID } from "@umituz/react-native-uuid";
7
7
  import type { Scene, Audio } from "../../domain/entities";
8
8
  import type { SceneOperationResult } from "../../domain/entities";
9
9
 
@@ -3,7 +3,7 @@
3
3
  * Single Responsibility: Shape layer business logic
4
4
  */
5
5
 
6
- import { generateUUID } from "@umituz/react-native-design-system";
6
+ import { generateUUID } from "@umituz/react-native-uuid";
7
7
  import type { Scene, ShapeLayer } from "../../domain/entities";
8
8
  import type { LayerOperationResult, AddShapeLayerData } from "../../domain/entities";
9
9
 
@@ -3,7 +3,7 @@
3
3
  * Single Responsibility: Text layer business logic
4
4
  */
5
5
 
6
- import { generateUUID } from "@umituz/react-native-design-system";
6
+ import { generateUUID } from "@umituz/react-native-uuid";
7
7
  import type { Scene, TextLayer } from "../../domain/entities";
8
8
  import type { LayerOperationResult, AddTextLayerData } from "../../domain/entities";
9
9
 
@@ -44,7 +44,7 @@ export const safePause = (player: VideoPlayer | null): boolean => {
44
44
  return true;
45
45
  } catch (error) {
46
46
  if (typeof __DEV__ !== "undefined" && __DEV__) {
47
- // eslint-disable-next-line no-console
47
+
48
48
  console.log("[VideoPlayer] Pause error ignored:", error);
49
49
  }
50
50
  return false;
@@ -96,7 +96,7 @@ export const configurePlayer = (
96
96
  }
97
97
  } catch (error) {
98
98
  if (typeof __DEV__ !== "undefined" && __DEV__) {
99
- // eslint-disable-next-line no-console
99
+
100
100
  console.log("[VideoPlayer] Configure error ignored:", error);
101
101
  }
102
102
  }
@@ -13,7 +13,7 @@ import {
13
13
  clearCache,
14
14
  type DownloadProgressCallback,
15
15
  type DownloadProgress,
16
- } from "@umituz/react-native-filesystem";
16
+ } from "@umituz/react-native-design-system";
17
17
 
18
18
  declare const __DEV__: boolean;
19
19
 
@@ -35,7 +35,7 @@ export const useVideoPlayerControl = (
35
35
 
36
36
  const player = useExpoVideoPlayer(source || "", (p) => {
37
37
  if (typeof __DEV__ !== "undefined" && __DEV__) {
38
- // eslint-disable-next-line no-console
38
+
39
39
  console.log("[useVideoPlayerControl] Player callback, source:", source, "player:", !!p);
40
40
  }
41
41
  if (source && p) {
@@ -45,7 +45,7 @@ export const useVideoPlayerControl = (
45
45
  setIsPlaying(true);
46
46
  }
47
47
  if (typeof __DEV__ !== "undefined" && __DEV__) {
48
- // eslint-disable-next-line no-console
48
+
49
49
  console.log("[useVideoPlayerControl] Player status:", {
50
50
  currentTime: p.currentTime,
51
51
  duration: p.duration,
@@ -5,7 +5,7 @@
5
5
 
6
6
  import React from "react";
7
7
  import { View, ScrollView, StyleSheet } from "react-native";
8
- import { useAppDesignTokens } from "@umituz/react-native-design-system";
8
+
9
9
  import type { Animation } from "../../domain/entities";
10
10
  import { useAnimationLayerForm } from "../hooks/useAnimationLayerForm";
11
11
  import {
@@ -57,7 +57,7 @@ export const AudioEditor: React.FC<AudioEditorProps> = ({
57
57
  if (!result.canceled && result.assets && result.assets.length > 0) {
58
58
  setAudioUri(result.assets[0].uri);
59
59
  }
60
- } catch (error) {
60
+ } catch {
61
61
  Alert.alert(t("audio.errors.pickFailed"));
62
62
  }
63
63
  }, [setAudioUri, t]);
@@ -63,17 +63,16 @@ export const DraggableLayer: React.FC<DraggableLayerProps> = ({
63
63
 
64
64
  const animatedStyle = useAnimatedStyle(() => {
65
65
  const rotationStr = `${layer.rotation}deg`;
66
- const style = {
66
+ return {
67
67
  transform: [
68
68
  { translateX: translateX.value },
69
69
  { translateY: translateY.value },
70
70
  { rotate: rotationStr },
71
- ] as const,
71
+ ],
72
72
  opacity: layer.opacity,
73
73
  width: width.value,
74
74
  height: height.value,
75
75
  };
76
- return style as any;
77
76
  });
78
77
 
79
78
  return (
@@ -10,7 +10,6 @@ import {
10
10
  AtomicIcon,
11
11
  useAppDesignTokens,
12
12
  } from "@umituz/react-native-design-system";
13
- import { AppNavigation } from "@umituz/react-native-design-system";
14
13
 
15
14
  export interface EditorHeaderProps {
16
15
  projectTitle: string;
@@ -1,7 +1,7 @@
1
1
  import { StyleSheet } from "react-native";
2
2
  import { DesignTokens } from "@umituz/react-native-design-system";
3
3
 
4
- export const createPreviewStyles = (tokens: DesignTokens) =>
4
+ export const createPreviewStyles = (_tokens: DesignTokens) =>
5
5
  StyleSheet.create({
6
6
  previewSection: {
7
7
  padding: 16,
@@ -17,7 +17,6 @@ import {
17
17
  useAppDesignTokens,
18
18
  } from "@umituz/react-native-design-system";
19
19
  import { useLocalization } from "@umituz/react-native-localization";
20
- import type { Audio } from "../../domain/entities";
21
20
 
22
21
  export interface EditorToolPanelProps {
23
22
  onAddText: () => void;
@@ -13,9 +13,6 @@ import {
13
13
  RESOLUTIONS,
14
14
  QUALITIES,
15
15
  FORMATS,
16
- type Resolution,
17
- type Quality,
18
- type Format,
19
16
  } from "../../infrastructure/constants/export.constants";
20
17
  import {
21
18
  ProjectInfoBox,
@@ -11,7 +11,7 @@ import {
11
11
  useAppDesignTokens,
12
12
  } from "@umituz/react-native-design-system";
13
13
  import { useLocalization } from "@umituz/react-native-localization";
14
- import type { Layer, ImageLayer } from "../../domain/entities";
14
+ import type { Layer } from "../../domain/entities";
15
15
 
16
16
  export interface LayerActionsMenuProps {
17
17
  layer: Layer;
@@ -19,7 +19,7 @@ export interface SceneActionsMenuProps {
19
19
  }
20
20
 
21
21
  export const SceneActionsMenu: React.FC<SceneActionsMenuProps> = ({
22
- sceneIndex,
22
+ sceneIndex: _sceneIndex,
23
23
  canDelete,
24
24
  onDuplicate,
25
25
  onDelete,
@@ -5,11 +5,6 @@
5
5
 
6
6
  import React from "react";
7
7
  import { View, ScrollView, StyleSheet } from "react-native";
8
- import {
9
- AtomicText,
10
- AtomicIcon,
11
- useAppDesignTokens,
12
- } from "@umituz/react-native-design-system";
13
8
  import type { ShapeLayer } from "../../domain/entities";
14
9
  import { useShapeLayerForm } from "../hooks/useShapeLayerForm";
15
10
  import {
@@ -35,7 +30,6 @@ export const ShapeLayerEditor: React.FC<ShapeLayerEditorProps> = ({
35
30
  onSave,
36
31
  onCancel,
37
32
  }) => {
38
- const tokens = useAppDesignTokens();
39
33
  const {
40
34
  formState,
41
35
  setShape,
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import React from "react";
7
- import { View, StyleSheet } from "react-native";
7
+ import { StyleSheet } from "react-native";
8
8
  import { Gesture, GestureDetector } from "react-native-gesture-handler";
9
9
  import Animated from "react-native-reanimated";
10
10
  import { useAppDesignTokens } from "@umituz/react-native-design-system";
@@ -9,7 +9,6 @@ import {
9
9
  AtomicText,
10
10
  useAppDesignTokens,
11
11
  } from "@umituz/react-native-design-system";
12
- import type { ShapeType } from "../../../infrastructure/constants/shape-layer.constants";
13
12
  import type { ShapeLayerFormState } from "../../hooks/useShapeLayerForm";
14
13
 
15
14
  interface ShapePreviewProps {
@@ -7,7 +7,6 @@ import React from "react";
7
7
  import { View, StyleSheet, TouchableOpacity } from "react-native";
8
8
  import {
9
9
  AtomicText,
10
- AtomicIcon,
11
10
  useAppDesignTokens,
12
11
  } from "@umituz/react-native-design-system";
13
12
  import { useLocalization } from "@umituz/react-native-localization";
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import { useState, useCallback } from "react";
7
- import { Alert } from "react-native";
8
7
 
9
8
  export interface BottomSheetContent {
10
9
  title: string;
@@ -3,24 +3,12 @@
3
3
  * Single Responsibility: History operations for editor
4
4
  */
5
5
 
6
- import { useCallback } from "react";
7
- import { Alert } from "react-native";
8
- import { useLocalization } from "@umituz/react-native-localization";
9
- // TODO: Refactor to use TanStack Query instead of store
10
- // Temporary stub until refactor
11
- const useHistoryStore = () => ({
12
- addToHistory: () => {},
13
- pushHistory: (_project: VideoProject | undefined, _action: string) => {},
14
- undo: () => undefined,
15
- redo: () => undefined,
16
- canUndo: () => false,
17
- canRedo: () => false,
18
- });
6
+ import { useCallback, useState } from "react";
19
7
  import type { VideoProject } from "../../domain/entities";
20
8
 
21
9
  export interface UseEditorHistoryParams {
22
10
  project: VideoProject | undefined;
23
- projectId: string;
11
+ projectId: string; // Kept for interface compatibility, used for reset if needed
24
12
  onUpdateProject: (updates: Partial<VideoProject>) => void;
25
13
  }
26
14
 
@@ -34,49 +22,56 @@ export interface UseEditorHistoryReturn {
34
22
 
35
23
  export function useEditorHistory({
36
24
  project,
37
- projectId,
38
25
  onUpdateProject,
39
26
  }: UseEditorHistoryParams): UseEditorHistoryReturn {
40
- const { t } = useLocalization();
41
- const {
42
- pushHistory,
43
- undo: historyUndo,
44
- redo: historyRedo,
45
- canUndo,
46
- canRedo,
47
- } = useHistoryStore();
27
+ const [history, setHistory] = useState<VideoProject[]>([]);
28
+ const [future, setFuture] = useState<VideoProject[]>([]);
48
29
 
49
30
  const updateWithHistory = useCallback(
50
- (updates: Partial<VideoProject>, action: string) => {
31
+ (updates: Partial<VideoProject>, _action: string) => {
51
32
  if (project) {
52
- pushHistory(project, action);
33
+ // Push current state to history before updating
34
+ setHistory((prev) => [...prev, project]);
35
+ // Clear future
36
+ setFuture([]);
37
+
53
38
  onUpdateProject(updates);
54
39
  }
55
40
  },
56
- [project, pushHistory, onUpdateProject],
41
+ [project, onUpdateProject],
57
42
  );
58
43
 
59
44
  const undo = useCallback(() => {
60
- const previousState = historyUndo();
61
- if (previousState) {
62
- onUpdateProject(previousState);
63
- Alert.alert(t("editor.history.undo.success"));
64
- }
65
- }, [historyUndo, onUpdateProject, t]);
45
+ if (history.length === 0 || !project) return;
46
+
47
+ const previousState = history[history.length - 1];
48
+ const newHistory = history.slice(0, -1);
49
+
50
+ setFuture((prev) => [project, ...prev]);
51
+ setHistory(newHistory);
52
+
53
+ // Full replacement of state
54
+ // We assume onUpdateProject can handle a full object which is a superset of Partial
55
+ onUpdateProject(previousState);
56
+ }, [history, project, onUpdateProject]);
66
57
 
67
58
  const redo = useCallback(() => {
68
- const nextState = historyRedo();
69
- if (nextState) {
70
- onUpdateProject(nextState);
71
- Alert.alert(t("editor.history.redo.success"));
72
- }
73
- }, [historyRedo, onUpdateProject, t]);
59
+ if (future.length === 0 || !project) return;
60
+
61
+ const nextState = future[0];
62
+ const newFuture = future.slice(1);
63
+
64
+ setHistory((prev) => [...prev, project]);
65
+ setFuture(newFuture);
66
+
67
+ onUpdateProject(nextState);
68
+ }, [future, project, onUpdateProject]);
74
69
 
75
70
  return {
76
71
  undo,
77
72
  redo,
78
- canUndo: canUndo(),
79
- canRedo: canRedo(),
73
+ canUndo: history.length > 0,
74
+ canRedo: future.length > 0,
80
75
  updateWithHistory,
81
76
  };
82
77
  }