rn-shiki 0.0.37-28 → 0.0.37-29

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-28",
4
+ "version": "0.0.37-29",
5
5
  "description": "Shiki syntax highlighter for React Native.",
6
6
  "author": "Ryan Skinner <hello@ryanskinner.com>",
7
7
  "license": "MIT",
@@ -1,5 +1,5 @@
1
1
  import type { ColorValue, StyleProp, TextStyle } from 'react-native'
2
- import type { ThemeInput, ThemeRegistration } from 'shiki'
2
+ import type { ThemedToken, ThemeInput, ThemeRegistration } from 'shiki'
3
3
  import type { SyntaxHighlighterProps } from 'src/types/shiki'
4
4
  import React, { useMemo } from 'react'
5
5
  import { Platform, ScrollView, StyleSheet, Text, View } from 'react-native'
@@ -19,13 +19,8 @@ interface TokenStyle extends Omit<TextStyle, 'color' | 'fontWeight'> {
19
19
  fontFamily?: string
20
20
  }
21
21
 
22
- interface Styles {
23
- [key: string]: TokenStyle
24
- }
25
-
26
22
  type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'
27
23
 
28
- // Helper function to extract theme registration from Shiki theme input
29
24
  function getThemeRegistration(theme: ThemeInput): ThemeRegistration {
30
25
  if ('default' in theme) {
31
26
  return theme.default
@@ -37,19 +32,27 @@ const baseStyles = StyleSheet.create({
37
32
  scrollView: {
38
33
  flex: 1,
39
34
  minHeight: 20,
35
+ backgroundColor: '#1e1e1e',
40
36
  },
41
37
  lineContainer: {
42
38
  flexDirection: 'row',
43
39
  flexWrap: 'wrap',
40
+ minWidth: '100%',
44
41
  paddingHorizontal: 16,
45
- paddingVertical: 8,
42
+ paddingVertical: 4,
46
43
  },
47
44
  token: {
48
45
  fontFamily: monospaceFont,
49
46
  fontSize: 14,
47
+ color: '#d4d4d4',
50
48
  },
51
49
  container: {
52
- flex: 1,
50
+ paddingVertical: 8,
51
+ },
52
+ line: {
53
+ flexDirection: 'row',
54
+ flexWrap: 'wrap',
55
+ width: '100%',
53
56
  },
54
57
  })
55
58
 
@@ -57,7 +60,8 @@ const SyntaxHighlighter: React.FC<SyntaxHighlighterProps> = ({ text, language, l
57
60
  const stylesheet = useMemo(() => {
58
61
  const themeRegistration = getThemeRegistration(theme)
59
62
  const styles = getRNStylesFromShikiStyle(themeRegistration)
60
- return StyleSheet.create<Styles>({
63
+
64
+ return StyleSheet.create({
61
65
  ...styles,
62
66
  editor: {
63
67
  backgroundColor: themeRegistration.colors?.['editor.background'] || '#1e1e1e',
@@ -77,51 +81,41 @@ const SyntaxHighlighter: React.FC<SyntaxHighlighterProps> = ({ text, language, l
77
81
  theme,
78
82
  })
79
83
 
80
- const renderToken = (token: any, index: number, lineIndex: number) => {
84
+ const renderToken = (token: ThemedToken, index: number) => {
81
85
  const styles: StyleProp<TokenStyle>[] = [stylesheet.token]
82
86
 
83
- // Add token-specific styles from stylesheet based on scope
84
- const tokenScopes = Array.isArray(token.scope) ? token.scope : [token.scope]
85
- tokenScopes.forEach((scope: string) => {
86
- if (stylesheet[scope]) {
87
- styles.push(stylesheet[scope])
88
- }
89
- })
90
-
91
- // Add token-specific styles from the token itself
92
- const tokenStyles: TokenStyle = {}
87
+ // Always apply the token color if it exists
93
88
  if (token.color) {
94
- tokenStyles.color = token.color
95
- }
96
- if (token.fontStyle === 'italic') {
97
- tokenStyles.fontStyle = 'italic'
98
- }
99
- if (token.fontWeight === 'bold') {
100
- tokenStyles.fontWeight = 'bold'
89
+ styles.push({ color: token.color })
101
90
  }
102
91
 
103
- if (Object.keys(tokenStyles).length > 0) {
104
- styles.push(tokenStyles)
92
+ // Add font styles
93
+ if (token.fontStyle) {
94
+ styles.push({
95
+ // fontStyle: token.fontStyle.includes('italic') ? 'italic' : 'normal',
96
+ // fontWeight: token.fontStyle.includes('bold') ? 'bold' : 'normal',
97
+ fontStyle: token.fontStyle as unknown as 'normal' | 'italic',
98
+ fontWeight: (token.fontStyle as unknown as string).includes('bold') ? 'bold' : 'normal',
99
+ })
105
100
  }
106
101
 
107
- const finalStyle = StyleSheet.flatten(styles)
108
-
109
102
  return (
110
- <Text key={`${lineIndex}-${index}`} style={finalStyle}>
103
+ <Text key={index} style={styles}>
111
104
  {token.content.replace(/ /g, '\u00A0')}
112
105
  </Text>
113
106
  )
114
107
  }
115
108
 
116
- const renderLine = (line: any[], lineIndex: number) => (
117
- <View key={lineIndex} style={baseStyles.lineContainer}>
118
- {line.map((token, tokenIndex) => renderToken(token, tokenIndex, lineIndex))}
109
+ const renderLine = (line: ThemedToken[], lineIndex: number) => (
110
+ <View key={lineIndex} style={baseStyles.line}>
111
+ {line.map((token, tokenIndex) => renderToken(token, tokenIndex))}
112
+ <Text>{'\n'}</Text>
119
113
  </View>
120
114
  )
121
115
 
122
116
  return (
123
117
  <ScrollView horizontal showsHorizontalScrollIndicator={Platform.OS !== 'web'} style={[baseStyles.scrollView, stylesheet.editor]} contentContainerStyle={baseStyles.container}>
124
- {tokens.map((line, index) => renderLine(line, index))}
118
+ <View>{tokens.map((line, index) => renderLine(line, index))}</View>
125
119
  </ScrollView>
126
120
  )
127
121
  }
@@ -7,85 +7,12 @@ export interface HighlighterStyleSheet {
7
7
 
8
8
  export type ReactStyle = Record<string, TextStyle>
9
9
 
10
- function hexToRgb(hex: string): { r: number, g: number, b: number } | null {
11
- // Remove # if present
12
- hex = hex.replace(/^#/, '')
13
-
14
- // Handle both 3 and 6 digit hex
15
- if (hex.length === 3) {
16
- hex = `${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}`
17
- }
18
-
19
- const result = /^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
20
- return result
21
- ? {
22
- r: Number.parseInt(result[1]!, 16),
23
- g: Number.parseInt(result[2]!, 16),
24
- b: Number.parseInt(result[3]!, 16),
25
- }
26
- : null
27
- }
28
-
29
10
  function normalizeColor(color: string | undefined): string {
30
11
  if (!color)
31
12
  return 'transparent'
32
-
33
- // Handle hex colors
34
- if (color.startsWith('#')) {
35
- const rgb = hexToRgb(color)
36
- if (rgb) {
37
- return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`
38
- }
39
- }
40
-
41
13
  return color
42
14
  }
43
15
 
44
- export function convertTokenColorsToReactStyle(tokenColors: ThemeRegistration['tokenColors']): ReactStyle {
45
- if (!tokenColors)
46
- return {}
47
-
48
- const styleMap: ReactStyle = {}
49
-
50
- tokenColors.forEach((token) => {
51
- if (!token.settings)
52
- return
53
-
54
- // Handle global theme settings
55
- if (!token.scope) {
56
- styleMap.default = {
57
- color: normalizeColor(token.settings.foreground),
58
- backgroundColor: normalizeColor(token.settings.background),
59
- }
60
- return
61
- }
62
-
63
- const scopes = Array.isArray(token.scope) ? token.scope : [token.scope]
64
- const style: TextStyle = {}
65
-
66
- if (token.settings.foreground) {
67
- style.color = normalizeColor(token.settings.foreground)
68
- }
69
- if (token.settings.background) {
70
- style.backgroundColor = normalizeColor(token.settings.background)
71
- }
72
- if (token.settings.fontStyle) {
73
- if (token.settings.fontStyle.includes('italic')) {
74
- style.fontStyle = 'italic'
75
- }
76
- if (token.settings.fontStyle.includes('bold')) {
77
- style.fontWeight = 'bold'
78
- }
79
- }
80
-
81
- scopes.forEach((scope) => {
82
- styleMap[scope] = { ...(styleMap[scope] || {}), ...style }
83
- })
84
- })
85
-
86
- return styleMap
87
- }
88
-
89
16
  export function getRNStylesFromShikiStyle(theme: ThemeRegistration): HighlighterStyleSheet {
90
17
  if (!theme)
91
18
  return {}
@@ -100,15 +27,35 @@ export function getRNStylesFromShikiStyle(theme: ThemeRegistration): Highlighter
100
27
  },
101
28
  }
102
29
 
103
- // Process token colors
104
30
  if (theme.tokenColors) {
105
- const tokenStyles = convertTokenColorsToReactStyle(theme.tokenColors)
106
- Object.assign(styles, tokenStyles)
31
+ theme.tokenColors.forEach((token) => {
32
+ if (!token.settings)
33
+ return
34
+
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
+ }
46
+
47
+ const scopes = Array.isArray(token.scope) ? token.scope : [token.scope]
48
+ scopes.forEach((scope) => {
49
+ if (scope) {
50
+ styles[scope] = style
51
+ }
52
+ })
53
+ })
107
54
  }
108
55
 
109
56
  return styles
110
57
  }
111
- catch {
58
+ catch (error) {
112
59
  return {
113
60
  editor: { backgroundColor: '#1e1e1e' },
114
61
  base: { color: '#d4d4d4' },