@umituz/react-native-video-editor 1.1.63 → 1.1.64

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-video-editor",
3
- "version": "1.1.63",
3
+ "version": "1.1.64",
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",
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { generateUUID } from "@umituz/react-native-design-system/uuid";
7
- import type { ImageLayer } from "../../domain/entities/video-project.types";
7
+ import type { ImageLayer, Scene } from "../../domain/entities/video-project.types";
8
8
  import type { LayerOperationResult, AddImageLayerData } from "../../domain/entities/video-project.types";
9
9
  import { BaseLayerOperationsService } from "./base/base-layer-operations.service";
10
10
 
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { generateUUID } from "@umituz/react-native-design-system/uuid";
7
- import type { ShapeLayer } from "../../domain/entities/video-project.types";
7
+ import type { ShapeLayer, Scene } from "../../domain/entities/video-project.types";
8
8
  import type { LayerOperationResult, AddShapeLayerData } from "../../domain/entities/video-project.types";
9
9
  import { BaseLayerOperationsService } from "./base/base-layer-operations.service";
10
10
 
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { generateUUID } from "@umituz/react-native-design-system/uuid";
7
- import type { TextLayer } from "../../domain/entities/video-project.types";
7
+ import type { TextLayer, Scene } from "../../domain/entities/video-project.types";
8
8
  import type { LayerOperationResult, AddTextLayerData } from "../../domain/entities/video-project.types";
9
9
  import { BaseLayerOperationsService } from "./base/base-layer-operations.service";
10
10
 
@@ -28,7 +28,7 @@ export const SubtitleListPanel: React.FC<SubtitleListPanelProps> = ({
28
28
  currentTime,
29
29
  onAdd,
30
30
  onUpdate,
31
- onDelete,
31
+ onDelete: _onDelete,
32
32
  onSeek,
33
33
  t,
34
34
  }) => {
@@ -44,8 +44,8 @@ export const CollageCanvas: React.FC<CollageCanvasProps> = ({
44
44
  overflow: "hidden" as const,
45
45
  },
46
46
  cellImage: {
47
- width: "100%",
48
- height: "100%",
47
+ width: "100%" as const,
48
+ height: "100%" as const,
49
49
  },
50
50
  cellEmpty: {
51
51
  flex: 1,
@@ -5,7 +5,6 @@
5
5
 
6
6
  import React from "react";
7
7
  import { View, ScrollView, TouchableOpacity } from "react-native";
8
- import { AtomicText } from "@umituz/react-native-design-system/atoms";
9
8
  import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
10
9
  import { COLLAGE_LAYOUTS } from "../../../infrastructure/constants/collage.constants";
11
10
  import type { CollageLayout } from "../../../infrastructure/constants/collage.constants";
@@ -93,9 +92,6 @@ export const CollageLayoutSelector: React.FC<CollageLayoutSelectorProps> = ({
93
92
  );
94
93
  })}
95
94
  </View>
96
- <AtomicText type="caption" color="textSecondary">
97
- {layout.name}
98
- </AtomicText>
99
95
  </TouchableOpacity>
100
96
  ))}
101
97
  </ScrollView>
@@ -29,7 +29,6 @@ export const SubtitleListItem: React.FC<SubtitleListItemProps> = ({
29
29
  item: {
30
30
  flexDirection: "row" as const,
31
31
  alignItems: "center" as const,
32
- backgroundColor: tokens.colors.surface,
33
32
  borderRadius: tokens.borders.radius.md,
34
33
  marginHorizontal: tokens.spacing.md,
35
34
  marginBottom: tokens.spacing.sm,
@@ -70,17 +69,17 @@ export const SubtitleListItem: React.FC<SubtitleListItemProps> = ({
70
69
  activeOpacity={0.7}
71
70
  >
72
71
  <View style={styles.itemTimeRow}>
73
- <AtomicText variant="caption" color="textSecondary">
72
+ <AtomicText color="textSecondary">
74
73
  {formatTimeDetailed(subtitle.startTime)}
75
74
  </AtomicText>
76
- <AtomicText variant="caption" color="textSecondary">
75
+ <AtomicText color="textSecondary">
77
76
 
78
77
  </AtomicText>
79
- <AtomicText variant="caption" color="textSecondary">
78
+ <AtomicText color="textSecondary">
80
79
  {formatTimeDetailed(subtitle.endTime)}
81
80
  </AtomicText>
82
81
  </View>
83
- <AtomicText variant="body" color="textPrimary" numberOfLines={2}>
82
+ <AtomicText color="textPrimary" numberOfLines={2}>
84
83
  {subtitle.text}
85
84
  </AtomicText>
86
85
  </TouchableOpacity>
@@ -55,7 +55,7 @@ export const SubtitleModal: React.FC<SubtitleModalProps> = ({
55
55
  paddingHorizontal: tokens.spacing.md,
56
56
  paddingTop: tokens.spacing.md,
57
57
  paddingBottom: tokens.spacing.xl,
58
- maxHeight: "90%",
58
+ maxHeight: "90%" as const,
59
59
  },
60
60
  handle: {
61
61
  width: 36,
@@ -136,7 +136,7 @@ export const SubtitleModal: React.FC<SubtitleModalProps> = ({
136
136
  />
137
137
  </View>
138
138
 
139
- <SubtitleStylePicker value={style} onChange={onChangeStyle} />
139
+ <SubtitleStylePicker style={style} previewText={text} onChange={onChangeStyle} t={(key) => key} />
140
140
 
141
141
  <View style={styles.actionRow}>
142
142
  <TouchableOpacity style={styles.cancelBtn} onPress={onCancel}>
@@ -3,7 +3,7 @@
3
3
  * Manages subtitle form state and operations
4
4
  */
5
5
 
6
- import { useState, useCallback, useMemo } from "react";
6
+ import { useState, useCallback } from "react";
7
7
  import { DEFAULT_SUBTITLE_STYLE } from "../../../infrastructure/constants/subtitle.constants";
8
8
  import type { Subtitle, SubtitleStyle } from "../../../domain/entities/video-project.types";
9
9
 
@@ -5,30 +5,30 @@
5
5
  */
6
6
 
7
7
  import { useState, useCallback } from "react";
8
- import type { Layer } from "../../domain/entities/video-project.types";
8
+ import type { Layer, ImageLayer, TextLayer } from "../../../domain/entities/video-project.types";
9
9
 
10
10
  /**
11
11
  * Form field validator function type
12
12
  */
13
- export type ValidatorFn<T> = (value: T[keyof T]) => string | null;
13
+ export type ValidatorFn<T, K extends keyof T = keyof T> = (value: T[K]) => string | null;
14
14
 
15
15
  /**
16
16
  * Layer form configuration
17
17
  */
18
18
  export interface UseLayerFormConfig<T extends Record<string, unknown>> {
19
19
  initialValues: Partial<T>;
20
- validators?: Partial<Record<keyof T, ValidatorFn<T>>>;
21
- buildData: (formState: T) => Partial<Layer>;
20
+ validators?: Record<string, (value: unknown) => string | null>;
21
+ buildData: (formState: T) => Partial<Layer> | Partial<ImageLayer> | Partial<TextLayer>;
22
22
  }
23
23
 
24
24
  /**
25
25
  * Layer form return type
26
26
  */
27
- export interface UseLayerFormReturn<T extends Record<string, unknown>> {
27
+ export interface UseLayerFormReturn<T extends Record<string, unknown>, R = Partial<Layer>> {
28
28
  formState: T;
29
29
  updateField: <K extends keyof T>(field: K, value: T[K]) => void;
30
30
  setFormState: (state: T | ((prev: T) => T)) => void;
31
- buildLayerData: () => Partial<Layer>;
31
+ buildLayerData: () => R;
32
32
  isValid: boolean;
33
33
  errors: Partial<Record<keyof T, string | null>>;
34
34
  validateField: <K extends keyof T>(field: K) => string | null;
@@ -39,9 +39,9 @@ export interface UseLayerFormReturn<T extends Record<string, unknown>> {
39
39
  * Generic hook for managing layer form state
40
40
  * Provides type-safe form management with validation support
41
41
  */
42
- export function useLayerForm<T extends Record<string, unknown>>(
42
+ export function useLayerForm<T extends Record<string, unknown>, R = Partial<Layer>>(
43
43
  config: UseLayerFormConfig<T>,
44
- ): UseLayerFormReturn<T> {
44
+ ): UseLayerFormReturn<T, R> {
45
45
  const { initialValues, validators = {}, buildData } = config;
46
46
 
47
47
  const [formState, setFormState] = useState<T>(
@@ -60,7 +60,7 @@ export function useLayerForm<T extends Record<string, unknown>>(
60
60
  }));
61
61
 
62
62
  // Clear error for this field
63
- if (errors[field]) {
63
+ if (errors[field as keyof typeof errors]) {
64
64
  setErrors((prev) => ({
65
65
  ...prev,
66
66
  [field]: null,
@@ -72,7 +72,7 @@ export function useLayerForm<T extends Record<string, unknown>>(
72
72
 
73
73
  const validateField = useCallback(
74
74
  <K extends keyof T>(field: K): string | null => {
75
- const validator = validators[field];
75
+ const validator = validators[String(field)];
76
76
  if (!validator) return null;
77
77
 
78
78
  const error = validator(formState[field]);
@@ -91,10 +91,13 @@ export function useLayerForm<T extends Record<string, unknown>>(
91
91
  const newErrors: Partial<Record<keyof T, string | null>> = {};
92
92
 
93
93
  for (const field in validators) {
94
- const error = validators[field]!(formState[field]);
95
- if (error) {
96
- newErrors[field] = error;
97
- hasError = true;
94
+ const validator = validators[field];
95
+ if (validator) {
96
+ const error = validator(formState[field as keyof T]);
97
+ if (error) {
98
+ newErrors[field as keyof T] = error;
99
+ hasError = true;
100
+ }
98
101
  }
99
102
  }
100
103
 
@@ -102,8 +105,8 @@ export function useLayerForm<T extends Record<string, unknown>>(
102
105
  return !hasError;
103
106
  }, [formState, validators]);
104
107
 
105
- const buildLayerData = useCallback((): Partial<Layer> => {
106
- return buildData(formState);
108
+ const buildLayerData = useCallback((): R => {
109
+ return buildData(formState) as R;
107
110
  }, [formState, buildData]);
108
111
 
109
112
  const isValid = Object.values(errors).every((error) => error === null);
@@ -4,11 +4,12 @@
4
4
  */
5
5
 
6
6
  import type { ImageLayer } from "../../domain/entities/video-project.types";
7
- import { useLayerForm } from "./generic/use-layer-form.hook";
7
+ import { useLayerForm, type UseLayerFormConfig } from "./generic/use-layer-form.hook";
8
8
 
9
9
  interface ImageLayerFormState {
10
10
  imageUri: string;
11
11
  opacity: number;
12
+ [key: string]: unknown;
12
13
  }
13
14
 
14
15
  interface UseImageLayerFormReturn {
@@ -25,14 +26,14 @@ interface UseImageLayerFormReturn {
25
26
  export function useImageLayerForm(
26
27
  initialLayer?: ImageLayer,
27
28
  ): UseImageLayerFormReturn {
28
- const form = useLayerForm<ImageLayerFormState>({
29
+ const config: UseLayerFormConfig<ImageLayerFormState> = {
29
30
  initialValues: {
30
31
  imageUri: initialLayer?.uri || "",
31
32
  opacity: initialLayer?.opacity || 1,
32
33
  },
33
34
  validators: {
34
- imageUri: (value) => {
35
- if (!value || value.trim().length === 0) {
35
+ imageUri: (value: unknown) => {
36
+ if (!value || (typeof value === "string" && value.trim().length === 0)) {
36
37
  return "Image URI is required";
37
38
  }
38
39
  return null;
@@ -41,8 +42,10 @@ export function useImageLayerForm(
41
42
  buildData: (formState) => ({
42
43
  uri: formState.imageUri,
43
44
  opacity: formState.opacity,
44
- }),
45
- });
45
+ } as Partial<ImageLayer>),
46
+ };
47
+
48
+ const form = useLayerForm<ImageLayerFormState, Partial<ImageLayer>>(config);
46
49
 
47
50
  const setImageUri = (uri: string) => form.updateField("imageUri", uri);
48
51
  const setOpacity = (opacity: number) => form.updateField("opacity", opacity);
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
7
7
  import type { TextLayer } from "../../domain/entities/video-project.types";
8
- import { useLayerForm } from "./generic/use-layer-form.hook";
8
+ import { useLayerForm, type UseLayerFormConfig } from "./generic/use-layer-form.hook";
9
9
 
10
10
  export interface TextLayerFormState {
11
11
  text: string;
@@ -14,6 +14,7 @@ export interface TextLayerFormState {
14
14
  fontWeight: "normal" | "bold" | "300" | "700";
15
15
  color: string;
16
16
  textAlign: "left" | "center" | "right";
17
+ [key: string]: unknown;
17
18
  }
18
19
 
19
20
  interface UseTextLayerFormReturn {
@@ -36,7 +37,7 @@ export function useTextLayerForm(
36
37
  ): UseTextLayerFormReturn {
37
38
  const tokens = useAppDesignTokens();
38
39
 
39
- const form = useLayerForm<TextLayerFormState>({
40
+ const config: UseLayerFormConfig<TextLayerFormState> = {
40
41
  initialValues: {
41
42
  text: initialLayer?.content || "",
42
43
  fontSize: initialLayer?.fontSize || 48,
@@ -47,8 +48,8 @@ export function useTextLayerForm(
47
48
  textAlign: initialLayer?.textAlign || "center",
48
49
  },
49
50
  validators: {
50
- text: (value) => {
51
- if (!value || value.trim().length === 0) {
51
+ text: (value: unknown) => {
52
+ if (!value || (typeof value === "string" && value.trim().length === 0)) {
52
53
  return "Text content is required";
53
54
  }
54
55
  return null;
@@ -61,8 +62,10 @@ export function useTextLayerForm(
61
62
  fontWeight: formState.fontWeight,
62
63
  color: formState.color,
63
64
  textAlign: formState.textAlign,
64
- }),
65
- });
65
+ } as Partial<TextLayer>),
66
+ };
67
+
68
+ const form = useLayerForm<TextLayerFormState, Partial<TextLayer>>(config);
66
69
 
67
70
  const setText = (text: string) => form.updateField("text", text);
68
71
  const setFontSize = (size: number) => form.updateField("fontSize", size);