@terreno/ui 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,154 @@
1
+ import type React from "react";
2
+ import {useMemo, useRef} from "react";
3
+ import {Platform, Pressable, Text as RNText, TextInput, View} from "react-native";
4
+
5
+ import {Box} from "./Box";
6
+ import type {ErrorTextProps, HelperTextProps} from "./Common";
7
+ import {FieldError, FieldHelperText, FieldTitle} from "./fieldElements";
8
+ import {MarkdownView} from "./MarkdownView";
9
+ import {Text} from "./Text";
10
+ import {useTheme} from "./Theme";
11
+
12
+ interface MarkdownEditorFieldProps extends HelperTextProps, ErrorTextProps {
13
+ title?: string;
14
+ value?: string;
15
+ onChange: (text: string) => void;
16
+ placeholder?: string;
17
+ disabled?: boolean;
18
+ testID?: string;
19
+ }
20
+
21
+ interface ToolbarButton {
22
+ label: string;
23
+ insert: (value: string) => string;
24
+ }
25
+
26
+ const TOOLBAR_BUTTONS: ToolbarButton[] = [
27
+ {insert: (v) => `${v}**text**`, label: "B"},
28
+ {insert: (v) => `${v}_text_`, label: "I"},
29
+ {insert: (v) => `${v}~~text~~`, label: "~"},
30
+ {insert: (v) => `${v}\`code\``, label: "<>"},
31
+ {insert: (v) => (v ? `${v}\n# text` : "# text"), label: "H1"},
32
+ {insert: (v) => (v ? `${v}\n## text` : "## text"), label: "H2"},
33
+ {insert: (v) => (v ? `${v}\n- item` : "- item"), label: "•"},
34
+ {insert: (v) => (v ? `${v}\n> text` : "> text"), label: ">"},
35
+ {insert: (v) => `${v}[text](url)`, label: "🔗"},
36
+ ];
37
+
38
+ export const MarkdownEditorField: React.FC<MarkdownEditorFieldProps> = ({
39
+ title,
40
+ value = "",
41
+ onChange,
42
+ placeholder,
43
+ disabled,
44
+ errorText,
45
+ helperText,
46
+ testID,
47
+ }) => {
48
+ const {theme} = useTheme();
49
+ const isWeb = Platform.OS === "web";
50
+ const inputRef = useRef<TextInput>(null);
51
+
52
+ const monoFont = useMemo(
53
+ () => (isWeb ? "monospace" : Platform.select({android: "monospace", ios: "Menlo"})),
54
+ [isWeb]
55
+ );
56
+
57
+ return (
58
+ <View testID={testID}>
59
+ {title && <FieldTitle text={title} />}
60
+ <Box
61
+ border={errorText ? "error" : "default"}
62
+ direction={isWeb ? "row" : "column"}
63
+ gap={0}
64
+ overflow="hidden"
65
+ rounding="md"
66
+ >
67
+ <View style={{flex: 1, minHeight: 200}}>
68
+ <TextInput
69
+ editable={!disabled}
70
+ multiline
71
+ onChangeText={onChange}
72
+ placeholder={placeholder ?? "Enter markdown..."}
73
+ placeholderTextColor={theme.text.secondaryDark}
74
+ ref={inputRef}
75
+ style={{
76
+ backgroundColor: theme.surface.base,
77
+ borderBottomWidth: isWeb ? 0 : 1,
78
+ borderColor: theme.border.default,
79
+ borderRightWidth: isWeb ? 1 : 0,
80
+ color: theme.text.primary,
81
+ flex: 1,
82
+ fontFamily: monoFont,
83
+ fontSize: 14,
84
+ minHeight: 200,
85
+ padding: 12,
86
+ textAlignVertical: "top",
87
+ }}
88
+ testID={testID ? `${testID}-input` : undefined}
89
+ value={value}
90
+ />
91
+ {!disabled && (
92
+ <View
93
+ style={{
94
+ backgroundColor: theme.surface.neutralLight,
95
+ borderColor: theme.border.default,
96
+ borderTopWidth: 1,
97
+ flexDirection: "row",
98
+ flexWrap: "wrap",
99
+ gap: 2,
100
+ paddingHorizontal: 4,
101
+ paddingVertical: 3,
102
+ }}
103
+ >
104
+ {TOOLBAR_BUTTONS.map((button) => (
105
+ <Pressable
106
+ key={button.label}
107
+ onPress={() => onChange(button.insert(value))}
108
+ style={({pressed}) => ({
109
+ alignItems: "center",
110
+ backgroundColor: pressed ? theme.border.default : "transparent",
111
+ borderColor: theme.border.default,
112
+ borderRadius: 3,
113
+ borderWidth: 1,
114
+ justifyContent: "center",
115
+ minHeight: 24,
116
+ minWidth: 28,
117
+ paddingHorizontal: 5,
118
+ paddingVertical: 3,
119
+ })}
120
+ >
121
+ <RNText
122
+ style={{
123
+ color: theme.text.primary,
124
+ fontFamily: monoFont,
125
+ fontSize: 12,
126
+ fontWeight: button.label === "B" ? "700" : "400",
127
+ lineHeight: 14,
128
+ textAlign: "center",
129
+ }}
130
+ >
131
+ {button.label}
132
+ </RNText>
133
+ </Pressable>
134
+ ))}
135
+ </View>
136
+ )}
137
+ </View>
138
+ <View style={{flex: 1, minHeight: 200}}>
139
+ <Box color="base" padding={3} style={{flex: 1, minHeight: 200}}>
140
+ {value ? (
141
+ <MarkdownView>{value}</MarkdownView>
142
+ ) : (
143
+ <Text color="secondaryDark" size="sm">
144
+ Preview
145
+ </Text>
146
+ )}
147
+ </Box>
148
+ </View>
149
+ </Box>
150
+ {errorText && <FieldError text={errorText} />}
151
+ {helperText && <FieldHelperText text={helperText} />}
152
+ </View>
153
+ );
154
+ };
@@ -48,10 +48,43 @@ export const MarkdownView: React.FC<{children: React.ReactNode; inverted?: boole
48
48
  "text-regular": Nunito_400Regular,
49
49
  });
50
50
 
51
+ const monoFont = isWeb ? "monospace" : Platform.select({android: "monospace", ios: "Menlo"});
52
+
51
53
  return (
52
54
  <Markdown
53
55
  style={{
54
56
  body: {fontFamily: "text", ...color},
57
+ code_block: {
58
+ backgroundColor: theme.surface.neutralLight,
59
+ borderColor: theme.border.default,
60
+ borderRadius: 4,
61
+ borderWidth: 1,
62
+ fontFamily: monoFont,
63
+ fontSize: 13,
64
+ padding: 8,
65
+ ...color,
66
+ },
67
+ code_inline: {
68
+ backgroundColor: theme.surface.neutralLight,
69
+ borderColor: theme.border.default,
70
+ borderRadius: 3,
71
+ borderWidth: 1,
72
+ fontFamily: monoFont,
73
+ fontSize: 13,
74
+ paddingHorizontal: 4,
75
+ paddingVertical: 1,
76
+ ...color,
77
+ },
78
+ fence: {
79
+ backgroundColor: theme.surface.neutralLight,
80
+ borderColor: theme.border.default,
81
+ borderRadius: 4,
82
+ borderWidth: 1,
83
+ fontFamily: monoFont,
84
+ fontSize: 13,
85
+ padding: 8,
86
+ ...color,
87
+ },
55
88
  heading1: {fontFamily: "heading-bold", fontSize: sizes.xl, ...color},
56
89
  heading2: {fontFamily: "heading-bold", fontSize: sizes.lg, ...color},
57
90
  heading3: {fontFamily: "heading-bold", fontSize: sizes.md, ...color},
@@ -849,12 +849,14 @@ exports[`MarkdownView renders code blocks 1`] = `
849
849
  "fontFamily": "text",
850
850
  },
851
851
  {
852
- "backgroundColor": "#f5f5f5",
853
- "borderColor": "#CCCCCC",
852
+ "backgroundColor": "#D9D9D9",
853
+ "borderColor": "#CDCDCD",
854
854
  "borderRadius": 4,
855
855
  "borderWidth": 1,
856
- "fontFamily": "Courier",
857
- "padding": 10,
856
+ "color": "#1C1C1C",
857
+ "fontFamily": "Menlo",
858
+ "fontSize": 13,
859
+ "padding": 8,
858
860
  },
859
861
  ],
860
862
  },
@@ -907,12 +909,16 @@ exports[`MarkdownView renders inline code 1`] = `
907
909
  "fontFamily": "text",
908
910
  },
909
911
  {
910
- "backgroundColor": "#f5f5f5",
911
- "borderColor": "#CCCCCC",
912
- "borderRadius": 4,
912
+ "backgroundColor": "#D9D9D9",
913
+ "borderColor": "#CDCDCD",
914
+ "borderRadius": 3,
913
915
  "borderWidth": 1,
914
- "fontFamily": "Courier",
916
+ "color": "#1C1C1C",
917
+ "fontFamily": "Menlo",
918
+ "fontSize": 13,
915
919
  "padding": 10,
920
+ "paddingHorizontal": 4,
921
+ "paddingVertical": 1,
916
922
  },
917
923
  ],
918
924
  },
package/src/index.tsx CHANGED
@@ -43,6 +43,7 @@ export * from "./InfoTooltipButton";
43
43
  export * from "./Link";
44
44
  export * from "./login";
45
45
 
46
+ export * from "./MarkdownEditorField";
46
47
  export * from "./MarkdownView";
47
48
  export * from "./MediaQuery";
48
49
  export * from "./MobileAddressAutoComplete";