rn-shiki 0.0.37-34 → 0.0.37-36

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rn-shiki",
3
3
  "type": "module",
4
- "version": "0.0.37-34",
4
+ "version": "0.0.37-36",
5
5
  "description": "Shiki syntax highlighter for React Native.",
6
6
  "author": "Ryan Skinner <hello@ryanskinner.com>",
7
7
  "license": "MIT",
@@ -1,131 +1,64 @@
1
- import type { ColorValue, StyleProp, TextStyle } from 'react-native'
2
- import type { ThemedToken, ThemeInput, ThemeRegistration } from 'shiki'
3
- import type { SyntaxHighlighterProps } from 'src/types/shiki'
4
- import React, { useMemo } from 'react'
5
- import { Platform, ScrollView, StyleSheet, Text, View } from 'react-native'
6
- import { useSyntaxHighlighter } from '../../hooks/useSyntaxHighlighter'
7
- import { getRNStylesFromShikiStyle } from '../../utils/style-transformer'
1
+ // src/utils/getRNStylesFromShikiStyle.ts
8
2
 
9
- const monospaceFont = Platform.select({
10
- ios: 'Menlo',
11
- android: 'monospace',
12
- default: 'monospace',
13
- })
3
+ import type { TextStyle } from 'react-native'
4
+ import type { ThemeRegistration } from 'shiki'
14
5
 
15
- interface TokenStyle extends Omit<TextStyle, 'color' | 'fontWeight'> {
16
- color?: ColorValue
17
- fontStyle?: 'normal' | 'italic'
18
- fontWeight?: FontWeight
19
- fontFamily?: string
6
+ export interface HighlighterStyleSheet {
7
+ [key: string]: TextStyle
20
8
  }
21
9
 
22
- type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'
23
-
24
- function getThemeRegistration(theme: ThemeInput): ThemeRegistration {
25
- if ('default' in theme) {
26
- return theme.default
27
- }
28
- return theme as ThemeRegistration
10
+ function normalizeColor(color: string | undefined): string {
11
+ if (!color)
12
+ return 'transparent'
13
+ return color
29
14
  }
30
15
 
31
- const baseStyles = StyleSheet.create({
32
- scrollView: {
33
- flex: 1,
34
- minHeight: 20,
35
- backgroundColor: '#1e1e1e',
36
- },
37
- contentContainer: {
38
- flexGrow: 1,
39
- minWidth: '100%',
40
- },
41
- codeContainer: {
42
- paddingVertical: 8,
43
- minWidth: '100%',
44
- },
45
- lineContainer: {
46
- flexDirection: 'row',
47
- minWidth: '100%',
48
- paddingHorizontal: 16,
49
- paddingVertical: 1,
50
- },
51
- line: {
52
- flexDirection: 'row',
53
- flexWrap: 'wrap',
54
- flex: 1,
55
- },
56
- token: {
57
- fontFamily: monospaceFont,
58
- fontSize: 14,
59
- color: '#d4d4d4',
60
- },
61
- })
62
-
63
- const SyntaxHighlighter: React.FC<SyntaxHighlighterProps> = ({ text, language, languageId, theme, fontSize = 14 }) => {
64
- const stylesheet = useMemo(() => {
65
- const themeRegistration = getThemeRegistration(theme)
66
- const styles = getRNStylesFromShikiStyle(themeRegistration)
16
+ export function getRNStylesFromShikiStyle(theme: ThemeRegistration): HighlighterStyleSheet {
17
+ if (!theme)
18
+ return {}
67
19
 
68
- return StyleSheet.create({
69
- ...styles,
20
+ try {
21
+ const styles: HighlighterStyleSheet = {
70
22
  editor: {
71
- backgroundColor: themeRegistration.colors?.['editor.background'] || '#1e1e1e',
23
+ backgroundColor: normalizeColor(theme.colors?.['editor.background']),
72
24
  },
73
- token: {
74
- ...baseStyles.token,
75
- fontSize,
76
- color: themeRegistration.colors?.['editor.foreground'] || '#d4d4d4',
25
+ base: {
26
+ color: normalizeColor(theme.colors?.['editor.foreground']),
77
27
  },
78
- lineNumber: {
79
- width: 40,
80
- paddingRight: 16,
81
- textAlign: 'right',
82
- color: themeRegistration.colors?.['editorLineNumber.foreground'] || '#858585',
83
- fontFamily: monospaceFont,
84
- fontSize,
85
- opacity: 0.5,
86
- },
87
- })
88
- }, [theme, fontSize])
89
-
90
- const { tokens } = useSyntaxHighlighter({
91
- text,
92
- language,
93
- languageId,
94
- theme,
95
- })
28
+ }
96
29
 
97
- const renderToken = (token: ThemedToken, index: number) => {
98
- const styles: StyleProp<TokenStyle>[] = [stylesheet.token]
30
+ if (theme.tokenColors) {
31
+ theme.tokenColors.forEach((token) => {
32
+ if (!token.settings)
33
+ return
99
34
 
100
- if (token.color) {
101
- styles.push({ color: token.color })
102
- }
35
+ const style: TextStyle = {}
36
+ if (token.settings.foreground) {
37
+ style.color = token.settings.foreground
38
+ }
39
+ if (token.settings.background) {
40
+ style.backgroundColor = token.settings.background
41
+ }
42
+ if (token.settings.fontStyle) {
43
+ style.fontStyle = token.settings.fontStyle.includes('italic') ? 'italic' : 'normal'
44
+ style.fontWeight = token.settings.fontStyle.includes('bold') ? 'bold' : 'normal'
45
+ }
103
46
 
104
- if (token.fontStyle) {
105
- styles.push({
106
- fontStyle: token.fontStyle as unknown as 'normal' | 'italic',
107
- fontWeight: (token.fontStyle as unknown as string).includes('bold') ? 'bold' : 'normal',
47
+ const scopes = Array.isArray(token.scope) ? token.scope : [token.scope]
48
+ scopes.forEach((scope) => {
49
+ if (scope) {
50
+ styles[scope] = style
51
+ }
52
+ })
108
53
  })
109
54
  }
110
55
 
111
- return (
112
- <Text key={index} style={styles}>
113
- {token.content.replace(/ /g, '\u00A0')}
114
- </Text>
115
- )
56
+ return styles
57
+ }
58
+ catch (error) {
59
+ return {
60
+ editor: { backgroundColor: '#1e1e1e' },
61
+ base: { color: '#d4d4d4' },
62
+ }
116
63
  }
117
-
118
- const renderLine = (line: ThemedToken[], lineIndex: number) => (
119
- <View key={lineIndex} style={baseStyles.lineContainer}>
120
- <View style={baseStyles.line}>{line.map((token, tokenIndex) => renderToken(token, tokenIndex))}</View>
121
- </View>
122
- )
123
-
124
- return (
125
- <ScrollView horizontal showsHorizontalScrollIndicator={Platform.OS !== 'web'} style={[baseStyles.scrollView, stylesheet.editor]} contentContainerStyle={baseStyles.contentContainer}>
126
- <View style={baseStyles.codeContainer}>{tokens.map((line, index) => renderLine(line, index))}</View>
127
- </ScrollView>
128
- )
129
64
  }
130
-
131
- export default SyntaxHighlighter
@@ -20,22 +20,17 @@ export function useSyntaxHighlighter({ text, language, languageId, theme }: Synt
20
20
  }
21
21
 
22
22
  try {
23
- // First create the highlighter
24
23
  const highlighter = await createHighlighter({
25
24
  langs: [language],
26
25
  themes: [theme],
27
26
  })
28
27
 
29
- // Get resolved theme name
30
- const themeResolved = highlighter.getLoadedThemes()?.[0]
31
- if (!themeResolved) {
32
- throw new Error('Failed to resolve theme')
33
- }
34
-
35
- // Use resolved theme for tokenization
28
+ // The highlighter will resolve the theme internally
29
+ // We can use the theme directly here as highlighter.codeToTokens
30
+ // handles the ThemeInput resolution
36
31
  const result = highlighter.codeToTokens(text, {
37
32
  lang: languageId,
38
- theme: themeResolved,
33
+ theme,
39
34
  }) as TokensResult
40
35
 
41
36
  if (mounted && result.tokens) {
@@ -14,7 +14,7 @@ async function initializeHighlighter(langs: LanguageInput[], themes: ThemeInput[
14
14
  return await createHighlighterCore({
15
15
  langs,
16
16
  themes,
17
- engine, // Pass the configured engine
17
+ engine,
18
18
  })
19
19
  }
20
20
  catch (err) {
@@ -1,12 +1,14 @@
1
1
  import type { TextStyle } from 'react-native'
2
2
  import type { ThemeRegistration } from 'shiki'
3
3
 
4
+ // src/utils/getRNStylesFromShikiStyle.
5
+
6
+ export type ReactStyle = Record<string, TextStyle>
7
+
4
8
  export interface HighlighterStyleSheet {
5
9
  [key: string]: TextStyle
6
10
  }
7
11
 
8
- export type ReactStyle = Record<string, TextStyle>
9
-
10
12
  function normalizeColor(color: string | undefined): string {
11
13
  if (!color)
12
14
  return 'transparent'