@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,61 @@
1
+ {
2
+ "v": "5.9.0",
3
+ "fr": 60,
4
+ "ip": 0,
5
+ "op": 120,
6
+ "w": 200,
7
+ "h": 200,
8
+ "nm": "Dance",
9
+ "ddd": 0,
10
+ "assets": [],
11
+ "layers": [
12
+ {
13
+ "ddd": 0,
14
+ "ind": 1,
15
+ "ty": 4,
16
+ "nm": "Body",
17
+ "ks": {
18
+ "o": { "a": 0, "k": 100 },
19
+ "r": { "a": 1, "k": [
20
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 0, "s": [0] },
21
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 15, "s": [15] },
22
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 30, "s": [-15] },
23
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 45, "s": [15] },
24
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 60, "s": [-15] },
25
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 75, "s": [15] },
26
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 90, "s": [-15] },
27
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 105, "s": [15] },
28
+ { "t": 120, "s": [0] }
29
+ ]},
30
+ "p": {
31
+ "a": 1,
32
+ "k": [
33
+ { "i": { "x": 0.833, "y": 0.833 }, "o": { "x": 0.167, "y": 0.167 }, "t": 0, "s": [100, 100] },
34
+ { "i": { "x": 0.833, "y": 0 }, "o": { "x": 0.167, "y": 1 }, "t": 30, "s": [100, 90] },
35
+ { "i": { "x": 0.833, "y": 0.833 }, "o": { "x": 0.167, "y": 0.167 }, "t": 60, "s": [100, 100] },
36
+ { "i": { "x": 0.833, "y": 0 }, "o": { "x": 0.167, "y": 1 }, "t": 90, "s": [100, 90] },
37
+ { "t": 120, "s": [100, 100] }
38
+ ]
39
+ },
40
+ "a": { "a": 0, "k": [0, 0] },
41
+ "s": { "a": 0, "k": [100, 100] }
42
+ },
43
+ "shapes": [
44
+ {
45
+ "ty": "gr",
46
+ "it": [
47
+ {
48
+ "ty": "el",
49
+ "s": { "a": 0, "k": [150, 150] },
50
+ "p": { "a": 0, "k": [0, 0] }
51
+ },
52
+ {
53
+ "ty": "fl",
54
+ "c": { "a": 0, "k": [0.95, 0.5, 0.35, 1] }
55
+ }
56
+ ]
57
+ }
58
+ ]
59
+ }
60
+ ]
61
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "v": "5.9.0",
3
+ "fr": 60,
4
+ "ip": 0,
5
+ "op": 60,
6
+ "w": 200,
7
+ "h": 200,
8
+ "nm": "Error",
9
+ "ddd": 0,
10
+ "assets": [],
11
+ "layers": [
12
+ {
13
+ "ddd": 0,
14
+ "ind": 1,
15
+ "ty": 4,
16
+ "nm": "Body",
17
+ "ks": {
18
+ "o": { "a": 0, "k": 100 },
19
+ "r": { "a": 1, "k": [
20
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 0, "s": [0] },
21
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 15, "s": [-10] },
22
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 30, "s": [10] },
23
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 45, "s": [-10] },
24
+ { "t": 60, "s": [0] }
25
+ ]},
26
+ "p": { "a": 0, "k": [100, 100] },
27
+ "a": { "a": 0, "k": [0, 0] },
28
+ "s": { "a": 0, "k": [100, 100] }
29
+ },
30
+ "shapes": [
31
+ {
32
+ "ty": "gr",
33
+ "it": [
34
+ {
35
+ "ty": "el",
36
+ "s": { "a": 0, "k": [150, 150] },
37
+ "p": { "a": 0, "k": [0, 0] }
38
+ },
39
+ {
40
+ "ty": "fl",
41
+ "c": { "a": 0, "k": [0.9, 0.3, 0.3, 1] }
42
+ }
43
+ ]
44
+ }
45
+ ]
46
+ }
47
+ ]
48
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "v": "5.9.0",
3
+ "fr": 60,
4
+ "ip": 0,
5
+ "op": 60,
6
+ "w": 200,
7
+ "h": 200,
8
+ "nm": "Idle",
9
+ "ddd": 0,
10
+ "assets": [],
11
+ "layers": [
12
+ {
13
+ "ddd": 0,
14
+ "ind": 1,
15
+ "ty": 4,
16
+ "nm": "Body",
17
+ "sr": 1,
18
+ "ks": {
19
+ "o": { "a": 0, "k": 100 },
20
+ "r": {
21
+ "a": 1,
22
+ "k": [
23
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 0, "s": [0] },
24
+ { "t": 60, "s": [5] }
25
+ ]
26
+ },
27
+ "p": { "a": 0, "k": [100, 100] },
28
+ "a": { "a": 0, "k": [0, 0] },
29
+ "s": { "a": 0, "k": [100, 100] }
30
+ },
31
+ "shapes": [
32
+ {
33
+ "ty": "gr",
34
+ "it": [
35
+ {
36
+ "ty": "el",
37
+ "s": { "a": 0, "k": [150, 150] },
38
+ "p": { "a": 0, "k": [0, 0] }
39
+ },
40
+ {
41
+ "ty": "fl",
42
+ "c": { "a": 0, "k": [0.95, 0.5, 0.35, 1] }
43
+ }
44
+ ]
45
+ }
46
+ ]
47
+ }
48
+ ]
49
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "v": "5.9.0",
3
+ "fr": 60,
4
+ "ip": 0,
5
+ "op": 60,
6
+ "w": 200,
7
+ "h": 200,
8
+ "nm": "Jump",
9
+ "ddd": 0,
10
+ "assets": [],
11
+ "layers": [
12
+ {
13
+ "ddd": 0,
14
+ "ind": 1,
15
+ "ty": 4,
16
+ "nm": "Body",
17
+ "ks": {
18
+ "o": { "a": 0, "k": 100 },
19
+ "p": {
20
+ "a": 1,
21
+ "k": [
22
+ { "i": { "x": 0.833, "y": 0.833 }, "o": { "x": 0.167, "y": 0.167 }, "t": 0, "s": [100, 120] },
23
+ { "i": { "x": 0.833, "y": 0 }, "o": { "x": 0.167, "y": 1 }, "t": 30, "s": [100, 60] },
24
+ { "t": 60, "s": [100, 120] }
25
+ ]
26
+ },
27
+ "a": { "a": 0, "k": [0, 0] },
28
+ "s": { "a": 0, "k": [100, 100] }
29
+ },
30
+ "shapes": [
31
+ {
32
+ "ty": "gr",
33
+ "it": [
34
+ {
35
+ "ty": "el",
36
+ "s": { "a": 0, "k": [150, 150] },
37
+ "p": { "a": 0, "k": [0, 0] }
38
+ },
39
+ {
40
+ "ty": "fl",
41
+ "c": { "a": 0, "k": [0.95, 0.5, 0.35, 1] }
42
+ }
43
+ ]
44
+ }
45
+ ]
46
+ }
47
+ ]
48
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "v": "5.9.0",
3
+ "fr": 60,
4
+ "ip": 0,
5
+ "op": 90,
6
+ "w": 200,
7
+ "h": 200,
8
+ "nm": "Success",
9
+ "ddd": 0,
10
+ "assets": [],
11
+ "layers": [
12
+ {
13
+ "ddd": 0,
14
+ "ind": 1,
15
+ "ty": 4,
16
+ "nm": "Body",
17
+ "ks": {
18
+ "o": { "a": 0, "k": 100 },
19
+ "r": { "a": 1, "k": [
20
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 0, "s": [0] },
21
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 45, "s": [360] },
22
+ { "t": 90, "s": [360] }
23
+ ]},
24
+ "p": { "a": 0, "k": [100, 100] },
25
+ "a": { "a": 0, "k": [0, 0] },
26
+ "s": { "a": 0, "k": [100, 100] }
27
+ },
28
+ "shapes": [
29
+ {
30
+ "ty": "gr",
31
+ "it": [
32
+ {
33
+ "ty": "el",
34
+ "s": { "a": 0, "k": [150, 150] },
35
+ "p": { "a": 0, "k": [0, 0] }
36
+ },
37
+ {
38
+ "ty": "fl",
39
+ "c": { "a": 0, "k": [0.2, 0.8, 0.4, 1] }
40
+ }
41
+ ]
42
+ }
43
+ ]
44
+ }
45
+ ]
46
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "v": "5.9.0",
3
+ "fr": 60,
4
+ "ip": 0,
5
+ "op": 90,
6
+ "w": 200,
7
+ "h": 200,
8
+ "nm": "Wave",
9
+ "ddd": 0,
10
+ "assets": [],
11
+ "layers": [
12
+ {
13
+ "ddd": 0,
14
+ "ind": 1,
15
+ "ty": 4,
16
+ "nm": "Body",
17
+ "ks": {
18
+ "o": { "a": 0, "k": 100 },
19
+ "r": { "a": 1, "k": [
20
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 0, "s": [-20] },
21
+ { "i": { "x": [0.833], "y": [0.833] }, "o": { "x": [0.167], "y": [0.167] }, "t": 30, "s": [20] },
22
+ { "t": 60, "s": [-20] }
23
+ ]},
24
+ "p": { "a": 0, "k": [100, 100] },
25
+ "a": { "a": 0, "k": [0, 0] },
26
+ "s": { "a": 0, "k": [100, 100] }
27
+ },
28
+ "shapes": [
29
+ {
30
+ "ty": "gr",
31
+ "it": [
32
+ {
33
+ "ty": "el",
34
+ "s": { "a": 0, "k": [150, 150] },
35
+ "p": { "a": 0, "k": [0, 0] }
36
+ },
37
+ {
38
+ "ty": "fl",
39
+ "c": { "a": 0, "k": [0.95, 0.5, 0.35, 1] }
40
+ }
41
+ ]
42
+ }
43
+ ]
44
+ }
45
+ ]
46
+ }
@@ -0,0 +1,20 @@
1
+ <svg viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <!-- Body -->
3
+ <rect x="25" y="30" width="50" height="45" rx="10" fill="currentColor" id="body"/>
4
+ <!-- Head -->
5
+ <rect x="20" y="20" width="60" height="40" rx="8" fill="currentColor" id="head"/>
6
+ <!-- Antenna -->
7
+ <line x1="50" y1="20" x2="50" y2="10" stroke="#666" stroke-width="3" id="antenna"/>
8
+ <circle cx="50" cy="8" r="4" fill="#FF6B6B" id="antenna-ball"/>
9
+ <!-- Eyes -->
10
+ <circle cx="35" cy="38" r="8" fill="#FFF" id="left-eye-bg"/>
11
+ <circle cx="35" cy="38" r="4" fill="#00F" id="left-eye"/>
12
+ <circle cx="65" cy="38" r="8" fill="#FFF" id="right-eye-bg"/>
13
+ <circle cx="65" cy="38" r="4" fill="#00F" id="right-eye"/>
14
+ <!-- Mouth -->
15
+ <rect x="40" y="48" width="20" height="6" rx="3" fill="#333" id="mouth"/>
16
+ <!-- Buttons -->
17
+ <circle cx="40" cy="65" r="3" fill="#FFD700" id="button-1"/>
18
+ <circle cx="50" cy="65" r="3" fill="#FFD700" id="button-2"/>
19
+ <circle cx="60" cy="65" r="3" fill="#FFD700" id="button-3"/>
20
+ </svg>
@@ -0,0 +1,19 @@
1
+ <svg viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <!-- Base face -->
3
+ <circle cx="50" cy="50" r="40" fill="currentColor" id="face"/>
4
+ <!-- Ears -->
5
+ <path d="M 20 30 L 15 15 L 35 25 Z" fill="currentColor" id="left-ear"/>
6
+ <path d="M 80 30 L 85 15 L 65 25 Z" fill="currentColor" id="right-ear"/>
7
+ <!-- Eyes -->
8
+ <circle cx="35" cy="45" r="5" fill="#000" id="left-eye"/>
9
+ <circle cx="65" cy="45" r="5" fill="#000" id="right-eye"/>
10
+ <!-- Nose -->
11
+ <path d="M 48 55 L 52 55 L 50 58 Z" fill="#FF9999" id="nose"/>
12
+ <!-- Mouth -->
13
+ <path d="M 45 60 Q 50 65 55 60" stroke="#000" stroke-width="2" fill="none" id="mouth"/>
14
+ <!-- Whiskers -->
15
+ <line x1="20" y1="55" x2="35" y2="58" stroke="#000" stroke-width="1" id="left-whisker-1"/>
16
+ <line x1="20" y1="60" x2="35" y2="60" stroke="#000" stroke-width="1" id="left-whisker-2"/>
17
+ <line x1="65" y1="58" x2="80" y2="55" stroke="#000" stroke-width="1" id="right-whisker-1"/>
18
+ <line x1="65" y1="60" x2="80" y2="60" stroke="#000" stroke-width="1" id="right-whisker-2"/>
19
+ </svg>
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Animation Controller Implementation
3
+ * Controls Lottie and SVG animations with unified API
4
+ */
5
+
6
+ import type {
7
+ IAnimationController,
8
+ AnimationOptions,
9
+ AnimationEvent,
10
+ } from '../../domain/interfaces/IAnimationController';
11
+ import type { MascotAnimation } from '../../domain/types/MascotTypes';
12
+
13
+ export class AnimationController implements IAnimationController {
14
+ private _currentAnimation: MascotAnimation | null = null;
15
+ private _isPlaying: boolean = false;
16
+ private _isPaused: boolean = false;
17
+ private _progress: number = 0;
18
+ private _speed: number = 1;
19
+ private _eventListeners: Map<AnimationEvent, Set<(data?: unknown) => void>>;
20
+
21
+ constructor() {
22
+ this._eventListeners = new Map();
23
+ this._initializeEventListeners();
24
+ }
25
+
26
+ play(
27
+ animation: MascotAnimation,
28
+ options?: AnimationOptions
29
+ ): Promise<void> {
30
+ this._currentAnimation = animation;
31
+ this._isPlaying = true;
32
+ this._isPaused = false;
33
+
34
+ if (options?.speed !== undefined) {
35
+ this._speed = options.speed;
36
+ }
37
+
38
+ this._emit('start', { animation: animation.id });
39
+
40
+ // Simulate animation completion
41
+ // In real implementation, this would be controlled by LottieView
42
+ const duration = animation.duration || 2000;
43
+ const adjustedDuration = duration / this._speed;
44
+
45
+ return new Promise((resolve) => {
46
+ setTimeout(() => {
47
+ if (this._isPlaying && !this._isPaused) {
48
+ this._isPlaying = false;
49
+ this._progress = 1;
50
+ this._emit('finish', { animation: animation.id });
51
+ options?.onFinish?.();
52
+ }
53
+ resolve();
54
+ }, adjustedDuration);
55
+
56
+ options?.onStart?.();
57
+ });
58
+ }
59
+
60
+ pause(): void {
61
+ if (!this._isPlaying || this._isPaused) {
62
+ return;
63
+ }
64
+
65
+ this._isPaused = true;
66
+ this._emit('pause');
67
+ }
68
+
69
+ resume(): void {
70
+ if (!this._isPaused) {
71
+ return;
72
+ }
73
+
74
+ this._isPaused = false;
75
+ this._emit('resume');
76
+ }
77
+
78
+ stop(): void {
79
+ this._isPlaying = false;
80
+ this._isPaused = false;
81
+ this._progress = 0;
82
+ this._currentAnimation = null;
83
+ }
84
+
85
+ getProgress(): number {
86
+ return this._progress;
87
+ }
88
+
89
+ setProgress(progress: number): void {
90
+ if (progress < 0 || progress > 1) {
91
+ throw new Error('Progress must be between 0 and 1');
92
+ }
93
+ this._progress = progress;
94
+ this._emit('progress', { progress });
95
+ }
96
+
97
+ setSpeed(speed: number): void {
98
+ if (speed <= 0) {
99
+ throw new Error('Speed must be greater than 0');
100
+ }
101
+ this._speed = speed;
102
+ }
103
+
104
+ isPlaying(): boolean {
105
+ return this._isPlaying && !this._isPaused;
106
+ }
107
+
108
+ on(event: AnimationEvent, callback: (data?: unknown) => void): () => void {
109
+ if (!this._eventListeners.has(event)) {
110
+ this._eventListeners.set(event, new Set());
111
+ }
112
+
113
+ this._eventListeners.get(event)!.add(callback);
114
+
115
+ // Return unsubscribe function
116
+ return () => {
117
+ this.off(event, callback);
118
+ };
119
+ }
120
+
121
+ off(event: AnimationEvent, callback: (data?: unknown) => void): void {
122
+ const listeners = this._eventListeners.get(event);
123
+ if (listeners) {
124
+ listeners.delete(callback);
125
+ }
126
+ }
127
+
128
+ // Private Methods
129
+ private _initializeEventListeners(): void {
130
+ const events: AnimationEvent[] = ['start', 'finish', 'pause', 'resume', 'progress', 'error'];
131
+ events.forEach((event) => {
132
+ if (!this._eventListeners.has(event)) {
133
+ this._eventListeners.set(event, new Set());
134
+ }
135
+ });
136
+ }
137
+
138
+ private _emit(event: AnimationEvent, data?: unknown): void {
139
+ const listeners = this._eventListeners.get(event);
140
+ if (listeners) {
141
+ listeners.forEach((callback) => {
142
+ try {
143
+ callback(data);
144
+ } catch (error) {
145
+ console.error(`Error in ${event} event listener:`, error);
146
+ }
147
+ });
148
+ }
149
+ }
150
+
151
+ // Getters
152
+ get currentAnimation(): MascotAnimation | null {
153
+ return this._currentAnimation;
154
+ }
155
+
156
+ get speed(): number {
157
+ return this._speed;
158
+ }
159
+
160
+ get isPaused(): boolean {
161
+ return this._isPaused;
162
+ }
163
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Asset Manager Implementation
3
+ * Loads and caches Lottie and SVG assets
4
+ */
5
+
6
+ import type {
7
+ IAssetManager,
8
+ AssetCache,
9
+ } from '../../domain/interfaces/IAssetManager';
10
+ import type { MascotAnimation } from '../../domain/types/MascotTypes';
11
+
12
+ export class AssetManager implements IAssetManager {
13
+ private readonly _cache: AssetCache;
14
+ private readonly _loadedAssets: Set<string>;
15
+ private readonly _maxCacheSize: number = 50 * 1024 * 1024; // 50MB
16
+ private _currentCacheSize: number = 0;
17
+
18
+ constructor() {
19
+ this._cache = {};
20
+ this._loadedAssets = new Set();
21
+ }
22
+
23
+ loadLottieAnimation(
24
+ source: string | object
25
+ ): Promise<MascotAnimation> {
26
+ const assetId = this._getAssetId(source);
27
+
28
+ if (this._isAssetLoaded(assetId)) {
29
+ return Promise.resolve(this._cache[assetId].data as MascotAnimation);
30
+ }
31
+
32
+ // Simulate loading - in real implementation, this would actually load the file
33
+ const animation: MascotAnimation = {
34
+ id: assetId,
35
+ name: typeof source === 'string' ? source.split('/').pop() || 'unknown' : 'custom',
36
+ type: 'idle',
37
+ source,
38
+ loop: false,
39
+ autoplay: false,
40
+ };
41
+
42
+ this._cacheAsset(assetId, animation);
43
+ return Promise.resolve(animation);
44
+ }
45
+
46
+ loadSVGAsset(source: string): Promise<string> {
47
+ if (this._isAssetLoaded(source)) {
48
+ return Promise.resolve(this._cache[source].data as string);
49
+ }
50
+
51
+ // Simulate loading - in real implementation, this would load the SVG file
52
+ const svgContent = this._loadSVGFromFile(source);
53
+ this._cacheAsset(source, svgContent);
54
+ return Promise.resolve(svgContent);
55
+ }
56
+
57
+ async preloadAnimations(sources: Array<string | object>): Promise<void> {
58
+ const promises = sources.map((source) =>
59
+ this.loadLottieAnimation(source)
60
+ );
61
+ await Promise.all(promises);
62
+ }
63
+
64
+ clearCache(): void {
65
+ Object.keys(this._cache).forEach((key) => {
66
+ delete this._cache[key];
67
+ });
68
+ this._loadedAssets.clear();
69
+ this._currentCacheSize = 0;
70
+ }
71
+
72
+ getAssetUrl(assetId: string): string | null {
73
+ if (this._isAssetLoaded(assetId)) {
74
+ return assetId;
75
+ }
76
+ return null;
77
+ }
78
+
79
+ isAssetLoaded(assetId: string): boolean {
80
+ return this._loadedAssets.has(assetId);
81
+ }
82
+
83
+ getLoadedAssets(): string[] {
84
+ return Array.from(this._loadedAssets);
85
+ }
86
+
87
+ // Private Methods
88
+ private _getAssetId(source: string | object): string {
89
+ if (typeof source === 'string') {
90
+ return source;
91
+ }
92
+ return JSON.stringify(source);
93
+ }
94
+
95
+ private _cacheAsset(assetId: string, data: unknown): void {
96
+ const size = this._estimateSize(data);
97
+
98
+ // Check if cache is full
99
+ if (this._currentCacheSize + size > this._maxCacheSize) {
100
+ this._evictOldestAssets();
101
+ }
102
+
103
+ this._cache[assetId] = {
104
+ data,
105
+ timestamp: Date.now(),
106
+ size,
107
+ };
108
+
109
+ this._loadedAssets.add(assetId);
110
+ this._currentCacheSize += size;
111
+ }
112
+
113
+ private _isAssetLoaded(assetId: string): boolean {
114
+ return this._loadedAssets.has(assetId) && !!this._cache[assetId];
115
+ }
116
+
117
+ private _evictOldestAssets(): void {
118
+ const sortedAssets = Object.entries(this._cache)
119
+ .sort(([, a], [, b]) => a.timestamp - b.timestamp);
120
+
121
+ let freedSpace = 0;
122
+ const targetSpace = this._maxCacheSize * 0.3; // Evict 30% of cache
123
+
124
+ for (const [assetId, asset] of sortedAssets) {
125
+ if (freedSpace >= targetSpace) {
126
+ break;
127
+ }
128
+
129
+ delete this._cache[assetId];
130
+ this._loadedAssets.delete(assetId);
131
+ freedSpace += asset.size;
132
+ this._currentCacheSize -= asset.size;
133
+ }
134
+ }
135
+
136
+ private _estimateSize(data: unknown): number {
137
+ // Rough estimation in bytes
138
+ return JSON.stringify(data).length * 2; // 2 bytes per char (UTF-16)
139
+ }
140
+
141
+ private _loadSVGFromFile(_source: string): string {
142
+ // In real implementation, this would use FileSystem or require()
143
+ // For now, return a placeholder
144
+ return `<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="currentColor"/></svg>`;
145
+ }
146
+
147
+ // Getters
148
+ get cacheSize(): number {
149
+ return this._currentCacheSize;
150
+ }
151
+
152
+ get cacheStats(): { size: number; count: number; maxSize: number } {
153
+ return {
154
+ size: this._currentCacheSize,
155
+ count: this._loadedAssets.size,
156
+ maxSize: this._maxCacheSize,
157
+ };
158
+ }
159
+ }