@umituz/react-native-mascot 1.0.3 → 1.0.7

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 (43) hide show
  1. package/README.md +60 -0
  2. package/package.json +2 -1
  3. package/src/application/dto/MascotDTO.ts +64 -0
  4. package/src/application/errors/MascotErrors.ts +76 -0
  5. package/src/application/services/AnimationStateManager.ts +69 -0
  6. package/src/application/services/AppearanceManagement.ts +40 -0
  7. package/src/application/services/MascotService.ts +203 -0
  8. package/src/application/services/PersonalityManagement.ts +39 -0
  9. package/src/application/services/StateHistory.ts +55 -0
  10. package/src/application/services/StateMachine.ts +154 -0
  11. package/src/application/services/StateTransitions.ts +73 -0
  12. package/src/application.ts +40 -0
  13. package/src/assets/index.ts +14 -19
  14. package/src/core.ts +62 -0
  15. package/src/domain/entities/Mascot.ts +197 -99
  16. package/src/domain/types/AnimationStateTypes.ts +148 -0
  17. package/src/domain/types/MascotTypes.ts +9 -0
  18. package/src/domain/value-objects/AnimationState.ts +126 -0
  19. package/src/domain/value-objects/EnergyLevel.ts +80 -0
  20. package/src/domain/value-objects/FriendlinessLevel.ts +66 -0
  21. package/src/domain/value-objects/Mood.ts +59 -0
  22. package/src/domain/value-objects/PlayfulnessLevel.ts +66 -0
  23. package/src/index.ts +16 -68
  24. package/src/infrastructure/controllers/AnimationController.ts +26 -122
  25. package/src/infrastructure/controllers/AnimationPlayer.ts +104 -0
  26. package/src/infrastructure/controllers/AnimationTimer.ts +62 -0
  27. package/src/infrastructure/controllers/EventManager.ts +108 -0
  28. package/src/infrastructure/di/Container.ts +153 -0
  29. package/src/infrastructure/managers/AssetManager.ts +134 -63
  30. package/src/infrastructure/managers/MascotBuilder.ts +89 -0
  31. package/src/infrastructure/managers/MascotFactory.ts +24 -176
  32. package/src/infrastructure/managers/MascotTemplates.ts +151 -0
  33. package/src/infrastructure/utils/LRUCache.ts +218 -0
  34. package/src/infrastructure.ts +24 -0
  35. package/src/presentation/components/LottieMascot.tsx +85 -0
  36. package/src/presentation/components/MascotView.tsx +42 -233
  37. package/src/presentation/components/SVGMascot.tsx +61 -0
  38. package/src/presentation/contexts/MascotContext.tsx +28 -111
  39. package/src/presentation/hooks/useMascot.ts +153 -169
  40. package/src/presentation/hooks/useMascotAnimation.ts +48 -94
  41. package/src/presentation/hooks/useMascotState.ts +213 -0
  42. package/src/presentation.ts +37 -0
  43. package/src/types.d.ts +4 -0
@@ -0,0 +1,154 @@
1
+ /**
2
+ * State Machine (120 lines)
3
+ * Core state transition logic with validation
4
+ */
5
+
6
+ import type { MascotAnimationState } from '../../domain/types/AnimationStateTypes';
7
+ import { AnimationState } from '../../domain/value-objects/AnimationState';
8
+ import { StateTransitions } from './StateTransitions';
9
+ import { StateHistory } from './StateHistory';
10
+
11
+ export interface StateMachineConfig {
12
+ enableAutoTransition?: boolean;
13
+ enableHistoryTracking?: boolean;
14
+ maxHistorySize?: number;
15
+ onStateChange?: (from: MascotAnimationState, to: MascotAnimationState) => void;
16
+ }
17
+
18
+ export class StateMachine {
19
+ private _currentState: AnimationState;
20
+ private _previousState: AnimationState | null = null;
21
+ private readonly _transitions: StateTransitions;
22
+ private readonly _history: StateHistory;
23
+ private readonly _config: Required<StateMachineConfig>;
24
+
25
+ constructor(
26
+ initialState: MascotAnimationState = 'idle',
27
+ config: StateMachineConfig = {}
28
+ ) {
29
+ this._currentState = AnimationState.create(initialState);
30
+ this._transitions = new StateTransitions();
31
+ this._history = new StateHistory(config.maxHistorySize || 50);
32
+ this._config = {
33
+ enableAutoTransition: config.enableAutoTransition ?? true,
34
+ enableHistoryTracking: config.enableHistoryTracking ?? true,
35
+ maxHistorySize: config.maxHistorySize ?? 50,
36
+ onStateChange: config.onStateChange ?? (() => {}),
37
+ };
38
+ }
39
+
40
+ get currentState(): AnimationState {
41
+ return this._currentState;
42
+ }
43
+
44
+ get currentStateValue(): MascotAnimationState {
45
+ return this._currentState.value;
46
+ }
47
+
48
+ get previousState(): AnimationState | null {
49
+ return this._previousState;
50
+ }
51
+
52
+ get history(): MascotAnimationState[] {
53
+ return this._history.getStates();
54
+ }
55
+
56
+ transitionTo(
57
+ newState: MascotAnimationState,
58
+ triggeredBy: 'user' | 'system' | 'auto-transition' = 'user'
59
+ ): void {
60
+ // Validate transition
61
+ if (!this._transitions.canTransitionTo(this.currentStateValue, newState)) {
62
+ const validTransitions = this._transitions
63
+ .getAvailableTransitions(this.currentStateValue)
64
+ .map((t) => t.to);
65
+ throw new Error(
66
+ `Cannot transition from '${this.currentStateValue}' to '${newState}'. ` +
67
+ `Valid transitions: ${validTransitions.join(', ')}`
68
+ );
69
+ }
70
+
71
+ // Store previous state
72
+ this._previousState = this._currentState;
73
+
74
+ // Track history
75
+ if (this._config.enableHistoryTracking) {
76
+ this._history.add(this.currentStateValue, triggeredBy);
77
+ }
78
+
79
+ // Update state
80
+ const oldState = this.currentStateValue;
81
+ this._currentState = AnimationState.create(newState);
82
+
83
+ // Notify
84
+ this._config.onStateChange(oldState, newState);
85
+
86
+ // Schedule auto-transition
87
+ if (this._config.enableAutoTransition && !this._currentState.shouldLoop()) {
88
+ const next = this._currentState.getNextState();
89
+ if (next) {
90
+ this._scheduleAutoTransition(next);
91
+ }
92
+ }
93
+ }
94
+
95
+ // Shortcut methods
96
+ triggerSuccess(): void {
97
+ this.transitionTo('success', 'system');
98
+ }
99
+
100
+ triggerError(): void {
101
+ this.transitionTo('error', 'system');
102
+ }
103
+
104
+ startLoading(): void {
105
+ this.transitionTo('loading', 'system');
106
+ }
107
+
108
+ stopLoading(success: boolean): void {
109
+ if (this.currentStateValue === 'loading') {
110
+ this.transitionTo(success ? 'success' : 'error', 'system');
111
+ }
112
+ }
113
+
114
+ reset(): void {
115
+ this.transitionTo('idle', 'system');
116
+ }
117
+
118
+ // State queries
119
+ isLooping(): boolean {
120
+ return this._currentState.shouldLoop();
121
+ }
122
+
123
+ isIdle(): boolean {
124
+ return this.currentStateValue === 'idle';
125
+ }
126
+
127
+ isLoading(): boolean {
128
+ return this.currentStateValue === 'loading';
129
+ }
130
+
131
+ // Auto-transition scheduling
132
+ private _autoTransitionTimer: NodeJS.Timeout | null = null;
133
+
134
+ private _scheduleAutoTransition(targetState: MascotAnimationState): void {
135
+ const duration = this._currentState.getDuration();
136
+ const delay = this._currentState.getTransitionDelay(targetState);
137
+
138
+ this._autoTransitionTimer = setTimeout(() => {
139
+ try {
140
+ this.transitionTo(targetState, 'auto-transition');
141
+ } catch (error) {
142
+ console.warn('Auto-transition failed:', error);
143
+ }
144
+ }, duration + delay);
145
+ }
146
+
147
+ destroy(): void {
148
+ if (this._autoTransitionTimer) {
149
+ clearTimeout(this._autoTransitionTimer);
150
+ }
151
+ this._history.clear();
152
+ this._config.onStateChange = () => {};
153
+ }
154
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * State Transitions (80 lines)
3
+ * Transition rules and validation
4
+ */
5
+
6
+ import type { MascotAnimationState } from '../../domain/types/AnimationStateTypes';
7
+
8
+ export interface StateTransition {
9
+ from: MascotAnimationState;
10
+ to: MascotAnimationState;
11
+ condition?: 'always' | 'on-success' | 'on-error' | 'on-complete';
12
+ delay?: number;
13
+ }
14
+
15
+ export class StateTransitions {
16
+ private readonly _transitions: Map<MascotAnimationState, StateTransition[]>;
17
+
18
+ constructor() {
19
+ this._transitions = new Map();
20
+ this._initializeTransitions();
21
+ }
22
+
23
+ canTransitionTo(from: MascotAnimationState, to: MascotAnimationState): boolean {
24
+ const transitions = this._transitions.get(from);
25
+ if (!transitions) return false;
26
+ return transitions.some((t) => t.to === to);
27
+ }
28
+
29
+ getAvailableTransitions(state: MascotAnimationState): StateTransition[] {
30
+ return this._transitions.get(state) || [];
31
+ }
32
+
33
+ getTransitionDelay(from: MascotAnimationState, to: MascotAnimationState): number {
34
+ const transitions = this._transitions.get(from);
35
+ const transition = transitions?.find((t) => t.to === to);
36
+ return transition?.delay || 0;
37
+ }
38
+
39
+ private _initializeTransitions(): void {
40
+ // Idle transitions
41
+ this._addTransition('idle', 'loading', 'always');
42
+ this._addTransition('idle', 'empty', 'always');
43
+ this._addTransition('idle', 'guide', 'always');
44
+
45
+ // Loading transitions
46
+ this._addTransition('loading', 'success', 'on-success');
47
+ this._addTransition('loading', 'error', 'on-error');
48
+
49
+ // Success transitions
50
+ this._addTransition('success', 'idle', 'on-complete', 100);
51
+
52
+ // Error transitions
53
+ this._addTransition('error', 'idle', 'on-complete', 100);
54
+
55
+ // Empty transitions
56
+ this._addTransition('empty', 'idle', 'always');
57
+
58
+ // Guide transitions
59
+ this._addTransition('guide', 'idle', 'on-complete', 200);
60
+ }
61
+
62
+ private _addTransition(
63
+ from: MascotAnimationState,
64
+ to: MascotAnimationState,
65
+ condition: StateTransition['condition'] = 'always',
66
+ delay: number = 0
67
+ ): void {
68
+ if (!this._transitions.has(from)) {
69
+ this._transitions.set(from, []);
70
+ }
71
+ this._transitions.get(from)!.push({ from, to, condition, delay });
72
+ }
73
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Application Layer Exports (60 lines)
3
+ * Services, use cases, and DTOs
4
+ */
5
+
6
+ // Application - Services
7
+ export { AnimationStateManager } from './application/services/AnimationStateManager';
8
+ export type { AnimationStateManagerConfig } from './application/services/AnimationStateManager';
9
+
10
+ export { MascotService } from './application/services/MascotService';
11
+ export type { MascotTemplate } from './application/services/MascotService';
12
+
13
+ export { PersonalityManagement } from './application/services/PersonalityManagement';
14
+ export { AppearanceManagement } from './application/services/AppearanceManagement';
15
+
16
+ export { StateMachine } from './application/services/StateMachine';
17
+ export { StateTransitions } from './application/services/StateTransitions';
18
+ export { StateHistory } from './application/services/StateHistory';
19
+
20
+ // Application - Errors
21
+ export {
22
+ MascotError,
23
+ MascotNotInitializedError,
24
+ AnimationNotFoundError,
25
+ InvalidEnergyLevelError,
26
+ InvalidFriendlinessLevelError,
27
+ InvalidPlayfulnessLevelError,
28
+ InvalidMoodTransitionError,
29
+ MascotNotFoundError,
30
+ TemplateNotFoundError,
31
+ } from './application/errors/MascotErrors';
32
+
33
+ // Application - DTOs
34
+ export type {
35
+ MascotDTO,
36
+ AnimationStateDTO,
37
+ MascotInitOptionsDTO,
38
+ AnimationPlaybackOptionsDTO,
39
+ MascotUpdateOptionsDTO,
40
+ } from './application/dto/MascotDTO';
@@ -3,21 +3,16 @@
3
3
  * Pre-configured mascots and animations
4
4
  */
5
5
 
6
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */
7
6
  import type { MascotConfig, MascotAnimationType } from '../domain/types/MascotTypes';
7
+ import type { MascotAnimation } from '../domain/types/MascotTypes';
8
8
 
9
- // eslint-disable-next-line @typescript-eslint/no-var-requires
10
- const idleAnim = require('./lottie/idle.json');
11
- // eslint-disable-next-line @typescript-eslint/no-var-requires
12
- const waveAnim = require('./lottie/wave.json');
13
- // eslint-disable-next-line @typescript-eslint/no-var-requires
14
- const jumpAnim = require('./lottie/jump.json');
15
- // eslint-disable-next-line @typescript-eslint/no-var-requires
16
- const successAnim = require('./lottie/success.json');
17
- // eslint-disable-next-line @typescript-eslint/no-var-requires
18
- const errorAnim = require('./lottie/error.json');
19
- // eslint-disable-next-line @typescript-eslint/no-var-requires
20
- const danceAnim = require('./lottie/dance.json');
9
+ // Import JSON animations
10
+ import idleAnim from './lottie/idle.json';
11
+ import waveAnim from './lottie/wave.json';
12
+ import jumpAnim from './lottie/jump.json';
13
+ import successAnim from './lottie/success.json';
14
+ import errorAnim from './lottie/error.json';
15
+ import danceAnim from './lottie/dance.json';
21
16
 
22
17
  export const BUILT_IN_MASCOTS: Record<string, MascotConfig> = {
23
18
  'happy-robot': {
@@ -42,7 +37,7 @@ export const BUILT_IN_MASCOTS: Record<string, MascotConfig> = {
42
37
  id: 'idle',
43
38
  name: 'Idle',
44
39
  type: 'idle' as MascotAnimationType,
45
- source: idleAnim,
40
+ source: idleAnim as MascotAnimation['source'],
46
41
  loop: true,
47
42
  autoplay: true,
48
43
  },
@@ -50,35 +45,35 @@ export const BUILT_IN_MASCOTS: Record<string, MascotConfig> = {
50
45
  id: 'wave',
51
46
  name: 'Wave',
52
47
  type: 'action' as MascotAnimationType,
53
- source: waveAnim,
48
+ source: waveAnim as MascotAnimation['source'],
54
49
  loop: false,
55
50
  },
56
51
  {
57
52
  id: 'jump',
58
53
  name: 'Jump',
59
54
  type: 'action' as MascotAnimationType,
60
- source: jumpAnim,
55
+ source: jumpAnim as MascotAnimation['source'],
61
56
  loop: false,
62
57
  },
63
58
  {
64
59
  id: 'success',
65
60
  name: 'Success',
66
61
  type: 'reaction' as MascotAnimationType,
67
- source: successAnim,
62
+ source: successAnim as MascotAnimation['source'],
68
63
  loop: false,
69
64
  },
70
65
  {
71
66
  id: 'error',
72
67
  name: 'Error',
73
68
  type: 'reaction' as MascotAnimationType,
74
- source: errorAnim,
69
+ source: errorAnim as MascotAnimation['source'],
75
70
  loop: false,
76
71
  },
77
72
  {
78
73
  id: 'dance',
79
74
  name: 'Dance',
80
75
  type: 'action' as MascotAnimationType,
81
- source: danceAnim,
76
+ source: danceAnim as MascotAnimation['source'],
82
77
  loop: true,
83
78
  },
84
79
  ],
package/src/core.ts ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Core Domain Exports (80 lines)
3
+ * Domain entities, value objects, and types
4
+ */
5
+
6
+ // Domain - Entities
7
+ export { Mascot } from './domain/entities/Mascot';
8
+
9
+ // Domain - Value Objects
10
+ export { Mood } from './domain/value-objects/Mood';
11
+ export { EnergyLevel } from './domain/value-objects/EnergyLevel';
12
+ export { FriendlinessLevel } from './domain/value-objects/FriendlinessLevel';
13
+ export { PlayfulnessLevel } from './domain/value-objects/PlayfulnessLevel';
14
+ export { AnimationState } from './domain/value-objects/AnimationState';
15
+
16
+ // Domain - Types - Animation States
17
+ export type {
18
+ MascotAnimationState,
19
+ MascotStateConfig,
20
+ StateTransition,
21
+ StateHistoryEntry,
22
+ MascotSize,
23
+ MascotSizeConfig,
24
+ } from './domain/types/AnimationStateTypes';
25
+
26
+ export {
27
+ DEFAULT_STATE_CONFIGS,
28
+ DEFAULT_SIZE_CONFIG,
29
+ STATE_TRANSITIONS,
30
+ } from './domain/types/AnimationStateTypes';
31
+
32
+ // Domain - Types - Mascot
33
+ export type {
34
+ MascotType,
35
+ MascotStyle,
36
+ MascotAnimationType,
37
+ MascotAppearance,
38
+ MascotAccessory,
39
+ MascotPersonality,
40
+ MascotAnimation,
41
+ MascotConfig,
42
+ MascotState,
43
+ MascotInteraction,
44
+ MascotMood,
45
+ AnimationSpeed,
46
+ } from './domain/types/MascotTypes';
47
+
48
+ // Domain - Interfaces
49
+ export type {
50
+ IAnimationController,
51
+ AnimationEvent,
52
+ AnimationOptions,
53
+ } from './domain/interfaces/IAnimationController';
54
+
55
+ export type {
56
+ IAssetManager,
57
+ AssetCache,
58
+ } from './domain/interfaces/IAssetManager';
59
+
60
+ export type {
61
+ IMascotRepository,
62
+ } from './domain/interfaces/IMascotRepository';