react-native-maplibre-lite 0.1.9 → 0.2.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.
Files changed (78) hide show
  1. package/README.md +92 -6
  2. package/lib/module/components/MapView.js +167 -48
  3. package/lib/module/components/MapView.js.map +1 -1
  4. package/lib/module/components/NavigatorHud.js +152 -0
  5. package/lib/module/components/NavigatorHud.js.map +1 -0
  6. package/lib/module/components/NavigatorRecenterButton.js +48 -0
  7. package/lib/module/components/NavigatorRecenterButton.js.map +1 -0
  8. package/lib/module/components/NavigatorVoiceControl.js +173 -0
  9. package/lib/module/components/NavigatorVoiceControl.js.map +1 -0
  10. package/lib/module/components/navigatorChromeTheme.js +98 -0
  11. package/lib/module/components/navigatorChromeTheme.js.map +1 -0
  12. package/lib/module/components/navigatorManeuverIcon.js +210 -0
  13. package/lib/module/components/navigatorManeuverIcon.js.map +1 -0
  14. package/lib/module/components/navigatorVoiceCatalog.js +225 -0
  15. package/lib/module/components/navigatorVoiceCatalog.js.map +1 -0
  16. package/lib/module/components/navigatorVoiceKeys.js +14 -0
  17. package/lib/module/components/navigatorVoiceKeys.js.map +1 -0
  18. package/lib/module/components/navigatorVoicePlayer.js +100 -0
  19. package/lib/module/components/navigatorVoicePlayer.js.map +1 -0
  20. package/lib/module/components/navigatorVoiceStrings.js +31 -0
  21. package/lib/module/components/navigatorVoiceStrings.js.map +1 -0
  22. package/lib/module/components/types.js +47 -0
  23. package/lib/module/components/types.js.map +1 -1
  24. package/lib/module/components/useNavigatorVoice.js +78 -0
  25. package/lib/module/components/useNavigatorVoice.js.map +1 -0
  26. package/lib/module/components/utils.js +26 -0
  27. package/lib/module/components/utils.js.map +1 -1
  28. package/lib/module/components/webMapBuild.js +1 -1
  29. package/lib/module/components/webMapBuild.js.map +1 -1
  30. package/lib/module/index.js.map +1 -1
  31. package/lib/typescript/src/components/MapView.d.ts +15 -2
  32. package/lib/typescript/src/components/MapView.d.ts.map +1 -1
  33. package/lib/typescript/src/components/NavigatorHud.d.ts +13 -0
  34. package/lib/typescript/src/components/NavigatorHud.d.ts.map +1 -0
  35. package/lib/typescript/src/components/NavigatorRecenterButton.d.ts +11 -0
  36. package/lib/typescript/src/components/NavigatorRecenterButton.d.ts.map +1 -0
  37. package/lib/typescript/src/components/NavigatorVoiceControl.d.ts +20 -0
  38. package/lib/typescript/src/components/NavigatorVoiceControl.d.ts.map +1 -0
  39. package/lib/typescript/src/components/navigatorChromeTheme.d.ts +19 -0
  40. package/lib/typescript/src/components/navigatorChromeTheme.d.ts.map +1 -0
  41. package/lib/typescript/src/components/navigatorManeuverIcon.d.ts +20 -0
  42. package/lib/typescript/src/components/navigatorManeuverIcon.d.ts.map +1 -0
  43. package/lib/typescript/src/components/navigatorVoiceCatalog.d.ts +50 -0
  44. package/lib/typescript/src/components/navigatorVoiceCatalog.d.ts.map +1 -0
  45. package/lib/typescript/src/components/navigatorVoiceKeys.d.ts +10 -0
  46. package/lib/typescript/src/components/navigatorVoiceKeys.d.ts.map +1 -0
  47. package/lib/typescript/src/components/navigatorVoicePlayer.d.ts +15 -0
  48. package/lib/typescript/src/components/navigatorVoicePlayer.d.ts.map +1 -0
  49. package/lib/typescript/src/components/navigatorVoiceStrings.d.ts +19 -0
  50. package/lib/typescript/src/components/navigatorVoiceStrings.d.ts.map +1 -0
  51. package/lib/typescript/src/components/types.d.ts +205 -12
  52. package/lib/typescript/src/components/types.d.ts.map +1 -1
  53. package/lib/typescript/src/components/useNavigatorVoice.d.ts +20 -0
  54. package/lib/typescript/src/components/useNavigatorVoice.d.ts.map +1 -0
  55. package/lib/typescript/src/components/utils.d.ts +9 -0
  56. package/lib/typescript/src/components/utils.d.ts.map +1 -1
  57. package/lib/typescript/src/components/webMapBuild.d.ts +1 -1
  58. package/lib/typescript/src/components/webMapBuild.d.ts.map +1 -1
  59. package/lib/typescript/src/index.d.ts +1 -1
  60. package/lib/typescript/src/index.d.ts.map +1 -1
  61. package/package.json +16 -7
  62. package/resources/README.md +62 -0
  63. package/resources/map.html +797 -0
  64. package/src/components/MapView.tsx +209 -58
  65. package/src/components/NavigatorHud.tsx +166 -0
  66. package/src/components/NavigatorRecenterButton.tsx +45 -0
  67. package/src/components/NavigatorVoiceControl.tsx +198 -0
  68. package/src/components/navigatorChromeTheme.ts +118 -0
  69. package/src/components/navigatorManeuverIcon.tsx +177 -0
  70. package/src/components/navigatorVoiceCatalog.ts +275 -0
  71. package/src/components/navigatorVoiceKeys.ts +132 -0
  72. package/src/components/navigatorVoicePlayer.tsx +126 -0
  73. package/src/components/navigatorVoiceStrings.ts +42 -0
  74. package/src/components/types.ts +198 -16
  75. package/src/components/useNavigatorVoice.ts +96 -0
  76. package/src/components/utils.ts +28 -0
  77. package/src/components/webMapBuild.ts +1 -1
  78. package/src/index.tsx +19 -0
@@ -0,0 +1,45 @@
1
+ import { Pressable } from 'react-native';
2
+
3
+ import { NavigatorRecenterIcon } from './navigatorManeuverIcon';
4
+ import type { NavigatorChromeTheme } from './navigatorChromeTheme';
5
+
6
+ /**
7
+ * FAB «вернуть камеру на положение». При нажатии шлёт команду
8
+ * `recenterNavigatorCamera` в WebView — навигатор делает recenter.
9
+ */
10
+ export function NavigatorRecenterButton({
11
+ theme,
12
+ accessibilityLabel,
13
+ onPress,
14
+ }: {
15
+ theme: NavigatorChromeTheme;
16
+ accessibilityLabel: string;
17
+ onPress: () => void;
18
+ }) {
19
+ return (
20
+ <Pressable
21
+ accessibilityRole="button"
22
+ accessibilityLabel={accessibilityLabel}
23
+ onPress={onPress}
24
+ style={({ pressed }) => ({
25
+ position: 'absolute',
26
+ right: 16,
27
+ bottom: 16,
28
+ width: 56,
29
+ height: 56,
30
+ borderRadius: 28,
31
+ alignItems: 'center',
32
+ justifyContent: 'center',
33
+ backgroundColor: theme.background,
34
+ shadowColor: '#0f172a',
35
+ shadowOpacity: 0.32,
36
+ shadowRadius: 24,
37
+ shadowOffset: { width: 0, height: 10 },
38
+ elevation: 6,
39
+ transform: [{ scale: pressed ? 0.96 : 1 }],
40
+ })}
41
+ >
42
+ <NavigatorRecenterIcon color={theme.iconForeground} />
43
+ </Pressable>
44
+ );
45
+ }
@@ -0,0 +1,198 @@
1
+ import { useState } from 'react';
2
+ import { Pressable, ScrollView, Text, View } from 'react-native';
3
+
4
+ import { NavigatorVoiceIcon } from './navigatorManeuverIcon';
5
+ import type { NavigatorChromeTheme } from './navigatorChromeTheme';
6
+ import type { VoiceCatalogEntry, VoiceVolumeLevel } from './navigatorVoiceCatalog';
7
+ import type { NavigatorUiStrings } from './navigatorVoiceStrings';
8
+
9
+ /**
10
+ * FAB выбора голоса + меню (список голосов, громкость 1–5, «отключить»).
11
+ * Порт DOM-меню из веб-навигатора. Каталог/манифест и персист — в
12
+ * `useNavigatorVoice`; компонент только презентационный.
13
+ */
14
+ export function NavigatorVoiceControl({
15
+ theme,
16
+ strings,
17
+ catalog,
18
+ selectedDir,
19
+ voiceEnabled,
20
+ volumeLevel,
21
+ onSelectVoice,
22
+ onSelectVolume,
23
+ onDisable,
24
+ }: {
25
+ theme: NavigatorChromeTheme;
26
+ strings: NavigatorUiStrings;
27
+ catalog: VoiceCatalogEntry[];
28
+ selectedDir: string | null;
29
+ voiceEnabled: boolean;
30
+ volumeLevel: VoiceVolumeLevel;
31
+ onSelectVoice: (dir: string) => void;
32
+ onSelectVolume: (level: VoiceVolumeLevel) => void;
33
+ onDisable: () => void;
34
+ }) {
35
+ const [open, setOpen] = useState(false);
36
+
37
+ if (catalog.length === 0) return null;
38
+
39
+ return (
40
+ <>
41
+ <Pressable
42
+ accessibilityRole="button"
43
+ accessibilityLabel={strings.voicePickerAria}
44
+ onPress={() => setOpen((v) => !v)}
45
+ style={({ pressed }) => ({
46
+ position: 'absolute',
47
+ right: 16,
48
+ bottom: 16 + 56 + 8,
49
+ width: 56,
50
+ height: 56,
51
+ borderRadius: 28,
52
+ alignItems: 'center',
53
+ justifyContent: 'center',
54
+ backgroundColor: theme.background,
55
+ shadowColor: '#0f172a',
56
+ shadowOpacity: 0.32,
57
+ shadowRadius: 24,
58
+ shadowOffset: { width: 0, height: 10 },
59
+ elevation: 6,
60
+ opacity: pressed ? 0.9 : 1,
61
+ })}
62
+ >
63
+ <NavigatorVoiceIcon
64
+ color={voiceEnabled ? theme.iconForeground : theme.muted}
65
+ />
66
+ </Pressable>
67
+
68
+ {open ? (
69
+ <View
70
+ style={{
71
+ position: 'absolute',
72
+ right: 16,
73
+ bottom: 16 + 56 + 8 + 56 + 8,
74
+ minWidth: 200,
75
+ maxWidth: 280,
76
+ paddingVertical: 6,
77
+ borderRadius: 12,
78
+ backgroundColor: theme.background,
79
+ shadowColor: '#0f172a',
80
+ shadowOpacity: 0.32,
81
+ shadowRadius: 24,
82
+ shadowOffset: { width: 0, height: 10 },
83
+ elevation: 8,
84
+ }}
85
+ >
86
+ <ScrollView style={{ maxHeight: 280 }}>
87
+ {catalog.map((entry) => {
88
+ const active = voiceEnabled && entry.dir === selectedDir;
89
+ return (
90
+ <Pressable
91
+ key={entry.dir}
92
+ accessibilityRole="menuitem"
93
+ onPress={() => {
94
+ setOpen(false);
95
+ onSelectVoice(entry.dir);
96
+ }}
97
+ style={{ paddingVertical: 10, paddingHorizontal: 16 }}
98
+ >
99
+ <Text
100
+ style={{
101
+ fontSize: 15,
102
+ color: active ? theme.iconForeground : theme.foreground,
103
+ fontWeight: active ? '600' : '400',
104
+ }}
105
+ >
106
+ {entry.name}
107
+ </Text>
108
+ </Pressable>
109
+ );
110
+ })}
111
+
112
+ <View
113
+ style={{
114
+ marginTop: 4,
115
+ paddingTop: 12,
116
+ paddingHorizontal: 16,
117
+ borderTopWidth: 1,
118
+ borderTopColor: 'rgba(255, 255, 255, 0.12)',
119
+ }}
120
+ >
121
+ <Text style={{ marginBottom: 10, fontSize: 13, color: theme.muted }}>
122
+ {strings.voiceVolumeLabel}
123
+ </Text>
124
+ <View
125
+ style={{
126
+ flexDirection: 'row',
127
+ alignItems: 'flex-end',
128
+ gap: 6,
129
+ }}
130
+ >
131
+ {([1, 2, 3, 4, 5] as const).map((step) => {
132
+ const stepActive = step <= volumeLevel;
133
+ return (
134
+ <Pressable
135
+ key={step}
136
+ accessibilityRole="button"
137
+ accessibilityLabel={strings.voiceVolumeStepAria(step)}
138
+ onPress={() => onSelectVolume(step as VoiceVolumeLevel)}
139
+ style={{
140
+ flex: 1,
141
+ height: 36,
142
+ justifyContent: 'flex-end',
143
+ alignItems: 'center',
144
+ paddingBottom: 4,
145
+ borderRadius: 6,
146
+ backgroundColor:
147
+ step === volumeLevel
148
+ ? 'rgba(59, 130, 246, 0.18)'
149
+ : 'transparent',
150
+ }}
151
+ >
152
+ <View
153
+ style={{
154
+ width: 14,
155
+ height: Math.max(6, step * 6),
156
+ borderRadius: 2,
157
+ backgroundColor: stepActive
158
+ ? theme.iconForeground
159
+ : theme.muted,
160
+ }}
161
+ />
162
+ </Pressable>
163
+ );
164
+ })}
165
+ </View>
166
+ </View>
167
+
168
+ <Pressable
169
+ accessibilityRole="menuitem"
170
+ onPress={() => {
171
+ setOpen(false);
172
+ onDisable();
173
+ }}
174
+ style={{
175
+ marginTop: 4,
176
+ paddingTop: 12,
177
+ paddingBottom: 10,
178
+ paddingHorizontal: 16,
179
+ borderTopWidth: 1,
180
+ borderTopColor: 'rgba(255, 255, 255, 0.12)',
181
+ }}
182
+ >
183
+ <Text
184
+ style={{
185
+ fontSize: 15,
186
+ color: !voiceEnabled ? theme.iconForeground : theme.muted,
187
+ fontWeight: !voiceEnabled ? '600' : '400',
188
+ }}
189
+ >
190
+ {strings.voiceDisable}
191
+ </Text>
192
+ </Pressable>
193
+ </ScrollView>
194
+ </View>
195
+ ) : null}
196
+ </>
197
+ );
198
+ }
@@ -0,0 +1,118 @@
1
+ import type { NavigatorChromeParams } from './types';
2
+
3
+ /**
4
+ * Цвета HUD/FAB навигатора, выведенные из `navigatorChrome`. Порт
5
+ * HUD-части `resolveNavigatorChrome` из веб-навигатора: раньше эти
6
+ * CSS-переменные применялись к DOM, теперь панель рисует нативная часть.
7
+ */
8
+ export type NavigatorChromeTheme = {
9
+ background: string;
10
+ foreground: string;
11
+ subtle: string;
12
+ muted: string;
13
+ summary: string;
14
+ divider: string;
15
+ iconBackground: string;
16
+ iconForeground: string;
17
+ shadow: string;
18
+ };
19
+
20
+ type Rgb = { r: number; g: number; b: number };
21
+
22
+ const DEF_ACCENT = '#3b82f6';
23
+ const DEF_HUD_BG = 'rgba(15, 23, 42, 0.92)';
24
+ const DEF_HUD_FG = '#f8fafc';
25
+ const DEF_HUD_MUTED = '#94a3b8';
26
+ const DEF_HUD_SUBTLE = '#e2e8f0';
27
+ const DEF_HUD_SUMMARY = '#cbd5e1';
28
+ const RGB_WHITE: Rgb = { r: 255, g: 255, b: 255 };
29
+
30
+ function clamp255(n: number): number {
31
+ return Math.max(0, Math.min(255, Math.round(n)));
32
+ }
33
+
34
+ function mixRgb(a: Rgb, b: Rgb, t: number): Rgb {
35
+ return {
36
+ r: clamp255(a.r + (b.r - a.r) * t),
37
+ g: clamp255(a.g + (b.g - a.g) * t),
38
+ b: clamp255(a.b + (b.b - a.b) * t),
39
+ };
40
+ }
41
+
42
+ function toHex({ r, g, b }: Rgb): string {
43
+ const h = (n: number) => n.toString(16).padStart(2, '0');
44
+ return `#${h(r)}${h(g)}${h(b)}`;
45
+ }
46
+
47
+ function parseHexColor(input: string | undefined): Rgb | null {
48
+ if (typeof input !== 'string') return null;
49
+ const s = input.trim();
50
+ if (!/^#[0-9a-fA-F]{3}$|^#[0-9a-fA-F]{6}$/.test(s)) return null;
51
+ if (s.length === 4) {
52
+ const r = parseInt(s[1]! + s[1]!, 16);
53
+ const g = parseInt(s[2]! + s[2]!, 16);
54
+ const b = parseInt(s[3]! + s[3]!, 16);
55
+ return { r, g, b };
56
+ }
57
+ return {
58
+ r: parseInt(s.slice(1, 3), 16),
59
+ g: parseInt(s.slice(3, 5), 16),
60
+ b: parseInt(s.slice(5, 7), 16),
61
+ };
62
+ }
63
+
64
+ function rgba(rgb: Rgb, a: number): string {
65
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${a})`;
66
+ }
67
+
68
+ function mixCssHexOr(a: string, b: string, t: number, fallback: string): string {
69
+ const ra = parseHexColor(a);
70
+ const rb = parseHexColor(b);
71
+ if (!ra || !rb) return fallback;
72
+ return toHex(mixRgb(ra, rb, t));
73
+ }
74
+
75
+ function dividerFromMutedCss(muted: string): string {
76
+ const m = parseHexColor(muted);
77
+ if (m) return rgba(m, 0.28);
78
+ return 'rgba(148, 163, 184, 0.28)';
79
+ }
80
+
81
+ export function resolveNavigatorChromeTheme(
82
+ input?: NavigatorChromeParams | null
83
+ ): NavigatorChromeTheme {
84
+ const accentRgb =
85
+ parseHexColor(input?.accent) ?? parseHexColor(DEF_ACCENT) ?? { r: 59, g: 130, b: 246 };
86
+
87
+ const background =
88
+ typeof input?.hudBackground === 'string' && input.hudBackground.trim()
89
+ ? input.hudBackground.trim()
90
+ : DEF_HUD_BG;
91
+ const foreground =
92
+ typeof input?.hudForeground === 'string' && input.hudForeground.trim()
93
+ ? input.hudForeground.trim()
94
+ : DEF_HUD_FG;
95
+ const muted =
96
+ typeof input?.hudMuted === 'string' && input.hudMuted.trim()
97
+ ? input.hudMuted.trim()
98
+ : DEF_HUD_MUTED;
99
+
100
+ const subtle = mixCssHexOr(foreground, muted, 0.52, DEF_HUD_SUBTLE);
101
+ const summary = mixCssHexOr(foreground, muted, 0.3, DEF_HUD_SUMMARY);
102
+ const divider = dividerFromMutedCss(muted);
103
+
104
+ const iconForeground = toHex(mixRgb(accentRgb, RGB_WHITE, 0.38));
105
+ const iconBackground = rgba(accentRgb, 0.18);
106
+
107
+ return {
108
+ background,
109
+ foreground,
110
+ subtle,
111
+ muted,
112
+ summary,
113
+ divider,
114
+ iconBackground,
115
+ iconForeground,
116
+ shadow: 'rgba(15, 23, 42, 0.32)',
117
+ };
118
+ }
@@ -0,0 +1,177 @@
1
+ import Svg, { Circle, G, Path } from 'react-native-svg';
2
+
3
+ /**
4
+ * SVG-иконка манёвра навигатора. Порт `getSignIcon` из веб-части
5
+ * (`webProject/src/map/navigator.ts`) на `react-native-svg`.
6
+ */
7
+ export function NavigatorManeuverIcon({
8
+ sign,
9
+ color,
10
+ size = 32,
11
+ }: {
12
+ sign: number;
13
+ color: string;
14
+ size?: number;
15
+ }) {
16
+ const stroke = color;
17
+
18
+ const arrow = (rotation: number) => (
19
+ <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
20
+ <G rotation={rotation} origin="12, 12">
21
+ <Path
22
+ d="M12 21 V5"
23
+ stroke={stroke}
24
+ strokeWidth={2.4}
25
+ strokeLinecap="round"
26
+ strokeLinejoin="round"
27
+ />
28
+ <Path
29
+ d="M5 12 L12 5 L19 12"
30
+ stroke={stroke}
31
+ strokeWidth={2.4}
32
+ strokeLinecap="round"
33
+ strokeLinejoin="round"
34
+ />
35
+ </G>
36
+ </Svg>
37
+ );
38
+
39
+ switch (sign) {
40
+ case -3:
41
+ return arrow(-135);
42
+ case -2:
43
+ return arrow(-90);
44
+ case -1:
45
+ return arrow(-45);
46
+ case 0:
47
+ return arrow(0);
48
+ case 1:
49
+ return arrow(45);
50
+ case 2:
51
+ return arrow(90);
52
+ case 3:
53
+ return arrow(135);
54
+ case 4:
55
+ return (
56
+ <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
57
+ <Circle cx={12} cy={12} r={9} stroke={stroke} strokeWidth={2.2} />
58
+ <Circle cx={12} cy={12} r={3} fill={stroke} />
59
+ </Svg>
60
+ );
61
+ case 5:
62
+ return (
63
+ <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
64
+ <Circle cx={12} cy={12} r={4} stroke={stroke} strokeWidth={2.2} />
65
+ <Circle cx={12} cy={12} r={9} stroke={stroke} strokeWidth={2.2} />
66
+ </Svg>
67
+ );
68
+ case 6:
69
+ case -6:
70
+ return (
71
+ <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
72
+ <Circle cx={12} cy={12} r={6} stroke={stroke} strokeWidth={2.2} />
73
+ <Path
74
+ d="M12 18 V21"
75
+ stroke={stroke}
76
+ strokeWidth={2.2}
77
+ strokeLinecap="round"
78
+ strokeLinejoin="round"
79
+ />
80
+ <Path
81
+ d="M9 21 H15"
82
+ stroke={stroke}
83
+ strokeWidth={2.2}
84
+ strokeLinecap="round"
85
+ strokeLinejoin="round"
86
+ />
87
+ </Svg>
88
+ );
89
+ case -8:
90
+ case 8:
91
+ case -98:
92
+ return (
93
+ <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
94
+ <Path
95
+ d="M8 20 V11 a5 5 0 0 1 10 0 V14"
96
+ stroke={stroke}
97
+ strokeWidth={2.4}
98
+ strokeLinecap="round"
99
+ strokeLinejoin="round"
100
+ />
101
+ <Path
102
+ d="M14 18 L18 14 L22 18"
103
+ stroke={stroke}
104
+ strokeWidth={2.4}
105
+ strokeLinecap="round"
106
+ strokeLinejoin="round"
107
+ />
108
+ </Svg>
109
+ );
110
+ default:
111
+ return arrow(0);
112
+ }
113
+ }
114
+
115
+ /** Иконка кнопки «вернуть камеру на положение» (порт из веб recenter FAB). */
116
+ export function NavigatorRecenterIcon({
117
+ color,
118
+ size = 28,
119
+ }: {
120
+ color: string;
121
+ size?: number;
122
+ }) {
123
+ return (
124
+ <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
125
+ <Circle cx={12} cy={12} r={8.5} stroke={color} strokeWidth={2.2} />
126
+ <Path
127
+ d="M12 15.5 V8.5"
128
+ stroke={color}
129
+ strokeWidth={2.2}
130
+ strokeLinecap="round"
131
+ strokeLinejoin="round"
132
+ />
133
+ <Path
134
+ d="M9.25 11.25 L12 8.5 L14.75 11.25"
135
+ stroke={color}
136
+ strokeWidth={2.2}
137
+ strokeLinecap="round"
138
+ strokeLinejoin="round"
139
+ />
140
+ </Svg>
141
+ );
142
+ }
143
+
144
+ /** Иконка кнопки выбора голоса озвучки (порт из веб voice FAB). */
145
+ export function NavigatorVoiceIcon({
146
+ color,
147
+ size = 26,
148
+ }: {
149
+ color: string;
150
+ size?: number;
151
+ }) {
152
+ return (
153
+ <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
154
+ <Path
155
+ d="M11 5 L6 9 L2 9 L2 15 L6 15 L11 19 Z"
156
+ stroke={color}
157
+ strokeWidth={2}
158
+ strokeLinecap="round"
159
+ strokeLinejoin="round"
160
+ />
161
+ <Path
162
+ d="M15.54 8.46a5 5 0 0 1 0 7.07"
163
+ stroke={color}
164
+ strokeWidth={2}
165
+ strokeLinecap="round"
166
+ strokeLinejoin="round"
167
+ />
168
+ <Path
169
+ d="M19.07 4.93a10 10 0 0 1 0 14.14"
170
+ stroke={color}
171
+ strokeWidth={2}
172
+ strokeLinecap="round"
173
+ strokeLinejoin="round"
174
+ />
175
+ </Svg>
176
+ );
177
+ }