@umituz/react-native-mascot 1.0.2 → 1.0.4

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,66 @@
1
+ /**
2
+ * PlayfulnessLevel Value Object
3
+ * Encapsulates playfulness validation and business rules
4
+ */
5
+
6
+ export class PlayfulnessLevel {
7
+ private readonly MIN = 0;
8
+ private readonly MAX = 1;
9
+ private readonly PLAYFUL_THRESHOLD = 0.5;
10
+ private readonly VERY_PLAYFUL_THRESHOLD = 0.8;
11
+
12
+ private constructor(public readonly value: number) {
13
+ if (value < this.MIN || value > this.MAX) {
14
+ throw new Error(`Playfulness level must be between ${this.MIN} and ${this.MAX}, got: ${value}`);
15
+ }
16
+ }
17
+
18
+ static create(value: number): PlayfulnessLevel {
19
+ return new PlayfulnessLevel(value);
20
+ }
21
+
22
+ /**
23
+ * Check if mascot is playful
24
+ */
25
+ isPlayful(): boolean {
26
+ return this.value >= this.PLAYFUL_THRESHOLD;
27
+ }
28
+
29
+ /**
30
+ * Check if mascot is very playful
31
+ */
32
+ isVeryPlayful(): boolean {
33
+ return this.value >= this.VERY_PLAYFUL_THRESHOLD;
34
+ }
35
+
36
+ /**
37
+ * Check if mascot is serious
38
+ */
39
+ isSerious(): boolean {
40
+ return this.value < 0.3;
41
+ }
42
+
43
+ /**
44
+ * Increase playfulness
45
+ */
46
+ increase(amount: number): PlayfulnessLevel {
47
+ const newValue = Math.min(this.MAX, this.value + amount);
48
+ return PlayfulnessLevel.create(newValue);
49
+ }
50
+
51
+ /**
52
+ * Decrease playfulness
53
+ */
54
+ decrease(amount: number): PlayfulnessLevel {
55
+ const newValue = Math.max(this.MIN, this.value - amount);
56
+ return PlayfulnessLevel.create(newValue);
57
+ }
58
+
59
+ equals(other: PlayfulnessLevel): boolean {
60
+ return this.value === other.value;
61
+ }
62
+
63
+ toJSON(): number {
64
+ return this.value;
65
+ }
66
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Value Objects
3
+ * Encapsulate domain logic and validation
4
+ */
5
+
6
+ export { Mood } from './Mood';
7
+ export { EnergyLevel } from './EnergyLevel';
8
+ export { FriendlinessLevel } from './FriendlinessLevel';
9
+ export { PlayfulnessLevel } from './PlayfulnessLevel';
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @umituz/react-native-mascot
3
3
  *
4
- * Interactive mascot system for React Native apps
4
+ * Interactive mascot system for React Native apps with DDD architecture
5
5
  */
6
6
 
7
7
  import type { MascotMood, AnimationSpeed } from './domain/types/MascotTypes';
@@ -9,6 +9,9 @@ import type { MascotMood, AnimationSpeed } from './domain/types/MascotTypes';
9
9
  // Domain - Entities
10
10
  export { Mascot } from './domain/entities/Mascot';
11
11
 
12
+ // Domain - Value Objects
13
+ export { Mood, EnergyLevel, FriendlinessLevel, PlayfulnessLevel } from './domain/value-objects';
14
+
12
15
  // Domain - Types
13
16
  export type {
14
17
  MascotType,
@@ -41,6 +44,35 @@ export type {
41
44
  IMascotRepository,
42
45
  } from './domain/interfaces/IMascotRepository';
43
46
 
47
+ // Application - Services
48
+ export { MascotService } from './application/services/MascotService';
49
+ export type { MascotTemplate } from './application/services/MascotService';
50
+
51
+ // Application - Errors
52
+ export {
53
+ MascotError,
54
+ MascotNotInitializedError,
55
+ AnimationNotFoundError,
56
+ InvalidEnergyLevelError,
57
+ InvalidFriendlinessLevelError,
58
+ InvalidPlayfulnessLevelError,
59
+ InvalidMoodTransitionError,
60
+ MascotNotFoundError,
61
+ TemplateNotFoundError,
62
+ } from './application/errors/MascotErrors';
63
+
64
+ // Application - DTOs
65
+ export type {
66
+ MascotDTO,
67
+ AnimationStateDTO,
68
+ MascotInitOptionsDTO,
69
+ AnimationPlaybackOptionsDTO,
70
+ MascotUpdateOptionsDTO,
71
+ } from './application/dto/MascotDTO';
72
+
73
+ // Infrastructure - DI
74
+ export { DIContainer } from './infrastructure/di/Container';
75
+
44
76
  // Infrastructure - Repositories
45
77
  export { MascotRepository } from './infrastructure/repositories/MascotRepository';
46
78
 
@@ -49,7 +81,7 @@ export { AnimationController } from './infrastructure/controllers/AnimationContr
49
81
 
50
82
  // Infrastructure - Managers
51
83
  export { AssetManager } from './infrastructure/managers/AssetManager';
52
- export { MascotFactory, type MascotTemplate } from './infrastructure/managers/MascotFactory';
84
+ export { MascotFactory, type MascotTemplate as FactoryMascotTemplate } from './infrastructure/managers/MascotFactory';
53
85
 
54
86
  // Presentation - Components
55
87
  export { MascotView } from './presentation/components/MascotView';
@@ -97,3 +129,9 @@ export const DEFAULT_ANIMATION_SPEEDS: AnimationSpeed[] = [
97
129
  'fast',
98
130
  'very-fast',
99
131
  ];
132
+
133
+ // Convenience export - get service instance
134
+ export const getMascotService = () => {
135
+ const { DIContainer } = require('./infrastructure/di/Container');
136
+ return DIContainer.getInstance().getMascotService();
137
+ };
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Dependency Injection Container
3
+ * Manages singleton instances and dependencies
4
+ */
5
+
6
+ import type { IMascotRepository } from '../../domain/interfaces/IMascotRepository';
7
+ import type { MascotService } from '../../application/services/MascotService';
8
+ import { AnimationController } from '../controllers/AnimationController';
9
+ import { AssetManager } from '../managers/AssetManager';
10
+ import { MascotRepository } from '../repositories/MascotRepository';
11
+
12
+ export class DIContainer {
13
+ private static _instance: DIContainer;
14
+ private _animationController: AnimationController | null = null;
15
+ private _assetManager: AssetManager | null = null;
16
+ private _repository: IMascotRepository | null = null;
17
+ private _mascotService: MascotService | null = null;
18
+
19
+ private constructor() {}
20
+
21
+ static getInstance(): DIContainer {
22
+ if (!this._instance) {
23
+ this._instance = new DIContainer();
24
+ }
25
+ return this._instance;
26
+ }
27
+
28
+ /**
29
+ * Get or create AnimationController singleton
30
+ */
31
+ getAnimationController(): AnimationController {
32
+ if (!this._animationController) {
33
+ this._animationController = new AnimationController();
34
+ }
35
+ return this._animationController;
36
+ }
37
+
38
+ /**
39
+ * Get or create AssetManager singleton
40
+ */
41
+ getAssetManager(): AssetManager {
42
+ if (!this._assetManager) {
43
+ this._assetManager = new AssetManager();
44
+ }
45
+ return this._assetManager;
46
+ }
47
+
48
+ /**
49
+ * Get or create MascotRepository singleton
50
+ */
51
+ getRepository(): IMascotRepository {
52
+ if (!this._repository) {
53
+ this._repository = new MascotRepository();
54
+ }
55
+ return this._repository;
56
+ }
57
+
58
+ /**
59
+ * Get or create MascotService singleton
60
+ */
61
+ getMascotService(): MascotService {
62
+ if (!this._mascotService) {
63
+ // Lazy import to avoid circular dependencies
64
+ const { MascotService } = require('../../application/services/MascotService');
65
+ this._mascotService = new MascotService(
66
+ this.getRepository(),
67
+ this.getAnimationController(),
68
+ this.getAssetManager()
69
+ );
70
+ }
71
+ return this._mascotService;
72
+ }
73
+
74
+ /**
75
+ * Reset all instances (useful for testing)
76
+ */
77
+ reset(): void {
78
+ this._animationController = null;
79
+ this._assetManager = null;
80
+ this._repository = null;
81
+ this._mascotService = null;
82
+ }
83
+
84
+ /**
85
+ * Check if container has been initialized
86
+ */
87
+ isInitialized(): boolean {
88
+ return this._mascotService !== null;
89
+ }
90
+ }
@@ -1,135 +1,53 @@
1
1
  /**
2
- * Mascot Context
3
- * Provides mascot state and functionality to components
2
+ * MascotContext
3
+ * Thin wrapper that provides MascotService to components
4
4
  */
5
5
 
6
- import React, { createContext, useContext, useState, useCallback, useRef } from 'react';
7
- import { Mascot } from '../../domain/entities/Mascot';
6
+ import React, { createContext, useContext, ReactNode } from 'react';
7
+ import type { Mascot } from '../../domain/entities/Mascot';
8
8
  import type { MascotConfig, MascotMood } from '../../domain/types/MascotTypes';
9
- import { MascotFactory } from '../../infrastructure/managers/MascotFactory';
10
- import { AnimationController } from '../../infrastructure/controllers/AnimationController';
11
9
  import type { AnimationOptions } from '../../domain/interfaces/IAnimationController';
10
+ import type { MascotService, MascotTemplate } from '../../application/services/MascotService';
11
+ import { DIContainer } from '../../infrastructure/di/Container';
12
12
 
13
13
  export interface MascotContextValue {
14
14
  mascot: Mascot | null;
15
15
  isPlaying: boolean;
16
16
  currentAnimation: string | null;
17
- initializeMascot: (config: MascotConfig) => void;
18
- initializeFromTemplate: (template: string, customizations?: Partial<MascotConfig>) => void;
19
- setMood: (mood: MascotMood) => void;
20
- playAnimation: (animationId: string, options?: AnimationOptions) => Promise<void>;
21
- stopAnimation: () => void;
22
- updateAppearance: (appearance: Partial<MascotConfig['appearance']>) => void;
23
- setVisible: (visible: boolean) => void;
17
+ service: MascotService;
24
18
  }
25
19
 
26
20
  const MascotContext = createContext<MascotContextValue | undefined>(undefined);
27
21
 
28
- export interface MascotProviderProps extends React.PropsWithChildren {
22
+ export interface MascotProviderProps {
23
+ children: ReactNode;
29
24
  initialConfig?: MascotConfig;
30
- template?: string;
25
+ template?: MascotTemplate;
31
26
  }
32
27
 
33
28
  export const MascotProvider: React.FC<MascotProviderProps> = ({
34
29
  children,
35
- initialConfig: _initialConfig,
36
- template: _template,
30
+ initialConfig,
31
+ template,
37
32
  }) => {
38
- const [mascot, setMascot] = useState<Mascot | null>(null);
39
- const [isPlaying, setIsPlaying] = useState(false);
40
- const [currentAnimation, setCurrentAnimation] = useState<string | null>(null);
41
- const animationControllerRef = useRef<AnimationController | null>(null);
42
-
43
- const initializeMascot = useCallback((config: MascotConfig) => {
44
- const newMascot = new Mascot(config);
45
- setMascot(newMascot);
46
- if (!animationControllerRef.current) {
47
- animationControllerRef.current = new AnimationController();
48
- }
49
- }, []);
50
-
51
- const initializeFromTemplate = useCallback((
52
- templateName: string,
53
- customizations?: Partial<MascotConfig>
54
- ) => {
55
- const template = templateName as 'friendly-bot' | 'cute-pet' | 'wise-owl' | 'pixel-hero';
56
- const newMascot = MascotFactory.createFromTemplate(template, customizations);
57
- setMascot(newMascot);
58
- if (!animationControllerRef.current) {
59
- animationControllerRef.current = new AnimationController();
60
- }
61
- }, []);
62
-
63
- const setMood = useCallback((mood: MascotMood) => {
64
- setMascot((prev) => {
65
- if (!prev) return null;
66
- prev.setMood(mood);
67
- return prev.clone();
68
- });
69
- }, []);
70
-
71
- const playAnimation = useCallback(async (animationId: string, options?: AnimationOptions) => {
72
- if (!mascot || !animationControllerRef.current) return;
73
-
74
- const animation = mascot.getAnimation(animationId);
75
- if (!animation) {
76
- console.warn(`Animation ${animationId} not found`);
77
- return;
78
- }
79
-
80
- setIsPlaying(true);
81
- setCurrentAnimation(animationId);
82
-
83
- if (animationControllerRef.current) {
84
- await animationControllerRef.current.play(animation, options);
85
- }
86
-
87
- setIsPlaying(false);
88
- setCurrentAnimation(null);
89
- }, [mascot]);
90
-
91
- const stopAnimation = useCallback(() => {
92
- if (animationControllerRef.current) {
93
- animationControllerRef.current.stop();
94
- }
95
- setIsPlaying(false);
96
- setCurrentAnimation(null);
97
- }, []);
98
-
99
- const updateAppearance = useCallback((appearance: Partial<MascotConfig['appearance']>) => {
100
- setMascot((prev) => {
101
- if (!prev) return null;
102
- prev.updateAppearance(appearance);
103
- return prev.clone();
104
- });
105
- }, []);
106
-
107
- const setVisible = useCallback((visible: boolean) => {
108
- setMascot((prev) => {
109
- if (!prev) return null;
110
- prev.setVisible(visible);
111
- return prev.clone();
112
- });
113
- }, []);
33
+ const container = DIContainer.getInstance();
34
+ const service = container.getMascotService();
35
+
36
+ // Auto-initialize if config or template provided
37
+ if (initialConfig) {
38
+ service.initialize(initialConfig);
39
+ } else if (template) {
40
+ service.fromTemplate(template);
41
+ }
114
42
 
115
43
  const value: MascotContextValue = {
116
- mascot,
117
- isPlaying,
118
- currentAnimation,
119
- initializeMascot,
120
- initializeFromTemplate,
121
- setMood,
122
- playAnimation,
123
- stopAnimation,
124
- updateAppearance,
125
- setVisible,
44
+ mascot: service.mascot,
45
+ isPlaying: service.isPlaying,
46
+ currentAnimation: service.currentAnimation,
47
+ service,
126
48
  };
127
49
 
128
- return (
129
- <MascotContext.Provider value={value}>
130
- {children}
131
- </MascotContext.Provider>
132
- );
50
+ return <MascotContext.Provider value={value}>{children}</MascotContext.Provider>;
133
51
  };
134
52
 
135
53
  export const useMascotContext = (): MascotContextValue => {