@umituz/react-native-photo-editor 1.0.4 → 1.0.6

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.
@@ -0,0 +1,31 @@
1
+ const js = require("@eslint/js");
2
+ const tseslint = require("@typescript-eslint/eslint-plugin");
3
+ const tsParser = require("@typescript-eslint/parser");
4
+
5
+ module.exports = [
6
+ js.configs.recommended,
7
+ {
8
+ files: ["**/*.ts", "**/*.tsx"],
9
+ languageOptions: {
10
+ parser: tsParser,
11
+ parserOptions: {
12
+ ecmaVersion: 2020,
13
+ sourceType: "module",
14
+ project: "./tsconfig.json",
15
+ },
16
+ },
17
+ plugins: {
18
+ "@typescript-eslint": tseslint,
19
+ },
20
+ rules: {
21
+ ...tseslint.configs.recommended.rules,
22
+ "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
23
+ "@typescript-eslint/explicit-function-return-type": "off",
24
+ "@typescript-eslint/no-explicit-any": "warn",
25
+ "no-console": "off",
26
+ },
27
+ },
28
+ {
29
+ ignores: ["node_modules/", "*.js"],
30
+ },
31
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-photo-editor",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "A powerful, generic photo editor for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -21,12 +21,27 @@
21
21
  "peerDependencies": {
22
22
  "react": "*",
23
23
  "react-native": "*",
24
- "@umituz/react-native-design-system": "*"
24
+ "@umituz/react-native-design-system": "*",
25
+ "react-native-gesture-handler": "*",
26
+ "react-native-reanimated": "*"
25
27
  },
26
28
  "dependencies": {
27
29
  "expo-image-picker": "*",
28
30
  "expo-media-library": "*",
29
31
  "expo-file-system": "*",
30
32
  "expo-image": "*"
33
+ },
34
+ "devDependencies": {
35
+ "@types/react": "*",
36
+ "@types/react-native": "*",
37
+ "@typescript-eslint/parser": "*",
38
+ "@typescript-eslint/eslint-plugin": "*",
39
+ "eslint": "*",
40
+ "typescript": "*",
41
+ "react-native-gesture-handler": "*",
42
+ "react-native-reanimated": "*",
43
+ "expo-application": "*",
44
+ "expo-device": "*",
45
+ "expo-linear-gradient": "*"
31
46
  }
32
47
  }
@@ -7,6 +7,7 @@ import {
7
7
  BottomSheetModal,
8
8
  SafeBottomSheetModalProvider,
9
9
  useSafeAreaInsets,
10
+ DesignTokens,
10
11
  } from "@umituz/react-native-design-system";
11
12
 
12
13
  import { EditorCanvas } from "./components/EditorCanvas";
@@ -18,11 +19,12 @@ import { LayerManager } from "./components/LayerManager";
18
19
  import { TextEditorSheet } from "./components/TextEditorSheet";
19
20
  import { createEditorStyles } from "./styles";
20
21
  import { usePhotoEditorUI } from "./hooks/usePhotoEditorUI";
22
+ import { Layer } from "./types";
21
23
 
22
24
  export interface EditorActions {
23
- addTextLayer: (tokens: any) => string;
24
- updateLayer: (id: string, updates: any) => void;
25
- getLayers: () => any[];
25
+ addTextLayer: (tokens: DesignTokens) => string;
26
+ updateLayer: (id: string, updates: Partial<Layer>) => void;
27
+ getLayers: () => Layer[];
26
28
  getActiveLayerId: () => string | null;
27
29
  }
28
30
 
@@ -15,7 +15,7 @@ import {
15
15
  interface AIMagicSheetProps {
16
16
  onGenerateCaption: (style: string) => void;
17
17
  isLoading?: boolean;
18
- t: (key: string) => string;
18
+ _t: (key: string) => string;
19
19
  }
20
20
 
21
21
  const AI_STYLES = [
@@ -30,7 +30,7 @@ const AI_STYLES = [
30
30
  export const AIMagicSheet: React.FC<AIMagicSheetProps> = ({
31
31
  onGenerateCaption,
32
32
  isLoading = false,
33
- t,
33
+ _t,
34
34
  }) => {
35
35
  const tokens = useAppDesignTokens();
36
36
  const [selectedStyle, setSelectedStyle] = useState<string | null>(null);
@@ -1,4 +1,4 @@
1
- import React, { useMemo } from "react";
1
+ import React from "react";
2
2
  import { StyleSheet, View } from "react-native";
3
3
  import { Gesture, GestureDetector } from "react-native-gesture-handler";
4
4
  import Animated, {
@@ -22,8 +22,8 @@ interface DraggableTextProps {
22
22
  scale?: number;
23
23
  opacity?: number;
24
24
  backgroundColor?: string;
25
- strokeColor?: string;
26
- strokeWidth?: number;
25
+ _strokeColor?: string;
26
+ _strokeWidth?: number;
27
27
  initialX: number;
28
28
  initialY: number;
29
29
  onDragEnd: (x: number, y: number) => void;
@@ -41,8 +41,8 @@ export const DraggableText: React.FC<DraggableTextProps> = ({
41
41
  scale = 1,
42
42
  opacity = 1,
43
43
  backgroundColor = "transparent",
44
- strokeColor,
45
- strokeWidth = 2,
44
+ _strokeColor,
45
+ _strokeWidth = 2,
46
46
  initialX,
47
47
  initialY,
48
48
  onDragEnd,
@@ -47,8 +47,8 @@ export const EditorCanvas: React.FC<EditorCanvasProps> = ({
47
47
  scale={textLayer.scale}
48
48
  opacity={textLayer.opacity}
49
49
  backgroundColor={textLayer.backgroundColor}
50
- strokeColor={textLayer.strokeColor}
51
- strokeWidth={textLayer.strokeWidth}
50
+ _strokeColor={textLayer.strokeColor}
51
+ _strokeWidth={textLayer.strokeWidth}
52
52
  initialX={textLayer.x}
53
53
  initialY={textLayer.y}
54
54
  onDragEnd={(x, y) => onLayerMove(layer.id, x, y)}
@@ -6,21 +6,14 @@ import {
6
6
  useAppDesignTokens,
7
7
  } from "@umituz/react-native-design-system";
8
8
 
9
- interface FilterOption {
10
- id: string;
11
- name: string;
12
- icon: string;
13
- value: number;
14
- }
15
-
16
- const FILTERS: FilterOption[] = [
17
- { id: "none", name: "None", icon: "close-circle", value: 0 },
18
- { id: "sepia", name: "Sepia", icon: "color-palette", value: 0.5 },
19
- { id: "grayscale", name: "B&W", icon: "contrast", value: 1 },
20
- { id: "vintage", name: "Vintage", icon: "time", value: 0.7 },
21
- { id: "warm", name: "Warm", icon: "sunny", value: 0.3 },
22
- { id: "cool", name: "Cool", icon: "snow", value: 0.3 },
23
- ];
9
+ const FILTERS = [
10
+ { id: "none", name: "None", icon: "close-circle" as const, value: 0 },
11
+ { id: "sepia", name: "Sepia", icon: "color-palette" as const, value: 0.5 },
12
+ { id: "grayscale", name: "B&W", icon: "contrast" as const, value: 1 },
13
+ { id: "vintage", name: "Vintage", icon: "time" as const, value: 0.7 },
14
+ { id: "warm", name: "Warm", icon: "sunny" as const, value: 0.3 },
15
+ { id: "cool", name: "Cool", icon: "snow" as const, value: 0.3 },
16
+ ] as const;
24
17
 
25
18
  interface FilterPickerProps {
26
19
  selectedFilter: string;
@@ -82,7 +75,7 @@ export const FilterPicker: React.FC<FilterPickerProps> = ({
82
75
  onPress={() => onSelectFilter(filter.id, filter.value)}
83
76
  >
84
77
  <AtomicIcon
85
- name={filter.icon as any}
78
+ name={filter.icon}
86
79
  size="lg"
87
80
  color={selectedFilter === filter.id ? "primary" : "textSecondary"}
88
81
  />
@@ -1,6 +1,7 @@
1
1
  import { useRef, useState, useCallback, useEffect } from "react";
2
2
  import { BottomSheetModalRef, DesignTokens } from "@umituz/react-native-design-system";
3
3
  import { usePhotoEditor } from "./usePhotoEditor";
4
+ import { Layer, TextLayer } from "../types";
4
5
 
5
6
  export const usePhotoEditorUI = (
6
7
  initialCaption: string | undefined,
@@ -32,16 +33,17 @@ export const usePhotoEditorUI = (
32
33
  useEffect(() => {
33
34
  if (initialCaption) {
34
35
  const id = addTextLayer(tokens);
35
- setTimeout(() => {
36
- updateLayer(id, { text: initialCaption } as any, true);
37
- }, 0);
36
+ void Promise.resolve().then(() => {
37
+ updateLayer(id, { text: initialCaption } as Partial<Layer>, true);
38
+ });
38
39
  }
39
- // eslint-disable-next-line react-hooks/exhaustive-deps
40
- }, []);
40
+ }, [initialCaption, addTextLayer, tokens]);
41
41
 
42
42
  const handleAddText = useCallback(() => {
43
43
  addTextLayer(tokens);
44
- setTimeout(() => textEditorSheetRef.current?.present(), 100);
44
+ void Promise.resolve().then(() => {
45
+ textEditorSheetRef.current?.present();
46
+ });
45
47
  }, [addTextLayer, tokens]);
46
48
 
47
49
  const handleTextLayerTap = useCallback(
@@ -49,8 +51,9 @@ export const usePhotoEditorUI = (
49
51
  selectLayer(layerId);
50
52
  const layer = layers.find((l) => l.id === layerId);
51
53
  if (layer?.type === "text") {
52
- setEditingText((layer as any).text || "");
53
- setFontSize((layer as any).fontSize || 48);
54
+ const textLayer = layer as TextLayer;
55
+ setEditingText(textLayer.text || "");
56
+ setFontSize(textLayer.fontSize || 48);
54
57
  textEditorSheetRef.current?.present();
55
58
  }
56
59
  },
@@ -63,10 +66,10 @@ export const usePhotoEditorUI = (
63
66
  text: editingText,
64
67
  fontSize,
65
68
  fontFamily: selectedFont,
66
- } as any);
69
+ } as Partial<Layer>);
67
70
  }
68
71
  textEditorSheetRef.current?.dismiss();
69
- }, [activeLayerId, editingText, fontSize, selectedFont, updateLayer]);
72
+ }, [activeLayerId, editingText, fontSize, selectedFont, updateLayer, textEditorSheetRef]);
70
73
 
71
74
  const handleSelectFilter = useCallback(
72
75
  (filterId: string, value: number) => {
package/tsconfig.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": ["ES2020"],
5
+ "allowJs": false,
6
+ "skipLibCheck": true,
7
+ "esModuleInterop": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "strict": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "moduleResolution": "node",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+ "jsx": "react-native",
16
+ "declaration": false,
17
+ "noUnusedLocals": false,
18
+ "noUnusedParameters": false,
19
+ "noImplicitReturns": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "baseUrl": "."
22
+ },
23
+ "include": ["src/**/*"],
24
+ "exclude": ["node_modules"]
25
+ }