@umituz/react-native-mascot 1.0.1

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,104 @@
1
+ /**
2
+ * Built-in Mascot Assets
3
+ * Pre-configured mascots and animations
4
+ */
5
+
6
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
7
+ import type { MascotConfig, MascotAnimationType } from '../domain/types/MascotTypes';
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');
21
+
22
+ export const BUILT_IN_MASCOTS: Record<string, MascotConfig> = {
23
+ 'happy-robot': {
24
+ id: 'happy-robot',
25
+ name: 'Happy Robot',
26
+ type: 'lottie',
27
+ personality: {
28
+ mood: 'happy',
29
+ energy: 0.8,
30
+ friendliness: 0.9,
31
+ playfulness: 0.7,
32
+ },
33
+ appearance: {
34
+ baseColor: '#4A90E2',
35
+ accentColor: '#50E3C2',
36
+ accessories: [],
37
+ style: 'cartoon',
38
+ scale: 1,
39
+ },
40
+ animations: [
41
+ {
42
+ id: 'idle',
43
+ name: 'Idle',
44
+ type: 'idle' as MascotAnimationType,
45
+ source: idleAnim,
46
+ loop: true,
47
+ autoplay: true,
48
+ },
49
+ {
50
+ id: 'wave',
51
+ name: 'Wave',
52
+ type: 'action' as MascotAnimationType,
53
+ source: waveAnim,
54
+ loop: false,
55
+ },
56
+ {
57
+ id: 'jump',
58
+ name: 'Jump',
59
+ type: 'action' as MascotAnimationType,
60
+ source: jumpAnim,
61
+ loop: false,
62
+ },
63
+ {
64
+ id: 'success',
65
+ name: 'Success',
66
+ type: 'reaction' as MascotAnimationType,
67
+ source: successAnim,
68
+ loop: false,
69
+ },
70
+ {
71
+ id: 'error',
72
+ name: 'Error',
73
+ type: 'reaction' as MascotAnimationType,
74
+ source: errorAnim,
75
+ loop: false,
76
+ },
77
+ {
78
+ id: 'dance',
79
+ name: 'Dance',
80
+ type: 'action' as MascotAnimationType,
81
+ source: danceAnim,
82
+ loop: true,
83
+ },
84
+ ],
85
+ interactive: true,
86
+ touchEnabled: true,
87
+ soundEnabled: false,
88
+ },
89
+ };
90
+
91
+ // Helper function to get built-in mascot
92
+ export function getBuiltInMascot(id: string): MascotConfig | undefined {
93
+ return BUILT_IN_MASCOTS[id];
94
+ }
95
+
96
+ // Helper function to get all built-in mascot IDs
97
+ export function getBuiltInMascotIds(): string[] {
98
+ return Object.keys(BUILT_IN_MASCOTS);
99
+ }
100
+
101
+ // Helper function to check if mascot is built-in
102
+ export function isBuiltInMascot(id: string): boolean {
103
+ return id in BUILT_IN_MASCOTS;
104
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Mascot Entity
3
+ * Core mascot representation following DDD principles
4
+ */
5
+
6
+ import type {
7
+ MascotConfig,
8
+ MascotPersonality,
9
+ MascotAppearance,
10
+ MascotAnimation,
11
+ MascotState,
12
+ MascotType,
13
+ MascotMood,
14
+ MascotAccessory,
15
+ } from '../types/MascotTypes';
16
+
17
+ export class Mascot {
18
+ readonly id: string;
19
+ readonly name: string;
20
+ readonly type: MascotType;
21
+ private _personality: MascotPersonality;
22
+ private _appearance: MascotAppearance;
23
+ private readonly _animations: Map<string, MascotAnimation>;
24
+ private readonly _config: MascotConfig;
25
+ private _state: MascotState;
26
+ private _interactions: Map<string, () => void | Promise<void>>;
27
+
28
+ constructor(config: MascotConfig) {
29
+ this.id = config.id;
30
+ this.name = config.name;
31
+ this.type = config.type;
32
+ this._personality = config.personality;
33
+ this._appearance = config.appearance;
34
+ this._animations = new Map(
35
+ config.animations.map((anim) => [anim.id, anim])
36
+ );
37
+ this._config = config;
38
+ this._state = {
39
+ currentMood: config.personality.mood,
40
+ currentAnimation: null,
41
+ isAnimating: false,
42
+ isVisible: true,
43
+ };
44
+ this._interactions = new Map();
45
+ }
46
+
47
+ // Getters
48
+ get personality(): MascotPersonality {
49
+ return { ...this._personality };
50
+ }
51
+
52
+ get appearance(): MascotAppearance {
53
+ return { ...this._appearance };
54
+ }
55
+
56
+ get state(): MascotState {
57
+ return { ...this._state };
58
+ }
59
+
60
+ get config(): MascotConfig {
61
+ return { ...this._config };
62
+ }
63
+
64
+ get animations(): MascotAnimation[] {
65
+ return Array.from(this._animations.values());
66
+ }
67
+
68
+ get interactive(): boolean {
69
+ return this._config.interactive ?? false;
70
+ }
71
+
72
+ get touchEnabled(): boolean {
73
+ return this._config.touchEnabled ?? true;
74
+ }
75
+
76
+ get soundEnabled(): boolean {
77
+ return this._config.soundEnabled ?? false;
78
+ }
79
+
80
+ // Personality Management
81
+ setMood(mood: MascotMood): void {
82
+ this._personality.mood = mood;
83
+ this._state.currentMood = mood;
84
+ }
85
+
86
+ setEnergy(energy: number): void {
87
+ if (energy < 0 || energy > 1) {
88
+ throw new Error('Energy must be between 0 and 1');
89
+ }
90
+ this._personality.energy = energy;
91
+ }
92
+
93
+ setFriendliness(friendliness: number): void {
94
+ if (friendliness < 0 || friendliness > 1) {
95
+ throw new Error('Friendliness must be between 0 and 1');
96
+ }
97
+ this._personality.friendliness = friendliness;
98
+ }
99
+
100
+ setPlayfulness(playfulness: number): void {
101
+ if (playfulness < 0 || playfulness > 1) {
102
+ throw new Error('Playfulness must be between 0 and 1');
103
+ }
104
+ this._personality.playfulness = playfulness;
105
+ }
106
+
107
+ // Appearance Management
108
+ updateAppearance(appearance: Partial<MascotAppearance>): void {
109
+ this._appearance = {
110
+ ...this._appearance,
111
+ ...appearance,
112
+ accessories: appearance.accessories ?? this._appearance.accessories,
113
+ };
114
+ }
115
+
116
+ setBaseColor(color: string): void {
117
+ this._appearance.baseColor = color;
118
+ }
119
+
120
+ setAccentColor(color: string): void {
121
+ this._appearance.accentColor = color;
122
+ }
123
+
124
+ addAccessory(accessory: {
125
+ id: string;
126
+ type: string;
127
+ color?: string;
128
+ position?: { x: number; y: number };
129
+ }): void {
130
+ const newAccessory: MascotAccessory = {
131
+ id: accessory.id,
132
+ type: accessory.type as MascotAccessory['type'],
133
+ color: accessory.color,
134
+ position: accessory.position,
135
+ visible: true,
136
+ };
137
+ this._appearance.accessories = [
138
+ ...this._appearance.accessories.filter((a) => a.id !== accessory.id),
139
+ newAccessory,
140
+ ];
141
+ }
142
+
143
+ removeAccessory(accessoryId: string): void {
144
+ this._appearance.accessories = this._appearance.accessories.filter(
145
+ (a) => a.id !== accessoryId
146
+ );
147
+ }
148
+
149
+ // Animation Management
150
+ getAnimation(animationId: string): MascotAnimation | undefined {
151
+ return this._animations.get(animationId);
152
+ }
153
+
154
+ getAnimationsByType(type: string): MascotAnimation[] {
155
+ return this.animations.filter((anim) => anim.type === type);
156
+ }
157
+
158
+ // State Management
159
+ startAnimation(animationId: string): void {
160
+ const animation = this._animations.get(animationId);
161
+ if (!animation) {
162
+ throw new Error(`Animation ${animationId} not found`);
163
+ }
164
+ this._state.currentAnimation = animationId;
165
+ this._state.isAnimating = true;
166
+ }
167
+
168
+ stopAnimation(): void {
169
+ this._state.isAnimating = false;
170
+ this._state.currentAnimation = null;
171
+ }
172
+
173
+ setVisible(visible: boolean): void {
174
+ this._state.isVisible = visible;
175
+ }
176
+
177
+ setPosition(position: { x: number; y: number }): void {
178
+ this._state.position = position;
179
+ }
180
+
181
+ // Interaction Management
182
+ registerInteraction(
183
+ id: string,
184
+ handler: () => void | Promise<void>
185
+ ): void {
186
+ this._interactions.set(id, handler);
187
+ }
188
+
189
+ unregisterInteraction(id: string): void {
190
+ this._interactions.delete(id);
191
+ }
192
+
193
+ async triggerInteraction(id: string): Promise<void> {
194
+ const handler = this._interactions.get(id);
195
+ if (handler) {
196
+ await handler();
197
+ }
198
+ }
199
+
200
+ // Utility Methods
201
+ clone(): Mascot {
202
+ return new Mascot(this._config);
203
+ }
204
+
205
+ toJSON(): object {
206
+ return {
207
+ id: this.id,
208
+ name: this.name,
209
+ type: this.type,
210
+ personality: this._personality,
211
+ appearance: this._appearance,
212
+ state: this._state,
213
+ config: this._config,
214
+ };
215
+ }
216
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Animation Controller Interface
3
+ * Defines contract for animation playback control
4
+ */
5
+
6
+ import type { MascotAnimation } from '../types/MascotTypes';
7
+
8
+ export interface IAnimationController {
9
+ /**
10
+ * Play an animation
11
+ */
12
+ play(animation: MascotAnimation, options?: AnimationOptions): Promise<void>;
13
+
14
+ /**
15
+ * Pause current animation
16
+ */
17
+ pause(): void;
18
+
19
+ /**
20
+ * Resume paused animation
21
+ */
22
+ resume(): void;
23
+
24
+ /**
25
+ * Stop current animation
26
+ */
27
+ stop(): void;
28
+
29
+ /**
30
+ * Get current animation progress (0-1)
31
+ */
32
+ getProgress(): number;
33
+
34
+ /**
35
+ * Set animation progress (0-1)
36
+ */
37
+ setProgress(progress: number): void;
38
+
39
+ /**
40
+ * Set animation speed multiplier
41
+ */
42
+ setSpeed(speed: number): void;
43
+
44
+ /**
45
+ * Check if currently playing
46
+ */
47
+ isPlaying(): boolean;
48
+
49
+ /**
50
+ * Add event listener
51
+ */
52
+ on(
53
+ event: AnimationEvent,
54
+ callback: (data?: unknown) => void
55
+ ): () => void;
56
+
57
+ /**
58
+ * Remove event listener
59
+ */
60
+ off(event: AnimationEvent, callback: (data?: unknown) => void): void;
61
+ }
62
+
63
+ export type AnimationEvent =
64
+ | 'start'
65
+ | 'finish'
66
+ | 'pause'
67
+ | 'resume'
68
+ | 'progress'
69
+ | 'error';
70
+
71
+ export interface AnimationOptions {
72
+ speed?: number;
73
+ loop?: boolean;
74
+ autoplay?: boolean;
75
+ onStart?: () => void;
76
+ onFinish?: () => void;
77
+ onError?: (error: Error) => void;
78
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Asset Manager Interface
3
+ * Defines contract for loading and managing mascot assets
4
+ */
5
+
6
+ import type { MascotAnimation } from '../types/MascotTypes';
7
+
8
+ export interface IAssetManager {
9
+ /**
10
+ * Load a Lottie animation
11
+ */
12
+ loadLottieAnimation(source: string | object): Promise<MascotAnimation>;
13
+
14
+ /**
15
+ * Load an SVG asset
16
+ */
17
+ loadSVGAsset(source: string): Promise<string>;
18
+
19
+ /**
20
+ * Preload multiple animations
21
+ */
22
+ preloadAnimations(sources: Array<string | object>): Promise<void>;
23
+
24
+ /**
25
+ * Clear cached assets
26
+ */
27
+ clearCache(): void;
28
+
29
+ /**
30
+ * Get asset URL or path
31
+ */
32
+ getAssetUrl(assetId: string): string | null;
33
+
34
+ /**
35
+ * Check if asset is loaded
36
+ */
37
+ isAssetLoaded(assetId: string): boolean;
38
+
39
+ /**
40
+ * Get all loaded assets
41
+ */
42
+ getLoadedAssets(): string[];
43
+ }
44
+
45
+ export interface AssetCache {
46
+ [key: string]: {
47
+ data: unknown;
48
+ timestamp: number;
49
+ size: number;
50
+ };
51
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Mascot Repository Interface
3
+ * Defines contract for mascot data persistence and retrieval
4
+ */
5
+
6
+ import type { Mascot } from '../entities/Mascot';
7
+ import type { MascotConfig } from '../types/MascotTypes';
8
+
9
+ export interface IMascotRepository {
10
+ /**
11
+ * Save a mascot configuration
12
+ */
13
+ save(config: MascotConfig): Promise<void>;
14
+
15
+ /**
16
+ * Load a mascot by ID
17
+ */
18
+ load(id: string): Promise<Mascot | null>;
19
+
20
+ /**
21
+ * Load all mascots
22
+ */
23
+ loadAll(): Promise<Mascot[]>;
24
+
25
+ /**
26
+ * Delete a mascot
27
+ */
28
+ delete(id: string): Promise<void>;
29
+
30
+ /**
31
+ * Update mascot configuration
32
+ */
33
+ update(id: string, config: Partial<MascotConfig>): Promise<void>;
34
+
35
+ /**
36
+ * Check if mascot exists
37
+ */
38
+ exists(id: string): Promise<boolean>;
39
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Mascot Types
3
+ * Core type definitions for the mascot system
4
+ */
5
+
6
+ export type MascotType = 'lottie' | 'svg' | 'custom';
7
+
8
+ export type MascotStyle = 'minimal' | 'cartoon' | 'realistic' | 'pixel';
9
+
10
+ export type MascotMood = 'happy' | 'sad' | 'excited' | 'thinking' | 'angry' | 'neutral' | 'surprised';
11
+
12
+ export type MascotAnimationType = 'idle' | 'action' | 'reaction' | 'transition';
13
+
14
+ export type AnimationSpeed = 'very-slow' | 'slow' | 'normal' | 'fast' | 'very-fast';
15
+
16
+ export interface MascotAppearance {
17
+ baseColor: string;
18
+ accentColor: string;
19
+ secondaryColor?: string;
20
+ accessories: MascotAccessory[];
21
+ style: MascotStyle;
22
+ scale?: number;
23
+ }
24
+
25
+ export interface MascotAccessory {
26
+ id: string;
27
+ type: 'glasses' | 'hat' | 'bow' | 'crown' | 'headphones' | 'mask' | 'custom';
28
+ color?: string;
29
+ position?: { x: number; y: number };
30
+ visible?: boolean;
31
+ }
32
+
33
+ export interface MascotPersonality {
34
+ mood: MascotMood;
35
+ energy: number; // 0-1
36
+ friendliness: number; // 0-1
37
+ playfulness: number; // 0-1
38
+ }
39
+
40
+ export interface MascotAnimation {
41
+ id: string;
42
+ name: string;
43
+ type: MascotAnimationType;
44
+ source: string | object;
45
+ loop: boolean;
46
+ duration?: number;
47
+ speed?: number;
48
+ autoplay?: boolean;
49
+ }
50
+
51
+ export interface MascotConfig {
52
+ id: string;
53
+ name: string;
54
+ type: MascotType;
55
+ personality: MascotPersonality;
56
+ appearance: MascotAppearance;
57
+ animations: MascotAnimation[];
58
+ interactive?: boolean;
59
+ touchEnabled?: boolean;
60
+ soundEnabled?: boolean;
61
+ }
62
+
63
+ export interface MascotState {
64
+ currentMood: MascotMood;
65
+ currentAnimation: string | null;
66
+ isAnimating: boolean;
67
+ isVisible: boolean;
68
+ position?: { x: number; y: number };
69
+ }
70
+
71
+ export interface MascotInteraction {
72
+ type: 'tap' | 'longPress' | 'drag' | 'pinch' | 'custom';
73
+ handler: () => void | Promise<void>;
74
+ animation?: string;
75
+ }
package/src/index.ts ADDED
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @umituz/react-native-mascot
3
+ *
4
+ * Interactive mascot system for React Native apps
5
+ */
6
+
7
+ import type { MascotMood, AnimationSpeed } from './domain/types/MascotTypes';
8
+
9
+ // Domain - Entities
10
+ export { Mascot } from './domain/entities/Mascot';
11
+
12
+ // Domain - Types
13
+ export type {
14
+ MascotType,
15
+ MascotStyle,
16
+ MascotAnimationType,
17
+ MascotAppearance,
18
+ MascotAccessory,
19
+ MascotPersonality,
20
+ MascotAnimation,
21
+ MascotConfig,
22
+ MascotState,
23
+ MascotInteraction,
24
+ MascotMood,
25
+ AnimationSpeed,
26
+ } from './domain/types/MascotTypes';
27
+
28
+ // Domain - Interfaces
29
+ export type {
30
+ IAnimationController,
31
+ AnimationEvent,
32
+ AnimationOptions,
33
+ } from './domain/interfaces/IAnimationController';
34
+
35
+ export type {
36
+ IAssetManager,
37
+ AssetCache,
38
+ } from './domain/interfaces/IAssetManager';
39
+
40
+ export type {
41
+ IMascotRepository,
42
+ } from './domain/interfaces/IMascotRepository';
43
+
44
+ // Infrastructure - Repositories
45
+ export { MascotRepository } from './infrastructure/repositories/MascotRepository';
46
+
47
+ // Infrastructure - Controllers
48
+ export { AnimationController } from './infrastructure/controllers/AnimationController';
49
+
50
+ // Infrastructure - Managers
51
+ export { AssetManager } from './infrastructure/managers/AssetManager';
52
+ export { MascotFactory, type MascotTemplate } from './infrastructure/managers/MascotFactory';
53
+
54
+ // Presentation - Components
55
+ export { MascotView } from './presentation/components/MascotView';
56
+ export type { MascotViewProps } from './presentation/components/MascotView';
57
+
58
+ // Presentation - Hooks
59
+ export { useMascot } from './presentation/hooks/useMascot';
60
+ export type {
61
+ UseMascotOptions,
62
+ UseMascotReturn,
63
+ } from './presentation/hooks/useMascot';
64
+
65
+ export { useMascotAnimation } from './presentation/hooks/useMascotAnimation';
66
+ export type {
67
+ UseMascotAnimationOptions,
68
+ UseMascotAnimationReturn,
69
+ } from './presentation/hooks/useMascotAnimation';
70
+
71
+ // Presentation - Contexts
72
+ export { MascotProvider, useMascotContext } from './presentation/contexts/MascotContext';
73
+ export type { MascotProviderProps, MascotContextValue } from './presentation/contexts/MascotContext';
74
+
75
+ // Constants
76
+ export const MASCOT_TEMPLATES = [
77
+ 'friendly-bot',
78
+ 'cute-pet',
79
+ 'wise-owl',
80
+ 'pixel-hero',
81
+ ] as const;
82
+
83
+ export const DEFAULT_MASCOT_MOODS: MascotMood[] = [
84
+ 'happy',
85
+ 'sad',
86
+ 'excited',
87
+ 'thinking',
88
+ 'angry',
89
+ 'neutral',
90
+ 'surprised',
91
+ ];
92
+
93
+ export const DEFAULT_ANIMATION_SPEEDS: AnimationSpeed[] = [
94
+ 'very-slow',
95
+ 'slow',
96
+ 'normal',
97
+ 'fast',
98
+ 'very-fast',
99
+ ];