diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock index 71a87117..830f3eae 100644 --- a/apps/example/ios/Podfile.lock +++ b/apps/example/ios/Podfile.lock @@ -1878,6 +1878,98 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga + - RNScreens (4.24.0): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - RNScreens/common (= 4.24.0) + - Yoga + - RNScreens/common (4.24.0): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - RNSVG (15.15.4): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - RNSVG/common (= 15.15.4) + - Yoga + - RNSVG/common (15.15.4): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga - Yoga (0.0.0) DEPENDENCIES: @@ -1956,6 +2048,8 @@ DEPENDENCIES: - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`) - ReactNativeEnrichedMarkdown (from `../../..`) + - RNScreens (from `../node_modules/react-native-screens`) + - RNSVG (from `../node_modules/react-native-svg`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: @@ -2112,12 +2206,16 @@ EXTERNAL SOURCES: :podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec" ReactNativeEnrichedMarkdown: :path: "../../.." + RNScreens: + :path: "../node_modules/react-native-screens" + RNSVG: + :path: "../node_modules/react-native-svg" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: FBLazyVector: e97c19a5a442429d1988f182a1940fb08df514da - hermes-engine: b0f9c82a51be8e938eb979ada628323e1e093f1d + hermes-engine: fe39e9e5fd85771a2284437c03070d229bd86364 iosMath: f7a6cbadf9d836d2149c2a84c435b1effc244cba RCTDeprecation: af44b104091a34482596cd9bd7e8d90c4e9b4bd7 RCTRequired: bb77b070f75f53398ce43c0aaaa58337cebe2bf6 @@ -2127,7 +2225,7 @@ SPEC CHECKSUMS: React: 1ba7d364ade7d883a1ec055bfc3606f35fdee17b React-callinvoker: bc2a26f8d84fb01f003fc6de6c9337b64715f95b React-Core: 7840d3a80b43a95c5e80ef75146bd70925ebab0f - React-Core-prebuilt: 3dc04e91547fc0f260f4b84c12da0f672b813862 + React-Core-prebuilt: 5c6d4841913c2f9c34dc045ec2821a618e7ccf66 React-CoreModules: 2eb010400b63b89e53a324ffb3c112e4c7c3ce42 React-cxxreact: a558e92199d26f145afa9e62c4233cf8e7950efe React-debug: 755200a6e7f5e6e0a40ff8d215493d43cce285fc @@ -2189,10 +2287,12 @@ SPEC CHECKSUMS: ReactAppDependencyProvider: e96e93b493d8d86eeaee3e590ba0be53f6abe46f ReactCodegen: 797de5178718324c6eba3327b07f9a423fbd5787 ReactCommon: 07572bf9e687c8a52fbe4a3641e9e3a1a477c78e - ReactNativeDependencies: 44f7326a697de7f6c8629036b1a4689f0e64c684 + ReactNativeDependencies: 07a3c3c91a68225c545417dde4202a570b8b401d ReactNativeEnrichedMarkdown: e6fea750b1ca4cbd853c1c78de9bd1ccb638ab77 + RNScreens: 6cb648bdad8fe9bee9259fe144df95b6d1d5b707 + RNSVG: c69f7709226108f5eb89b5aa8833c17a36345468 Yoga: c0b3f2c7e8d3e327e450223a2414ca3fa296b9a2 PODFILE CHECKSUM: 9c5417fc84515945aa2357a49779fde55434ae62 -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/apps/example/metro.config.js b/apps/example/metro.config.js index bb9d3c2a..aab7a56b 100644 --- a/apps/example/metro.config.js +++ b/apps/example/metro.config.js @@ -1,16 +1,20 @@ const path = require('path'); -const { getDefaultConfig } = require('@react-native/metro-config'); +const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); const { withMetroConfig } = require('react-native-monorepo-config'); const root = path.resolve(__dirname, '../..'); +const defaultConfig = getDefaultConfig(__dirname); +const { assetExts, sourceExts } = defaultConfig.resolver; -/** - * Metro configuration - * https://facebook.github.io/metro/docs/configuration - * - * @type {import('metro-config').MetroConfig} - */ -module.exports = withMetroConfig(getDefaultConfig(__dirname), { - root, - dirname: __dirname, -}); +module.exports = withMetroConfig( + mergeConfig(defaultConfig, { + transformer: { + babelTransformerPath: require.resolve('react-native-svg-transformer'), + }, + resolver: { + assetExts: assetExts.filter((ext) => ext !== 'svg'), + sourceExts: [...sourceExts, 'svg'], + }, + }), + { root, dirname: __dirname } +); diff --git a/apps/example/package.json b/apps/example/package.json index 9f3c6885..15a1c160 100644 --- a/apps/example/package.json +++ b/apps/example/package.json @@ -11,9 +11,13 @@ }, "dependencies": { "@react-native/new-app-screen": "0.84.1", + "@react-navigation/native": "^7.2.2", + "@react-navigation/native-stack": "^7.14.12", "react": "19.2.3", "react-native": "0.84.1", - "react-native-safe-area-context": "^5.5.2" + "react-native-safe-area-context": "^5.5.2", + "react-native-screens": "^4.24.0", + "react-native-svg": "^15.15.4" }, "devDependencies": { "@babel/core": "^7.25.2", @@ -27,7 +31,8 @@ "@react-native/typescript-config": "0.84.1", "@types/react": "^19.2.0", "react-native-builder-bob": "^0.40.18", - "react-native-monorepo-config": "^0.3.3" + "react-native-monorepo-config": "^0.3.3", + "react-native-svg-transformer": "^1.5.3" }, "engines": { "node": ">= 22.11.0" diff --git a/apps/example/src/App.tsx b/apps/example/src/App.tsx index b9d71b60..f6c750a4 100644 --- a/apps/example/src/App.tsx +++ b/apps/example/src/App.tsx @@ -1,142 +1,53 @@ -import { useState, useMemo } from 'react'; -import { - StyleSheet, - ScrollView, - Alert, - Linking, - Platform, - View, - Text, -} from 'react-native'; -import { - EnrichedMarkdownText, - type LinkPressEvent, -} from 'react-native-enriched-markdown'; -import { SafeAreaView } from 'react-native-safe-area-context'; -import { sampleMarkdown } from './sampleMarkdown'; -import { customMarkdownStyle } from './markdownStyles'; -import InputScreen from './InputScreen'; -import StreamingMarkdownSimulator from './StreamingMarkdownSimulator'; - -type Screen = 'text' | 'input' | 'stream'; +import { NavigationContainer } from '@react-navigation/native'; +import { Stack } from './navigation/Stack'; +import HomeScreen from './screens/home/HomeScreen'; +import PlaygroundScreen from './screens/playground/PlaygroundScreen'; +import TextScreen from './screens/text/TextScreen'; +import InputScreen from './screens/input/InputScreen'; +import StreamingMarkdownSimulator from './screens/streaming/StreamingMarkdownSimulator'; export default function App() { - const [screen, setScreen] = useState('input'); - const markdownStyle = useMemo(() => customMarkdownStyle, []); - - const contextMenuItems = useMemo( - () => [ - { - text: 'Summarize with AI', - icon: Platform.OS === 'ios' ? 'sparkles' : undefined, - onPress: ({ text }: { text: string }) => { - Alert.alert('✦ Summarize with AI', `"${text}"`, [ - { text: 'Dismiss', style: 'cancel' }, - ]); - }, - }, - { - text: 'Translate', - icon: Platform.OS === 'ios' ? 'globe' : undefined, - onPress: ({ text }: { text: string }) => { - Alert.alert('Translate', `"${text}"`, [ - { text: 'Dismiss', style: 'cancel' }, - ]); - }, - }, - ], - [] - ); - - const handleLinkPress = (event: LinkPressEvent) => { - const { url } = event; - Alert.alert('Link Pressed!', `You tapped on: ${url}`, [ - { - text: 'Open in Browser', - onPress: () => { - Linking.openURL(url); - }, - }, - { - text: 'Cancel', - style: 'cancel', - }, - ]); - }; - return ( - - - setScreen('input')} - > - Input - - setScreen('text')} - > - Text - - setScreen('stream')} - > - Stream - - - - {screen === 'input' ? ( - - ) : screen === 'stream' ? ( - - ) : ( - - - - )} - + + + + + + + + + ); } - -const styles = StyleSheet.create({ - root: { - flex: 1, - }, - tabs: { - flexDirection: 'row', - borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: '#D1D5DB', - }, - tab: { - flex: 1, - textAlign: 'center', - paddingVertical: 12, - fontSize: 15, - fontWeight: '500', - color: '#6B7280', - }, - tabActive: { - color: '#2563EB', - borderBottomWidth: 2, - borderBottomColor: '#2563EB', - }, - scrollView: { - paddingHorizontal: 16, - }, - content: { - paddingVertical: 16, - }, -}); diff --git a/apps/example/src/assets/icons/add_link_24dp.svg b/apps/example/src/assets/icons/add_link_24dp.svg new file mode 100644 index 00000000..8ad0dded --- /dev/null +++ b/apps/example/src/assets/icons/add_link_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/example/src/assets/icons/format_bold_24dp.svg b/apps/example/src/assets/icons/format_bold_24dp.svg new file mode 100644 index 00000000..a3f4c8ec --- /dev/null +++ b/apps/example/src/assets/icons/format_bold_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/example/src/assets/icons/format_italic_24dp.svg b/apps/example/src/assets/icons/format_italic_24dp.svg new file mode 100644 index 00000000..3585e98d --- /dev/null +++ b/apps/example/src/assets/icons/format_italic_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/example/src/assets/icons/format_underlined_24dp.svg b/apps/example/src/assets/icons/format_underlined_24dp.svg new file mode 100644 index 00000000..ce5ba37f --- /dev/null +++ b/apps/example/src/assets/icons/format_underlined_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/example/src/assets/icons/strikethrough_s_24dp.svg b/apps/example/src/assets/icons/strikethrough_s_24dp.svg new file mode 100644 index 00000000..f0b7b702 --- /dev/null +++ b/apps/example/src/assets/icons/strikethrough_s_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/example/src/assets/icons/visibility_off_24dp.svg b/apps/example/src/assets/icons/visibility_off_24dp.svg new file mode 100644 index 00000000..2eb0dae4 --- /dev/null +++ b/apps/example/src/assets/icons/visibility_off_24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/example/src/components/FormattingToolbar.tsx b/apps/example/src/components/FormattingToolbar.tsx new file mode 100644 index 00000000..2b07fd21 --- /dev/null +++ b/apps/example/src/components/FormattingToolbar.tsx @@ -0,0 +1,168 @@ +import { useCallback, useRef, useState } from 'react'; +import { + View, + TouchableOpacity, + StyleSheet, + type StyleProp, + type ViewStyle, +} from 'react-native'; +import { + type EnrichedMarkdownTextInputInstance, + type StyleState, +} from 'react-native-enriched-markdown'; +import { LinkModal } from './LinkModal'; +import BoldIcon from '../assets/icons/format_bold_24dp.svg'; +import ItalicIcon from '../assets/icons/format_italic_24dp.svg'; +import UnderlineIcon from '../assets/icons/format_underlined_24dp.svg'; +import StrikethroughIcon from '../assets/icons/strikethrough_s_24dp.svg'; +import SpoilerIcon from '../assets/icons/visibility_off_24dp.svg'; +import AddLinkIcon from '../assets/icons/add_link_24dp.svg'; + +interface FormattingToolbarProps { + state: StyleState | null; + inputRef: React.RefObject; + hasSelection: boolean; + style?: StyleProp; + testID?: string; +} + +const ICON_COLOR = '#001A72'; +const ICON_SIZE = 18; + +const ITEMS = [ + { + styleKey: 'bold', + action: 'toggleBold', + icon: , + }, + { + styleKey: 'italic', + action: 'toggleItalic', + icon: ( + + ), + }, + { + styleKey: 'underline', + action: 'toggleUnderline', + icon: ( + + ), + }, + { + styleKey: 'strikethrough', + action: 'toggleStrikethrough', + icon: ( + + ), + }, + { + styleKey: 'spoiler', + action: 'toggleSpoiler', + icon: ( + + ), + }, +] as const; + +const LINK_ICON = ( + +); + +export function FormattingToolbar({ + state, + inputRef, + hasSelection, + style, + testID, +}: FormattingToolbarProps) { + const [linkModalVisible, setLinkModalVisible] = useState(false); + const selectionAtOpen = useRef(false); + + const handleLinkButtonPress = useCallback(() => { + if (state?.link.isActive) { + inputRef.current?.removeLink(); + } else { + selectionAtOpen.current = hasSelection; + setLinkModalVisible(true); + } + }, [state?.link.isActive, hasSelection, inputRef]); + + const handleLinkSubmit = useCallback( + (text: string, url: string) => { + setLinkModalVisible(false); + if (!url) return; + if (selectionAtOpen.current) { + inputRef.current?.setLink(url); + } else { + inputRef.current?.insertLink(text, url); + } + }, + [inputRef] + ); + + return ( + <> + + {ITEMS.map(({ styleKey, action, icon }) => ( + inputRef.current?.[action]()} + testID={`toolbar-${styleKey}`} + > + {icon} + + ))} + + {LINK_ICON} + + + setLinkModalVisible(false)} + onSubmit={handleLinkSubmit} + /> + + ); +} + +const styles = StyleSheet.create({ + toolbar: { + flexDirection: 'row', + gap: 4, + paddingHorizontal: 10, + paddingVertical: 8, + borderTopWidth: StyleSheet.hairlineWidth, + borderTopColor: '#E5E7EB', + backgroundColor: '#F9FAFB', + }, + toolbarButton: { + minWidth: 34, + height: 30, + borderRadius: 6, + justifyContent: 'center', + alignItems: 'center', + paddingHorizontal: 6, + backgroundColor: 'transparent', + }, + toolbarButtonActive: { + backgroundColor: '#E2F8EB', + }, +}); diff --git a/apps/example/src/LinkModal.tsx b/apps/example/src/components/LinkModal.tsx similarity index 100% rename from apps/example/src/LinkModal.tsx rename to apps/example/src/components/LinkModal.tsx diff --git a/apps/example/src/navigation/Stack.tsx b/apps/example/src/navigation/Stack.tsx new file mode 100644 index 00000000..215dd013 --- /dev/null +++ b/apps/example/src/navigation/Stack.tsx @@ -0,0 +1,4 @@ +import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import type { RootStackParamList } from './types'; + +export const Stack = createNativeStackNavigator(); diff --git a/apps/example/src/navigation/types.ts b/apps/example/src/navigation/types.ts new file mode 100644 index 00000000..63ca3354 --- /dev/null +++ b/apps/example/src/navigation/types.ts @@ -0,0 +1,18 @@ +import type { NativeStackScreenProps } from '@react-navigation/native-stack'; + +export type RootStackParamList = { + Home: undefined; + Playground: undefined; + Text: undefined; + Input: undefined; + Stream: undefined; +}; + +export type RootStackScreenProps = + NativeStackScreenProps; + +declare global { + namespace ReactNavigation { + interface RootParamList extends RootStackParamList {} + } +} diff --git a/apps/example/src/screens/home/HomeScreen.tsx b/apps/example/src/screens/home/HomeScreen.tsx new file mode 100644 index 00000000..757f4418 --- /dev/null +++ b/apps/example/src/screens/home/HomeScreen.tsx @@ -0,0 +1,91 @@ +import { View, Text, StyleSheet } from 'react-native'; +import { HomeScreenButton } from './HomeScreenButton'; +import type { + RootStackParamList, + RootStackScreenProps, +} from '../../navigation/types'; + +type Props = RootStackScreenProps<'Home'>; + +type ScreenItem = { + route: Exclude; + label: string; + subtext: string; + testID: string; + color: string; +}; + +const SCREENS: ScreenItem[] = [ + { + route: 'Playground', + label: 'Playground', + subtext: 'live editor with preview', + testID: 'home-block-playground', + color: '#007AFF', + }, + { + route: 'Text', + label: 'Text', + subtext: 'static markdown rendering', + testID: 'home-block-text', + color: '#34C759', + }, + { + route: 'Input', + label: 'Input', + subtext: 'chat-style rich text input', + testID: 'home-block-input', + color: '#FF9500', + }, + { + route: 'Stream', + label: 'Stream', + subtext: 'streaming markdown with tables', + testID: 'home-block-stream', + color: '#AF52DE', + }, +]; + +export default function HomeScreen({ navigation }: Props) { + return ( + + Enriched Markdown Examples + + Explore different markdown rendering and input capabilities + + + {SCREENS.map(({ route, label, subtext, testID, color }) => ( + navigation.navigate(route)} + /> + ))} + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + padding: 20, + backgroundColor: '#f5f5f5', + }, + title: { + fontSize: 28, + fontWeight: 'bold', + marginBottom: 10, + textAlign: 'center', + }, + subtitle: { + fontSize: 16, + color: '#666', + marginBottom: 40, + textAlign: 'center', + }, +}); diff --git a/apps/example/src/screens/home/HomeScreenButton.tsx b/apps/example/src/screens/home/HomeScreenButton.tsx new file mode 100644 index 00000000..ffa2c567 --- /dev/null +++ b/apps/example/src/screens/home/HomeScreenButton.tsx @@ -0,0 +1,50 @@ +import { Text, StyleSheet, TouchableOpacity } from 'react-native'; + +type Props = { + label: string; + subtext: string; + testID: string; + color: string; + onPress: () => void; +}; + +export function HomeScreenButton({ + label, + subtext, + testID, + color, + onPress, +}: Props) { + return ( + + {label} + {subtext} + + ); +} + +const styles = StyleSheet.create({ + button: { + paddingHorizontal: 30, + paddingVertical: 15, + borderRadius: 10, + marginVertical: 10, + minWidth: 250, + }, + buttonText: { + color: 'white', + fontSize: 16, + fontWeight: '600', + textAlign: 'center', + }, + buttonSubtext: { + color: 'rgba(255,255,255,0.8)', + fontSize: 12, + textAlign: 'center', + marginTop: 2, + }, +}); diff --git a/apps/example/src/InputScreen.tsx b/apps/example/src/screens/input/InputScreen.tsx similarity index 65% rename from apps/example/src/InputScreen.tsx rename to apps/example/src/screens/input/InputScreen.tsx index 71a10bbc..ba272806 100644 --- a/apps/example/src/InputScreen.tsx +++ b/apps/example/src/screens/input/InputScreen.tsx @@ -9,14 +9,15 @@ import { Platform, Alert, } from 'react-native'; -import type { HostInstance } from 'react-native'; +import { useHeaderHeight } from '@react-navigation/elements'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { EnrichedMarkdownTextInput, EnrichedMarkdownText, type EnrichedMarkdownTextInputInstance, type StyleState, } from 'react-native-enriched-markdown'; -import { LinkModal } from './LinkModal'; +import { FormattingToolbar } from '../../components/FormattingToolbar'; interface Message { id: number; @@ -70,13 +71,13 @@ let nextId = 6; export default function InputScreen() { const inputRef = useRef(null); - const scrollRef = useRef>(null); + const scrollRef = useRef>(null); const [state, setState] = useState(null); const [messages, setMessages] = useState(INITIAL_MESSAGES); - const [linkModalVisible, setLinkModalVisible] = useState(false); - const [linkModalText, setLinkModalText] = useState(''); - const [linkModalUrl, setLinkModalUrl] = useState(''); - const hasSelectionRef = useRef(false); + const [hasSelection, setHasSelection] = useState(false); + const navHeaderHeight = useHeaderHeight(); + const [chatHeaderHeight, setChatHeaderHeight] = useState(0); + const { bottom: bottomInset } = useSafeAreaInsets(); const sendMessage = useCallback(async () => { const md = await inputRef.current?.getMarkdown(); @@ -94,23 +95,6 @@ export default function InputScreen() { setTimeout(() => scrollRef.current?.scrollToEnd({ animated: true }), 50); }, []); - const openLinkModal = useCallback(() => { - setLinkModalText(''); - setLinkModalUrl(''); - setLinkModalVisible(true); - }, []); - - const handleLinkSubmit = useCallback((text: string, url: string) => { - setLinkModalVisible(false); - if (url.length === 0) return; - - if (hasSelectionRef.current) { - inputRef.current?.setLink(url); - } else { - inputRef.current?.insertLink(text, url); - } - }, []); - const bubbleContextMenuItems = useMemo( () => [ { @@ -168,20 +152,12 @@ export default function InputScreen() { [] ); - const containerRef = useRef(null); - const [keyboardOffset, setKeyboardOffset] = useState(0); - - const measureContainer = useCallback(() => { - containerRef.current?.measureInWindow((_x, y) => setKeyboardOffset(y)); - }, []); - return ( - - + + setChatHeaderHeight(e.nativeEvent.layout.height)} + > JD @@ -194,7 +170,7 @@ export default function InputScreen() { ))} - - {( - [ - { label: 'B', style: 'bold', action: 'toggleBold' }, - { label: 'I', style: 'italic', action: 'toggleItalic' }, - { label: 'U', style: 'underline', action: 'toggleUnderline' }, - { - label: 'S', - style: 'strikethrough', - action: 'toggleStrikethrough', - }, - { - label: '||', - style: 'spoiler', - action: 'toggleSpoiler', - }, - ] as const - ).map(({ label, style, action }) => ( - inputRef.current?.[action]()} - > - - {label} - - - ))} - { - if (state?.link.isActive) { - inputRef.current?.removeLink(); - } else { - openLinkModal(); - } - }} - > - - Link - - - - + + { - hasSelectionRef.current = sel.start !== sel.end; - }} + onChangeSelection={(sel) => setHasSelection(sel.start !== sel.end)} contextMenuItems={inputContextMenuItems} /> @@ -319,13 +236,6 @@ export default function InputScreen() { - setLinkModalVisible(false)} - onSubmit={handleLinkSubmit} - /> ); } @@ -427,44 +337,6 @@ const styles = StyleSheet.create({ bubbleTimeOther: { color: '#9CA3AF', }, - toolbar: { - flexDirection: 'row', - gap: 4, - paddingHorizontal: 12, - paddingTop: 8, - paddingBottom: 4, - backgroundColor: '#F9FAFB', - borderTopWidth: StyleSheet.hairlineWidth, - borderTopColor: '#E5E7EB', - }, - toolbarButton: { - width: 34, - height: 30, - borderRadius: 6, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: 'transparent', - }, - toolbarButtonActive: { - backgroundColor: '#DBEAFE', - }, - toolbarButtonText: { - fontSize: 15, - fontWeight: '700', - color: '#374151', - }, - toolbarButtonTextActive: { - color: '#2563EB', - }, - italic: { - fontStyle: 'italic', - }, - underline: { - textDecorationLine: 'underline', - }, - strikethrough: { - textDecorationLine: 'line-through', - }, inputRow: { flexDirection: 'row', alignItems: 'flex-end', diff --git a/apps/example/src/screens/playground/PlaygroundScreen.tsx b/apps/example/src/screens/playground/PlaygroundScreen.tsx new file mode 100644 index 00000000..d81d9d48 --- /dev/null +++ b/apps/example/src/screens/playground/PlaygroundScreen.tsx @@ -0,0 +1,256 @@ +import { useRef, useState, useCallback } from 'react'; +import { + View, + Text, + ScrollView, + TouchableOpacity, + StyleSheet, + KeyboardAvoidingView, + Platform, + Alert, +} from 'react-native'; +import { useHeaderHeight } from '@react-navigation/elements'; +import { + EnrichedMarkdownTextInput, + EnrichedMarkdownText, + type EnrichedMarkdownTextInputInstance, + type StyleState, +} from 'react-native-enriched-markdown'; +import { FormattingToolbar } from '../../components/FormattingToolbar'; + +const MARKDOWN_STYLE = { + link: { color: '#2563EB', underline: true as const }, + code: { color: '#7c3aed', backgroundColor: '#f5f3ff' }, + codeBlock: { + color: '#f3f4f6', + backgroundColor: '#1f2937', + borderRadius: 8, + }, + blockquote: { + color: '#4b5563', + borderColor: '#d1d5db', + borderWidth: 3, + gapWidth: 12, + }, + table: { + borderColor: '#e5e7eb', + borderRadius: 6, + cellPaddingHorizontal: 10, + cellPaddingVertical: 6, + }, + taskList: { + checkedColor: '#2563eb', + borderColor: '#9ca3af', + checkmarkColor: '#ffffff', + checkedStrikethrough: true, + }, +}; + +export default function PlaygroundScreen() { + const headerHeight = useHeaderHeight(); + const inputRef = useRef(null); + const [state, setState] = useState(null); + const [markdown, setMarkdown] = useState(''); + const [sizeMode, setSizeMode] = useState<'base' | 'max'>('base'); + const [hasSelection, setHasSelection] = useState(false); + const handleGetMarkdown = useCallback(async () => { + const md = await inputRef.current?.getMarkdown(); + Alert.alert('Markdown', md ?? '(empty)', [{ text: 'OK' }]); + }, []); + + return ( + + + + inputRef.current?.focus()} + testID="focus-button" + > + Focus + + inputRef.current?.blur()} + testID="blur-button" + > + Blur + + { + inputRef.current?.setValue(''); + setMarkdown(''); + }} + testID="clear-button" + > + Clear + + setSizeMode((m) => (m === 'max' ? 'base' : 'max'))} + testID="size-button" + > + + {sizeMode === 'max' ? 'Base' : 'Max'} + + + + + + setHasSelection(sel.start !== sel.end)} + /> + + + + + Get Raw Markdown + + + + + Preview + + {markdown.length > 0 ? ( + + Alert.alert('Link', url, [{ text: 'OK' }]) + } + onTaskListItemPress={({ checked, index }) => + Alert.alert( + 'Task item', + `Item ${index} is now ${checked ? 'checked' : 'unchecked'}`, + [{ text: 'OK' }] + ) + } + testID="preview-text" + /> + ) : ( + + Preview will appear here + + )} + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#F9FAFB', + }, + scroll: { + flex: 1, + }, + content: { + padding: 16, + gap: 12, + }, + buttonRow: { + flexDirection: 'row', + gap: 8, + }, + button: { + flex: 1, + paddingVertical: 9, + borderRadius: 8, + backgroundColor: '#E5E7EB', + alignItems: 'center', + }, + buttonText: { + fontSize: 13, + fontWeight: '600', + color: '#374151', + }, + editorContainer: { + borderRadius: 10, + borderWidth: StyleSheet.hairlineWidth, + borderColor: '#D1D5DB', + overflow: 'hidden', + backgroundColor: '#FFFFFF', + }, + input: { + minHeight: 120, + maxHeight: 200, + fontSize: 15, + color: '#111827', + paddingHorizontal: 14, + paddingVertical: 12, + }, + inputMax: { + maxHeight: 400, + }, + getMarkdownButton: { + paddingVertical: 10, + borderRadius: 8, + backgroundColor: '#BEEBD0', + alignItems: 'center', + }, + getMarkdownText: { + fontSize: 14, + fontWeight: '600', + color: '#001A72', + }, + divider: { + height: StyleSheet.hairlineWidth, + backgroundColor: '#E5E7EB', + marginVertical: 4, + }, + previewLabel: { + fontSize: 12, + fontWeight: '600', + color: '#9CA3AF', + textTransform: 'uppercase', + letterSpacing: 0.5, + }, + previewContainer: { + backgroundColor: '#FFFFFF', + borderRadius: 10, + borderWidth: StyleSheet.hairlineWidth, + borderColor: '#D1D5DB', + padding: 14, + minHeight: 80, + }, + previewEmpty: { + fontSize: 14, + color: '#9CA3AF', + fontStyle: 'italic', + }, +}); diff --git a/apps/example/src/StreamingMarkdownSimulator.tsx b/apps/example/src/screens/streaming/StreamingMarkdownSimulator.tsx similarity index 97% rename from apps/example/src/StreamingMarkdownSimulator.tsx rename to apps/example/src/screens/streaming/StreamingMarkdownSimulator.tsx index 3b6707e0..f144ec6f 100644 --- a/apps/example/src/StreamingMarkdownSimulator.tsx +++ b/apps/example/src/screens/streaming/StreamingMarkdownSimulator.tsx @@ -7,7 +7,7 @@ import { View, } from 'react-native'; import { EnrichedMarkdownText } from 'react-native-enriched-markdown'; -import { customMarkdownStyle } from './markdownStyles'; +import { customMarkdownStyle } from '../../markdownStyles'; const STREAM_SOURCE = `Here is a longer streamed answer used to stress GitHub-flavored markdown streaming on iOS. @@ -114,7 +114,11 @@ export default function StreamingMarkdownSimulator() { }, [isStreaming, isComplete, step]); return ( - + Streaming markdown simulator JS-only stream: longer text, several tables, and several block LaTeX diff --git a/apps/example/src/screens/text/TextScreen.tsx b/apps/example/src/screens/text/TextScreen.tsx new file mode 100644 index 00000000..e2b354f1 --- /dev/null +++ b/apps/example/src/screens/text/TextScreen.tsx @@ -0,0 +1,79 @@ +import { useMemo } from 'react'; +import { ScrollView, StyleSheet, Platform, Alert, Linking } from 'react-native'; +import { + EnrichedMarkdownText, + type LinkPressEvent, +} from 'react-native-enriched-markdown'; +import { sampleMarkdown } from '../../sampleMarkdown'; +import { customMarkdownStyle } from '../../markdownStyles'; + +export default function TextScreen() { + const markdownStyle = useMemo(() => customMarkdownStyle, []); + + const contextMenuItems = useMemo( + () => [ + { + text: 'Summarize with AI', + icon: Platform.OS === 'ios' ? 'sparkles' : undefined, + onPress: ({ text }: { text: string }) => { + Alert.alert('✦ Summarize with AI', `"${text}"`, [ + { text: 'Dismiss', style: 'cancel' }, + ]); + }, + }, + { + text: 'Translate', + icon: Platform.OS === 'ios' ? 'globe' : undefined, + onPress: ({ text }: { text: string }) => { + Alert.alert('Translate', `"${text}"`, [ + { text: 'Dismiss', style: 'cancel' }, + ]); + }, + }, + ], + [] + ); + + const handleLinkPress = (event: LinkPressEvent) => { + const { url } = event; + Alert.alert('Link Pressed!', `You tapped on: ${url}`, [ + { + text: 'Open in Browser', + onPress: () => { + Linking.openURL(url); + }, + }, + { + text: 'Cancel', + style: 'cancel', + }, + ]); + }; + + return ( + + + + ); +} + +const styles = StyleSheet.create({ + scrollView: { + paddingHorizontal: 16, + }, + content: { + paddingVertical: 16, + }, +}); diff --git a/apps/example/src/types/svg.d.ts b/apps/example/src/types/svg.d.ts new file mode 100644 index 00000000..6a0b0b83 --- /dev/null +++ b/apps/example/src/types/svg.d.ts @@ -0,0 +1,5 @@ +declare module '*.svg' { + import type { SvgProps } from 'react-native-svg'; + const content: React.FC; + export default content; +} diff --git a/apps/example/tsconfig.json b/apps/example/tsconfig.json new file mode 100644 index 00000000..6f548a07 --- /dev/null +++ b/apps/example/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@react-native/typescript-config/tsconfig.json", + "compilerOptions": { + "jsx": "react-native", + "baseUrl": "../..", + "paths": { + "react-native-enriched-markdown": ["./src/index"] + } + } +} diff --git a/ios/views/EnrichedMarkdownInternalText.m b/ios/views/EnrichedMarkdownInternalText.m index cdb8a0b5..20700c5d 100644 --- a/ios/views/EnrichedMarkdownInternalText.m +++ b/ios/views/EnrichedMarkdownInternalText.m @@ -78,6 +78,7 @@ - (void)applyAttributedText:(NSMutableAttributedString *)text context:(RenderCon [_textView.layoutManager invalidateLayoutForCharacterRange:NSMakeRange(0, text.length) actualCharacterRange:NULL]; [_spoilerManager setNeedsUpdate]; + [self setNeedsLayout]; #if !TARGET_OS_OSX [_textView setNeedsLayout]; diff --git a/tsconfig.json b/tsconfig.json index 130d2143..bbb9a963 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,5 @@ { + "exclude": ["apps/"], "compilerOptions": { "rootDir": ".", "paths": { diff --git a/yarn.lock b/yarn.lock index 1d5df6aa..d48f1c39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -89,7 +89,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.20.0, @babel/core@npm:^7.24.4": +"@babel/core@npm:^7.20.0, @babel/core@npm:^7.21.3, @babel/core@npm:^7.24.4": version: 7.29.0 resolution: "@babel/core@npm:7.29.0" dependencies: @@ -1889,7 +1889,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.25.2, @babel/types@npm:^7.26.0, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0": +"@babel/types@npm:^7.21.3, @babel/types@npm:^7.25.2, @babel/types@npm:^7.26.0, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0": version: 7.29.0 resolution: "@babel/types@npm:7.29.0" dependencies: @@ -4750,6 +4750,87 @@ __metadata: languageName: node linkType: hard +"@react-navigation/core@npm:^7.17.2": + version: 7.17.2 + resolution: "@react-navigation/core@npm:7.17.2" + dependencies: + "@react-navigation/routers": "npm:^7.5.3" + escape-string-regexp: "npm:^4.0.0" + fast-deep-equal: "npm:^3.1.3" + nanoid: "npm:^3.3.11" + query-string: "npm:^7.1.3" + react-is: "npm:^19.1.0" + use-latest-callback: "npm:^0.2.4" + use-sync-external-store: "npm:^1.5.0" + peerDependencies: + react: ">= 18.2.0" + checksum: 10c0/df1889769e90f85b71605070818b22bd9967f5fd0572187d31e6a17386339336c8890b9c7ba505854382426cb3b5be8d03ea4684da4ad5be2cdae828302b98a0 + languageName: node + linkType: hard + +"@react-navigation/elements@npm:^2.9.15": + version: 2.9.15 + resolution: "@react-navigation/elements@npm:2.9.15" + dependencies: + color: "npm:^4.2.3" + use-latest-callback: "npm:^0.2.4" + use-sync-external-store: "npm:^1.5.0" + peerDependencies: + "@react-native-masked-view/masked-view": ">= 0.2.0" + "@react-navigation/native": ^7.2.2 + react: ">= 18.2.0" + react-native: "*" + react-native-safe-area-context: ">= 4.0.0" + peerDependenciesMeta: + "@react-native-masked-view/masked-view": + optional: true + checksum: 10c0/0fce662e717573b85028626edfe7100af2bfc5ee32a4ca17f6216ad8091091baa4a14d6acc27ead48d3f700610d81a93dd85013d5643cca2bfeae7bfa88826b2 + languageName: node + linkType: hard + +"@react-navigation/native-stack@npm:^7.14.12": + version: 7.14.12 + resolution: "@react-navigation/native-stack@npm:7.14.12" + dependencies: + "@react-navigation/elements": "npm:^2.9.15" + color: "npm:^4.2.3" + sf-symbols-typescript: "npm:^2.1.0" + warn-once: "npm:^0.1.1" + peerDependencies: + "@react-navigation/native": ^7.2.2 + react: ">= 18.2.0" + react-native: "*" + react-native-safe-area-context: ">= 4.0.0" + react-native-screens: ">= 4.0.0" + checksum: 10c0/abffb7efca6376863b9d7d89418cfe41d149e27a2eee6b611155d8e582a7bde8eb1b314d4c99905be90e64792e23c0347efd226d5ffbbcfa1b2c2f707c596bdc + languageName: node + linkType: hard + +"@react-navigation/native@npm:^7.2.2": + version: 7.2.2 + resolution: "@react-navigation/native@npm:7.2.2" + dependencies: + "@react-navigation/core": "npm:^7.17.2" + escape-string-regexp: "npm:^4.0.0" + fast-deep-equal: "npm:^3.1.3" + nanoid: "npm:^3.3.11" + use-latest-callback: "npm:^0.2.4" + peerDependencies: + react: ">= 18.2.0" + react-native: "*" + checksum: 10c0/3ca6e742da2ed4110b81fc008536ca62f07cdf49b368e9b7f73cbc25ad86603f87f14d08492bf1de2647ca6f4cf7141bec4fa3cd76961fa2fa22f83d0f805e83 + languageName: node + linkType: hard + +"@react-navigation/routers@npm:^7.5.3": + version: 7.5.3 + resolution: "@react-navigation/routers@npm:7.5.3" + dependencies: + nanoid: "npm:^3.3.11" + checksum: 10c0/85f6cb9ac71e0492845aa87637c7c745d85aa15e4ad7e71a8d910080f5d5a469dd348f59ffaaed8c488cb92708fae56350a0bfc7bc5750c65e12da1f0d4eca70 + languageName: node + linkType: hard + "@release-it/conventional-changelog@npm:^10.0.1": version: 10.0.1 resolution: "@release-it/conventional-changelog@npm:10.0.1" @@ -4820,6 +4901,146 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/a50bd0baa34faf16bcba712091f94c7f0e230431fe99a9dfc3401fa92823ad3f68495b86ab9bf9044b53839e8c416cfbb37eb3f246ff33f261e0fa9ee1779c5b + languageName: node + linkType: hard + +"@svgr/babel-plugin-remove-jsx-attribute@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-attribute@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/8a98e59bd9971e066815b4129409932f7a4db4866834fe75677ea6d517972fb40b380a69a4413189f20e7947411f9ab1b0f029dd5e8068686a5a0188d3ccd4c7 + languageName: node + linkType: hard + +"@svgr/babel-plugin-remove-jsx-empty-expression@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-empty-expression@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/517dcca75223bd05d3f056a8514dbba3031278bea4eadf0842c576d84f4651e7a4e0e7082d3ee4ef42456de0f9c4531d8a1917c04876ca64b014b859ca8f1bde + languageName: node + linkType: hard + +"@svgr/babel-plugin-replace-jsx-attribute-value@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-replace-jsx-attribute-value@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/004bd1892053b7e9c1b0bb14acc44e77634ec393722b87b1e4fae53e2c35122a2dd0d5c15e9070dbeec274e22e7693a2b8b48506733a8009ee92b12946fcb10a + languageName: node + linkType: hard + +"@svgr/babel-plugin-svg-dynamic-title@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-svg-dynamic-title@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/80e0a7fcf902f984c705051ca5c82ea6050ccbb70b651a8fea6d0eb5809e4dac274b49ea6be2d87f1eb9dfc0e2d6cdfffe1669ec2117f44b67a60a07d4c0b8b8 + languageName: node + linkType: hard + +"@svgr/babel-plugin-svg-em-dimensions@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-svg-em-dimensions@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/73e92c8277a89279745c0c500f59f083279a8dc30cd552b22981fade2a77628fb2bd2819ee505725fcd2e93f923e3790b52efcff409a159e657b46604a0b9a21 + languageName: node + linkType: hard + +"@svgr/babel-plugin-transform-react-native-svg@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/babel-plugin-transform-react-native-svg@npm:8.1.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/655ed6bc7a208ceaa4ecff0a54ccc36008c3cb31efa90d11e171cab325ebbb21aa78f09c7b65f9b3ddeda3a85f348c0c862902c48be13c14b4de165c847974e3 + languageName: node + linkType: hard + +"@svgr/babel-plugin-transform-svg-component@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-transform-svg-component@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/4ac00bb99a3db4ef05e4362f116a3c608ee365a2d26cf7318d8d41a4a5b30a02c80455cce0e62c65b60ed815b5d632bedabac2ccd4b56f998fadef5286e3ded4 + languageName: node + linkType: hard + +"@svgr/babel-preset@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/babel-preset@npm:8.1.0" + dependencies: + "@svgr/babel-plugin-add-jsx-attribute": "npm:8.0.0" + "@svgr/babel-plugin-remove-jsx-attribute": "npm:8.0.0" + "@svgr/babel-plugin-remove-jsx-empty-expression": "npm:8.0.0" + "@svgr/babel-plugin-replace-jsx-attribute-value": "npm:8.0.0" + "@svgr/babel-plugin-svg-dynamic-title": "npm:8.0.0" + "@svgr/babel-plugin-svg-em-dimensions": "npm:8.0.0" + "@svgr/babel-plugin-transform-react-native-svg": "npm:8.1.0" + "@svgr/babel-plugin-transform-svg-component": "npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/49367d3ad0831f79b1056871b91766246f449d4d1168623af5e283fbaefce4a01d77ab00de6b045b55e956f9aae27895823198493cd232d88d3435ea4517ffc5 + languageName: node + linkType: hard + +"@svgr/core@npm:^8.1.0": + version: 8.1.0 + resolution: "@svgr/core@npm:8.1.0" + dependencies: + "@babel/core": "npm:^7.21.3" + "@svgr/babel-preset": "npm:8.1.0" + camelcase: "npm:^6.2.0" + cosmiconfig: "npm:^8.1.3" + snake-case: "npm:^3.0.4" + checksum: 10c0/6a2f6b1bc79bce39f66f088d468985d518005fc5147ebf4f108570a933818b5951c2cb7da230ddff4b7c8028b5a672b2d33aa2acce012b8b9770073aa5a2d041 + languageName: node + linkType: hard + +"@svgr/hast-util-to-babel-ast@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/hast-util-to-babel-ast@npm:8.0.0" + dependencies: + "@babel/types": "npm:^7.21.3" + entities: "npm:^4.4.0" + checksum: 10c0/f4165b583ba9eaf6719e598977a7b3ed182f177983e55f9eb55a6a73982d81277510e9eb7ab41f255151fb9ed4edd11ac4bef95dd872f04ed64966d8c85e0f79 + languageName: node + linkType: hard + +"@svgr/plugin-jsx@npm:^8.1.0": + version: 8.1.0 + resolution: "@svgr/plugin-jsx@npm:8.1.0" + dependencies: + "@babel/core": "npm:^7.21.3" + "@svgr/babel-preset": "npm:8.1.0" + "@svgr/hast-util-to-babel-ast": "npm:8.0.0" + svg-parser: "npm:^2.0.4" + peerDependencies: + "@svgr/core": "*" + checksum: 10c0/07b4d9e00de795540bf70556fa2cc258774d01e97a12a26234c6fdf42b309beb7c10f31ee24d1a71137239347b1547b8bb5587d3a6de10669f95dcfe99cddc56 + languageName: node + linkType: hard + +"@svgr/plugin-svgo@npm:^8.1.0": + version: 8.1.0 + resolution: "@svgr/plugin-svgo@npm:8.1.0" + dependencies: + cosmiconfig: "npm:^8.1.3" + deepmerge: "npm:^4.3.1" + svgo: "npm:^3.0.2" + peerDependencies: + "@svgr/core": "*" + checksum: 10c0/bfd25460f23f1548bfb8f6f3bedd6d6972c1a4f8881bd35a4f8c115218da6e999e8f9ac0ef0ed88c4e0b93fcec37f382b94c0322f4ec2b26752a89e5cc8b9d7a + languageName: node + linkType: hard + "@tootallnate/quickjs-emscripten@npm:^0.23.0": version: 0.23.0 resolution: "@tootallnate/quickjs-emscripten@npm:0.23.0" @@ -5892,6 +6113,13 @@ __metadata: languageName: node linkType: hard +"boolbase@npm:^1.0.0": + version: 1.0.0 + resolution: "boolbase@npm:1.0.0" + checksum: 10c0/e4b53deb4f2b85c52be0e21a273f2045c7b6a6ea002b0e139c744cb6f95e9ec044439a52883b0d74dedd1ff3da55ed140cfdddfed7fb0cccbed373de5dce1bcf + languageName: node + linkType: hard + "bplist-creator@npm:0.1.0": version: 0.1.0 resolution: "bplist-creator@npm:0.1.0" @@ -6401,13 +6629,33 @@ __metadata: languageName: node linkType: hard -"color-name@npm:~1.1.4": +"color-name@npm:^1.0.0, color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 languageName: node linkType: hard +"color-string@npm:^1.9.0": + version: 1.9.1 + resolution: "color-string@npm:1.9.1" + dependencies: + color-name: "npm:^1.0.0" + simple-swizzle: "npm:^0.2.2" + checksum: 10c0/b0bfd74c03b1f837f543898b512f5ea353f71630ccdd0d66f83028d1f0924a7d4272deb278b9aef376cacf1289b522ac3fb175e99895283645a2dc3a33af2404 + languageName: node + linkType: hard + +"color@npm:^4.2.3": + version: 4.2.3 + resolution: "color@npm:4.2.3" + dependencies: + color-convert: "npm:^2.0.1" + color-string: "npm:^1.9.0" + checksum: 10c0/7fbe7cfb811054c808349de19fb380252e5e34e61d7d168ec3353e9e9aacb1802674bddc657682e4e9730c2786592a4de6f8283e7e0d3870b829bb0b7b2f6118 + languageName: node + linkType: hard + "colorette@npm:^1.0.7": version: 1.4.0 resolution: "colorette@npm:1.4.0" @@ -6776,6 +7024,23 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^8.1.3": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: "npm:^3.3.0" + js-yaml: "npm:^4.1.0" + parse-json: "npm:^5.2.0" + path-type: "npm:^4.0.0" + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/0382a9ed13208f8bfc22ca2f62b364855207dffdb73dc26e150ade78c3093f1cf56172df2dd460c8caf2afa91c0ed4ec8a88c62f8f9cd1cf423d26506aa8797a + languageName: node + linkType: hard + "cosmiconfig@npm:^9.0.0": version: 9.0.0 resolution: "cosmiconfig@npm:9.0.0" @@ -6839,6 +7104,65 @@ __metadata: languageName: node linkType: hard +"css-select@npm:^5.1.0": + version: 5.2.2 + resolution: "css-select@npm:5.2.2" + dependencies: + boolbase: "npm:^1.0.0" + css-what: "npm:^6.1.0" + domhandler: "npm:^5.0.2" + domutils: "npm:^3.0.1" + nth-check: "npm:^2.0.1" + checksum: 10c0/d79fffa97106007f2802589f3ed17b8c903f1c961c0fc28aa8a051eee0cbad394d8446223862efd4c1b40445a6034f626bb639cf2035b0bfc468544177593c99 + languageName: node + linkType: hard + +"css-tree@npm:^1.1.3": + version: 1.1.3 + resolution: "css-tree@npm:1.1.3" + dependencies: + mdn-data: "npm:2.0.14" + source-map: "npm:^0.6.1" + checksum: 10c0/499a507bfa39b8b2128f49736882c0dd636b0cd3370f2c69f4558ec86d269113286b7df469afc955de6a68b0dba00bc533e40022a73698081d600072d5d83c1c + languageName: node + linkType: hard + +"css-tree@npm:^2.3.1": + version: 2.3.1 + resolution: "css-tree@npm:2.3.1" + dependencies: + mdn-data: "npm:2.0.30" + source-map-js: "npm:^1.0.1" + checksum: 10c0/6f8c1a11d5e9b14bf02d10717fc0351b66ba12594166f65abfbd8eb8b5b490dd367f5c7721db241a3c792d935fc6751fbc09f7e1598d421477ad9fadc30f4f24 + languageName: node + linkType: hard + +"css-tree@npm:~2.2.0": + version: 2.2.1 + resolution: "css-tree@npm:2.2.1" + dependencies: + mdn-data: "npm:2.0.28" + source-map-js: "npm:^1.0.1" + checksum: 10c0/47e87b0f02f8ac22f57eceb65c58011dd142d2158128882a0bf963cf2eabb81a4ebbc2e3790c8289be7919fa8b83750c7b69272bd66772c708143b772ba3c186 + languageName: node + linkType: hard + +"css-what@npm:^6.1.0": + version: 6.2.2 + resolution: "css-what@npm:6.2.2" + checksum: 10c0/91e24c26fb977b4ccef30d7007d2668c1c10ac0154cc3f42f7304410e9594fb772aea4f30c832d2993b132ca8d99338050866476210316345ec2e7d47b248a56 + languageName: node + linkType: hard + +"csso@npm:^5.0.5": + version: 5.0.5 + resolution: "csso@npm:5.0.5" + dependencies: + css-tree: "npm:~2.2.0" + checksum: 10c0/ab4beb1e97dd7e207c10e9925405b45f15a6cd1b4880a8686ad573aa6d476aed28b4121a666cffd26c37a26179f7b54741f7c257543003bfb244d06a62ad569b + languageName: node + linkType: hard + "csstype@npm:^3.2.2": version: 3.2.3 resolution: "csstype@npm:3.2.3" @@ -6937,6 +7261,13 @@ __metadata: languageName: node linkType: hard +"decode-uri-component@npm:^0.2.2": + version: 0.2.2 + resolution: "decode-uri-component@npm:0.2.2" + checksum: 10c0/1f4fa54eb740414a816b3f6c24818fbfcabd74ac478391e9f4e2282c994127db02010ce804f3d08e38255493cfe68608b3f5c8e09fd6efc4ae46c807691f7a31 + languageName: node + linkType: hard + "dedent@npm:^0.7.0": version: 0.7.0 resolution: "dedent@npm:0.7.0" @@ -7161,6 +7492,54 @@ __metadata: languageName: node linkType: hard +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.2" + entities: "npm:^4.2.0" + checksum: 10c0/d5ae2b7110ca3746b3643d3ef60ef823f5f078667baf530cec096433f1627ec4b6fa8c072f09d079d7cda915fd2c7bc1b7b935681e9b09e591e1e15f4040b8e2 + languageName: node + linkType: hard + +"domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9 + languageName: node + linkType: hard + +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: "npm:^2.3.0" + checksum: 10c0/bba1e5932b3e196ad6862286d76adc89a0dbf0c773e5ced1eb01f9af930c50093a084eff14b8de5ea60b895c56a04d5de8bbc4930c5543d029091916770b2d2a + languageName: node + linkType: hard + +"domutils@npm:^3.0.1": + version: 3.2.2 + resolution: "domutils@npm:3.2.2" + dependencies: + dom-serializer: "npm:^2.0.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + checksum: 10c0/47938f473b987ea71cd59e59626eb8666d3aa8feba5266e45527f3b636c7883cca7e582d901531961f742c519d7514636b7973353b648762b2e3bedbf235fada + languageName: node + linkType: hard + +"dot-case@npm:^3.0.4": + version: 3.0.4 + resolution: "dot-case@npm:3.0.4" + dependencies: + no-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 10c0/5b859ea65097a7ea870e2c91b5768b72ddf7fa947223fd29e167bcdff58fe731d941c48e47a38ec8aa8e43044c8fbd15cd8fa21689a526bc34b6548197cd5b05 + languageName: node + linkType: hard + "dot-prop@npm:^5.1.0": version: 5.3.0 resolution: "dot-prop@npm:5.3.0" @@ -7269,6 +7648,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^4.2.0, entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -8233,6 +8619,13 @@ __metadata: languageName: node linkType: hard +"filter-obj@npm:^1.1.0": + version: 1.1.0 + resolution: "filter-obj@npm:1.1.0" + checksum: 10c0/071e0886b2b50238ca5026c5bbf58c26a7c1a1f720773b8c7813d16ba93d0200de977af14ac143c5ac18f666b2cfc83073f3a5fe6a4e996c49e0863d5500fccf + languageName: node + linkType: hard + "finalhandler@npm:1.1.2": version: 1.1.2 resolution: "finalhandler@npm:1.1.2" @@ -9261,6 +9654,13 @@ __metadata: languageName: node linkType: hard +"is-arrayish@npm:^0.3.1": + version: 0.3.4 + resolution: "is-arrayish@npm:0.3.4" + checksum: 10c0/1fa672a2f0bedb74154440310f616c0b6e53a95cf0625522ae050f06626d1cabd1a3d8085c882dc45c61ad0e7df2529aff122810b3b4a552880bf170d6df94e0 + languageName: node + linkType: hard + "is-async-function@npm:^2.0.0": version: 2.1.1 resolution: "is-async-function@npm:2.1.1" @@ -10936,6 +11336,15 @@ __metadata: languageName: node linkType: hard +"lower-case@npm:^2.0.2": + version: 2.0.2 + resolution: "lower-case@npm:2.0.2" + dependencies: + tslib: "npm:^2.0.3" + checksum: 10c0/3d925e090315cf7dc1caa358e0477e186ffa23947740e4314a7429b6e62d72742e0bbe7536a5ae56d19d7618ce998aba05caca53c2902bd5742fdca5fc57fd7b + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -11024,6 +11433,27 @@ __metadata: languageName: node linkType: hard +"mdn-data@npm:2.0.14": + version: 2.0.14 + resolution: "mdn-data@npm:2.0.14" + checksum: 10c0/67241f8708c1e665a061d2b042d2d243366e93e5bf1f917693007f6d55111588b952dcbfd3ea9c2d0969fb754aad81b30fdcfdcc24546495fc3b24336b28d4bd + languageName: node + linkType: hard + +"mdn-data@npm:2.0.28": + version: 2.0.28 + resolution: "mdn-data@npm:2.0.28" + checksum: 10c0/20000932bc4cd1cde9cba4e23f08cc4f816398af4c15ec81040ed25421d6bf07b5cf6b17095972577fb498988f40f4cb589e3169b9357bb436a12d8e07e5ea7b + languageName: node + linkType: hard + +"mdn-data@npm:2.0.30": + version: 2.0.30 + resolution: "mdn-data@npm:2.0.30" + checksum: 10c0/a2c472ea16cee3911ae742593715aa4c634eb3d4b9f1e6ada0902aa90df13dcbb7285d19435f3ff213ebaa3b2e0c0265c1eb0e3fb278fda7f8919f046a410cd9 + languageName: node + linkType: hard + "media-typer@npm:0.3.0": version: 0.3.0 resolution: "media-typer@npm:0.3.0" @@ -11773,7 +12203,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.7": +"nanoid@npm:^3.3.11, nanoid@npm:^3.3.7": version: 3.3.11 resolution: "nanoid@npm:3.3.11" bin: @@ -11833,6 +12263,16 @@ __metadata: languageName: node linkType: hard +"no-case@npm:^3.0.4": + version: 3.0.4 + resolution: "no-case@npm:3.0.4" + dependencies: + lower-case: "npm:^2.0.2" + tslib: "npm:^2.0.3" + checksum: 10c0/8ef545f0b3f8677c848f86ecbd42ca0ff3cd9dd71c158527b344c69ba14710d816d8489c746b6ca225e7b615108938a0bda0a54706f8c255933703ac1cf8e703 + languageName: node + linkType: hard + "nocache@npm:^3.0.1": version: 3.0.4 resolution: "nocache@npm:3.0.4" @@ -11975,6 +12415,15 @@ __metadata: languageName: node linkType: hard +"nth-check@npm:^2.0.1": + version: 2.1.1 + resolution: "nth-check@npm:2.1.1" + dependencies: + boolbase: "npm:^1.0.0" + checksum: 10c0/5fee7ff309727763689cfad844d979aedd2204a817fbaaf0e1603794a7c20db28548d7b024692f953557df6ce4a0ee4ae46cd8ebd9b36cfb300b9226b567c479 + languageName: node + linkType: hard + "nullthrows@npm:^1.1.1": version: 1.1.1 resolution: "nullthrows@npm:1.1.1" @@ -12465,6 +12914,13 @@ __metadata: languageName: node linkType: hard +"path-dirname@npm:^1.0.2": + version: 1.0.2 + resolution: "path-dirname@npm:1.0.2" + checksum: 10c0/71e59be2bada7c91f62b976245fd421b7cb01fde3207fe53a82d8880621ad04fd8b434e628c9cf4e796259fc168a107d77cd56837725267c5b2c58cefe2c4e1b + languageName: node + linkType: hard + "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" @@ -12555,7 +13011,7 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.1.1": +"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 @@ -12822,6 +13278,18 @@ __metadata: languageName: node linkType: hard +"query-string@npm:^7.1.3": + version: 7.1.3 + resolution: "query-string@npm:7.1.3" + dependencies: + decode-uri-component: "npm:^0.2.2" + filter-obj: "npm:^1.1.0" + split-on-first: "npm:^1.0.0" + strict-uri-encode: "npm:^2.0.0" + checksum: 10c0/a896c08e9e0d4f8ffd89a572d11f668c8d0f7df9c27c6f49b92ab31366d3ba0e9c331b9a620ee747893436cd1f2f821a6327e2bc9776bde2402ac6c270b801b2 + languageName: node + linkType: hard + "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -12888,6 +13356,15 @@ __metadata: languageName: node linkType: hard +"react-freeze@npm:^1.0.0": + version: 1.0.4 + resolution: "react-freeze@npm:1.0.4" + peerDependencies: + react: ">=17.0.0" + checksum: 10c0/8f51257c261bfefff86f618e958683536248f708019632d309ee5ebdd52f25d3c130660d06fb6f0f4fdef79f00f8ec7177233a872c2321f7d46b7e77ccc522a1 + languageName: node + linkType: hard + "react-is@npm:^16.13.1": version: 16.13.1 resolution: "react-is@npm:16.13.1" @@ -12902,6 +13379,13 @@ __metadata: languageName: node linkType: hard +"react-is@npm:^19.1.0": + version: 19.2.5 + resolution: "react-is@npm:19.2.5" + checksum: 10c0/58c28ab2f7f868f9836c728fa164a16dcf20246ab84a3ae6a09e617b0e4d9bbb3acdddfdc40452f0134d27b121d3359227602a050c0be554cb20069cb52a67f4 + languageName: node + linkType: hard + "react-native-builder-bob@npm:^0.40.18": version: 0.40.18 resolution: "react-native-builder-bob@npm:0.40.18" @@ -12948,12 +13432,17 @@ __metadata: "@react-native/metro-config": "npm:0.84.1" "@react-native/new-app-screen": "npm:0.84.1" "@react-native/typescript-config": "npm:0.84.1" + "@react-navigation/native": "npm:^7.2.2" + "@react-navigation/native-stack": "npm:^7.14.12" "@types/react": "npm:^19.2.0" react: "npm:19.2.3" react-native: "npm:0.84.1" react-native-builder-bob: "npm:^0.40.18" react-native-monorepo-config: "npm:^0.3.3" react-native-safe-area-context: "npm:^5.5.2" + react-native-screens: "npm:^4.24.0" + react-native-svg: "npm:^15.15.4" + react-native-svg-transformer: "npm:^1.5.3" languageName: unknown linkType: soft @@ -13108,6 +13597,48 @@ __metadata: languageName: node linkType: hard +"react-native-screens@npm:^4.24.0": + version: 4.24.0 + resolution: "react-native-screens@npm:4.24.0" + dependencies: + react-freeze: "npm:^1.0.0" + warn-once: "npm:^0.1.0" + peerDependencies: + react: "*" + react-native: "*" + checksum: 10c0/49299e694ed20cf5a8c0f86702eb77df03f5b7353d9b73e7415bb593ac5ff3aa4dfe76b1e9d8efb0fd926917e507f02f13e0a8791c8833910080454b66d99943 + languageName: node + linkType: hard + +"react-native-svg-transformer@npm:^1.5.3": + version: 1.5.3 + resolution: "react-native-svg-transformer@npm:1.5.3" + dependencies: + "@svgr/core": "npm:^8.1.0" + "@svgr/plugin-jsx": "npm:^8.1.0" + "@svgr/plugin-svgo": "npm:^8.1.0" + path-dirname: "npm:^1.0.2" + peerDependencies: + react-native: ">=0.59.0" + react-native-svg: ">=12.0.0" + checksum: 10c0/0e2dd028c7e691a8db6f775c8142e07bd54f3f86473794a5512fbe8303d591f20eb35d7422ea7995347c8ea8776e32552be303499860699dc9325bd54ff1410f + languageName: node + linkType: hard + +"react-native-svg@npm:^15.15.4": + version: 15.15.4 + resolution: "react-native-svg@npm:15.15.4" + dependencies: + css-select: "npm:^5.1.0" + css-tree: "npm:^1.1.3" + warn-once: "npm:0.1.1" + peerDependencies: + react: "*" + react-native: "*" + checksum: 10c0/1fb8e3ac9d45a4db74731a006cd32f883051844f361974dff49e1a4142aa7c1a0d87e0b04fff06a1932ca53940bcfb94e45e01a845eb451d4659fbf07092629e + languageName: node + linkType: hard + "react-native-web@npm:~0.19.13": version: 0.19.13 resolution: "react-native-web@npm:0.19.13" @@ -13694,6 +14225,13 @@ __metadata: languageName: node linkType: hard +"sax@npm:^1.5.0": + version: 1.6.0 + resolution: "sax@npm:1.6.0" + checksum: 10c0/e5593f4a91eb25761a688c4d96902e4e95a0dd6017bc65146b6f21236e3d715cf893333b76bc758923c9574c2fb5a7a76c3a81e96ea15432f2624f906c027c1e + languageName: node + linkType: hard + "scheduler@npm:0.26.0": version: 0.26.0 resolution: "scheduler@npm:0.26.0" @@ -13863,6 +14401,13 @@ __metadata: languageName: node linkType: hard +"sf-symbols-typescript@npm:^2.1.0": + version: 2.2.0 + resolution: "sf-symbols-typescript@npm:2.2.0" + checksum: 10c0/3f3bbf33aaad19e619d6f169899b39e9fe9c5fd21f0d6d511100e36887606ad349109ddc6ff82933f2b8cbf437dd7105c2ae6b0059b291dc47f143b30c2074cc + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -13959,6 +14504,15 @@ __metadata: languageName: node linkType: hard +"simple-swizzle@npm:^0.2.2": + version: 0.2.4 + resolution: "simple-swizzle@npm:0.2.4" + dependencies: + is-arrayish: "npm:^0.3.1" + checksum: 10c0/846c3fdd1325318d5c71295cfbb99bfc9edc4c8dffdda5e6e9efe30482bbcd32cf360fc2806f46ac43ff7d09bcfaff20337bb79f826f0e6a8e366efd3cdd7868 + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -14012,6 +14566,16 @@ __metadata: languageName: node linkType: hard +"snake-case@npm:^3.0.4": + version: 3.0.4 + resolution: "snake-case@npm:3.0.4" + dependencies: + dot-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 10c0/ab19a913969f58f4474fe9f6e8a026c8a2142a01f40b52b79368068343177f818cdfef0b0c6b9558f298782441d5ca8ed5932eb57822439fad791d866e62cecd + languageName: node + linkType: hard + "socks-proxy-agent@npm:^8.0.3, socks-proxy-agent@npm:^8.0.5": version: 8.0.5 resolution: "socks-proxy-agent@npm:8.0.5" @@ -14033,7 +14597,7 @@ __metadata: languageName: node linkType: hard -"source-map-js@npm:^1.2.1": +"source-map-js@npm:^1.0.1, source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf @@ -14108,6 +14672,13 @@ __metadata: languageName: node linkType: hard +"split-on-first@npm:^1.0.0": + version: 1.1.0 + resolution: "split-on-first@npm:1.1.0" + checksum: 10c0/56df8344f5a5de8521898a5c090023df1d8b8c75be6228f56c52491e0fc1617a5236f2ac3a066adb67a73231eac216ccea7b5b4a2423a543c277cb2f48d24c29 + languageName: node + linkType: hard + "split2@npm:^4.0.0": version: 4.2.0 resolution: "split2@npm:4.2.0" @@ -14201,6 +14772,13 @@ __metadata: languageName: node linkType: hard +"strict-uri-encode@npm:^2.0.0": + version: 2.0.0 + resolution: "strict-uri-encode@npm:2.0.0" + checksum: 10c0/010cbc78da0e2cf833b0f5dc769e21ae74cdc5d5f5bd555f14a4a4876c8ad2c85ab8b5bdf9a722dc71a11dcd3184085e1c3c0bd50ec6bb85fffc0f28cf82597d + languageName: node + linkType: hard + "string-length@npm:^4.0.1": version: 4.0.2 resolution: "string-length@npm:4.0.2" @@ -14448,6 +15026,30 @@ __metadata: languageName: node linkType: hard +"svg-parser@npm:^2.0.4": + version: 2.0.4 + resolution: "svg-parser@npm:2.0.4" + checksum: 10c0/02f6cb155dd7b63ebc2f44f36365bc294543bebb81b614b7628f1af3c54ab64f7e1cec20f06e252bf95bdde78441ae295a412c68ad1678f16a6907d924512b7a + languageName: node + linkType: hard + +"svgo@npm:^3.0.2": + version: 3.3.3 + resolution: "svgo@npm:3.3.3" + dependencies: + commander: "npm:^7.2.0" + css-select: "npm:^5.1.0" + css-tree: "npm:^2.3.1" + css-what: "npm:^6.1.0" + csso: "npm:^5.0.5" + picocolors: "npm:^1.0.0" + sax: "npm:^1.5.0" + bin: + svgo: ./bin/svgo + checksum: 10c0/06568c6b0430f96748c557f0b17dc7de79b19fa16d13d7523527ede0ec727fc6d8e6a10e13ff106dc4372d2e6063a1dca7c455c495efb1b83857480425f9b965 + languageName: node + linkType: hard + "synckit@npm:^0.11.7": version: 0.11.11 resolution: "synckit@npm:0.11.11" @@ -14589,7 +15191,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1, tslib@npm:^2.1.0": +"tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 @@ -14987,6 +15589,24 @@ __metadata: languageName: node linkType: hard +"use-latest-callback@npm:^0.2.4": + version: 0.2.6 + resolution: "use-latest-callback@npm:0.2.6" + peerDependencies: + react: ">=16.8" + checksum: 10c0/6523747b2d76f12a91cf80a3cd9803449571e9defa8db69e9a03b8199b211127d88c038063714fe31d3c2e63ca51a491bd05f4e34203795a1c692a5a44416610 + languageName: node + linkType: hard + +"use-sync-external-store@npm:^1.5.0": + version: 1.6.0 + resolution: "use-sync-external-store@npm:1.6.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/35e1179f872a53227bdf8a827f7911da4c37c0f4091c29b76b1e32473d1670ebe7bcd880b808b7549ba9a5605c233350f800ffab963ee4a4ee346ee983b6019b + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" @@ -15061,6 +15681,13 @@ __metadata: languageName: node linkType: hard +"warn-once@npm:0.1.1, warn-once@npm:^0.1.0, warn-once@npm:^0.1.1": + version: 0.1.1 + resolution: "warn-once@npm:0.1.1" + checksum: 10c0/f531e7b2382124f51e6d8f97b8c865246db8ab6ff4e53257a2d274e0f02b97d7201eb35db481843dc155815e154ad7afb53b01c4d4db15fb5aa073562496aff7 + languageName: node + linkType: hard + "wcwidth@npm:^1.0.1": version: 1.0.1 resolution: "wcwidth@npm:1.0.1"