Skip to content

Commit 82f7451

Browse files
authored
feat(web): enriched input style (#510)
# Summary + This PR introduces `EnrichedInputStyle`, which is a subset of `ViewStyle | TextStyle`. + Currently this new style type is only used on the web, and not on native. Since web version isn't pushed to npm this PR does not introduce breaking changes. + Added a converter `EnrichedInputStyle` -> `CSSProperties` as well as tests for it. + Small changes related to `tsconfig`, which were needed because `index.web.tsx` now is a bit different than `index.tsx`. ## Test Plan + Run `yarn example-web dev` + Play around with `const enrichedInputStyle: EnrichedInputStyle` in `apps/example-web/src/App.tsx` ## Screenshots / Videos Include any visual proof that helps reviewers understand the change — UI updates, bug reproduction or the result of the fix. ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ❌ | | Android | ❌ | | Web | ✅ | ## Checklist - [ ] E2E tests are passing - [ ] Required E2E tests have been added (if applicable)
1 parent 7b5c6c5 commit 82f7451

11 files changed

Lines changed: 1429 additions & 73 deletions

apps/example-web/src/App.css

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -37,39 +37,6 @@ body {
3737
margin: 0 0 24px;
3838
}
3939

40-
.editor-wrapper {
41-
width: 100%;
42-
background: var(--editor-bg);
43-
border-radius: var(--radius-md);
44-
overflow: hidden;
45-
cursor: text;
46-
margin-bottom: 16px;
47-
}
48-
49-
.editor-content {
50-
padding: 12px 14px;
51-
min-height: 120px;
52-
font-size: 18px;
53-
line-height: 1.5;
54-
outline: none;
55-
display: flex;
56-
flex-direction: column;
57-
}
58-
59-
.editor-content .tiptap {
60-
outline: none;
61-
flex: 1;
62-
display: flex;
63-
flex-direction: column;
64-
}
65-
66-
.editor-content .tiptap .ProseMirror {
67-
outline: none;
68-
flex: 1;
69-
min-height: 120px;
70-
cursor: text;
71-
}
72-
7340
.btn {
7441
flex: 1;
7542
padding: 16px;

apps/example-web/src/App.tsx

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
type OnChangeSelectionEvent,
88
type FocusEvent,
99
type BlurEvent,
10+
type EnrichedInputStyle,
1011
} from 'react-native-enriched';
1112
import type { NativeSyntheticEvent } from 'react-native';
1213
import { EditorActions } from './components/EditorActions';
@@ -51,24 +52,21 @@ function App() {
5152
<div className="container">
5253
<h1 className="app-title">Enriched Text Input</h1>
5354

54-
<div className="editor-wrapper" onClick={() => ref.current?.focus()}>
55-
<div className="editor-content">
56-
<EnrichedTextInput
57-
ref={ref}
58-
placeholder="Type something"
59-
autoFocus
60-
editable
61-
scrollEnabled
62-
autoCapitalize="sentences"
63-
onFocus={handleFocus}
64-
onBlur={handleBlur}
65-
onKeyPress={handleKeyPress}
66-
onChangeText={handleOnChangeText}
67-
onChangeSelection={handleChangeSelection}
68-
onChangeHtml={handleOnChangeHtml}
69-
/>
70-
</div>
71-
</div>
55+
<EnrichedTextInput
56+
ref={ref}
57+
placeholder="Type something here..."
58+
autoFocus
59+
editable
60+
scrollEnabled
61+
autoCapitalize="sentences"
62+
style={enrichedInputStyle}
63+
onFocus={handleFocus}
64+
onBlur={handleBlur}
65+
onKeyPress={handleKeyPress}
66+
onChangeText={handleOnChangeText}
67+
onChangeSelection={handleChangeSelection}
68+
onChangeHtml={handleOnChangeHtml}
69+
/>
7270

7371
<EditorActions
7472
showHtmlOutput={showHtmlOutput}
@@ -105,4 +103,14 @@ function App() {
105103
);
106104
}
107105

106+
const enrichedInputStyle: EnrichedInputStyle = {
107+
backgroundColor: 'gainsboro',
108+
width: '100%',
109+
marginVertical: 12,
110+
maxHeight: 300,
111+
paddingVertical: 12,
112+
paddingHorizontal: 14,
113+
borderRadius: 8,
114+
};
115+
108116
export default App;

apps/example/tsconfig.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"paths": {
5+
"react-native-enriched": ["../../src/index.tsx"]
6+
}
7+
}
8+
}

lefthook.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pre-commit:
77

88
types:
99
glob: "*.{js,ts, jsx, tsx}"
10-
run: npx tsc
10+
run: yarn typecheck
1111

1212
lint-android:
1313
glob: "**/*.{kt,kts,java,gradle}"

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@
4848
"example": "yarn workspace react-native-enriched-example",
4949
"example-web": "yarn workspace react-native-enriched-web-example",
5050
"test": "jest --passWithNoTests",
51-
"typecheck": "tsc",
51+
"typecheck": "yarn typecheck:lib && yarn typecheck:example && yarn typecheck:example-web",
52+
"typecheck:lib": "tsc -p tsconfig.build.json",
53+
"typecheck:example": "tsc -p apps/example/tsconfig.json",
54+
"typecheck:example-web": "tsc -p apps/example-web/tsconfig.app.json",
5255
"lint": "eslint \"**/*.{js,ts,tsx}\"",
5356
"lint:android": "cd apps/example/android && ./gradlew lintVerify",
5457
"lint:android:fix": "cd apps/example/android && ./gradlew lintFormat",

src/index.web.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export { EnrichedTextInput } from './web/EnrichedTextInput';
22
export type {
3-
EnrichedTextInputProps,
3+
EnrichedInputStyle,
4+
EnrichedTextInputWebProps as EnrichedTextInputProps,
45
OnChangeTextEvent,
56
OnChangeHtmlEvent,
67
OnChangeStateEvent,

src/types.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { RefObject } from 'react';
22
import type {
33
ColorValue,
4+
DimensionValue,
45
NativeMethods,
56
NativeSyntheticEvent,
67
ReturnKeyTypeOptions,
@@ -10,6 +11,171 @@ import type {
1011
ViewStyle,
1112
} from 'react-native';
1213

14+
export interface EnrichedInputStyle {
15+
// Layout / FlexStyle
16+
alignSelf?: TextStyle['alignSelf'];
17+
aspectRatio?: number | string;
18+
borderBottomWidth?: number;
19+
borderEndWidth?: number;
20+
borderLeftWidth?: number;
21+
borderRightWidth?: number;
22+
borderStartWidth?: number;
23+
borderTopWidth?: number;
24+
borderWidth?: number;
25+
bottom?: DimensionValue;
26+
boxSizing?: TextStyle['boxSizing'];
27+
display?: TextStyle['display'];
28+
end?: DimensionValue;
29+
flex?: number;
30+
flexBasis?: DimensionValue;
31+
flexGrow?: number;
32+
flexShrink?: number;
33+
height?: DimensionValue;
34+
inset?: DimensionValue;
35+
insetBlock?: DimensionValue;
36+
insetBlockEnd?: DimensionValue;
37+
insetBlockStart?: DimensionValue;
38+
insetInline?: DimensionValue;
39+
insetInlineEnd?: DimensionValue;
40+
insetInlineStart?: DimensionValue;
41+
left?: DimensionValue;
42+
margin?: DimensionValue;
43+
marginBlock?: DimensionValue;
44+
marginBlockEnd?: DimensionValue;
45+
marginBlockStart?: DimensionValue;
46+
marginBottom?: DimensionValue;
47+
marginEnd?: DimensionValue;
48+
marginHorizontal?: DimensionValue;
49+
marginInline?: DimensionValue;
50+
marginInlineEnd?: DimensionValue;
51+
marginInlineStart?: DimensionValue;
52+
marginLeft?: DimensionValue;
53+
marginRight?: DimensionValue;
54+
marginStart?: DimensionValue;
55+
marginTop?: DimensionValue;
56+
marginVertical?: DimensionValue;
57+
maxHeight?: DimensionValue;
58+
maxWidth?: DimensionValue;
59+
minHeight?: DimensionValue;
60+
minWidth?: DimensionValue;
61+
padding?: DimensionValue;
62+
paddingBlock?: DimensionValue;
63+
paddingBlockEnd?: DimensionValue;
64+
paddingBlockStart?: DimensionValue;
65+
paddingBottom?: DimensionValue;
66+
paddingEnd?: DimensionValue;
67+
paddingHorizontal?: DimensionValue;
68+
paddingInline?: DimensionValue;
69+
paddingInlineEnd?: DimensionValue;
70+
paddingInlineStart?: DimensionValue;
71+
paddingLeft?: DimensionValue;
72+
paddingRight?: DimensionValue;
73+
paddingStart?: DimensionValue;
74+
paddingTop?: DimensionValue;
75+
paddingVertical?: DimensionValue;
76+
position?: TextStyle['position'];
77+
right?: DimensionValue;
78+
start?: DimensionValue;
79+
top?: DimensionValue;
80+
width?: DimensionValue;
81+
zIndex?: number;
82+
83+
// Shadows
84+
/** @platform ios */
85+
shadowColor?: ColorValue;
86+
/** @platform ios */
87+
shadowOffset?: TextStyle['shadowOffset'];
88+
/** @platform ios */
89+
shadowOpacity?: TextStyle['shadowOpacity'];
90+
/** @platform ios */
91+
shadowRadius?: number;
92+
93+
// Transforms
94+
transform?: TextStyle['transform'];
95+
transformOrigin?: TextStyle['transformOrigin'];
96+
97+
// View appearance
98+
/** @platform ios web */
99+
backfaceVisibility?: TextStyle['backfaceVisibility'];
100+
backgroundColor?: ColorValue;
101+
/** @platform ios web */
102+
borderBlockColor?: ColorValue;
103+
/** @platform ios web */
104+
borderBlockEndColor?: ColorValue;
105+
/** @platform ios web */
106+
borderBlockStartColor?: ColorValue;
107+
/** @platform ios web */
108+
borderBottomColor?: ColorValue;
109+
/** @platform ios web */
110+
borderBottomEndRadius?: TextStyle['borderBottomEndRadius'];
111+
/** @platform ios web */
112+
borderBottomLeftRadius?: TextStyle['borderBottomLeftRadius'];
113+
/** @platform ios web */
114+
borderBottomRightRadius?: TextStyle['borderBottomRightRadius'];
115+
/** @platform ios web */
116+
borderBottomStartRadius?: TextStyle['borderBottomStartRadius'];
117+
/** @platform ios web */
118+
borderColor?: ColorValue;
119+
/** @platform ios web */
120+
borderEndColor?: ColorValue;
121+
/** @platform ios web */
122+
borderEndEndRadius?: TextStyle['borderEndEndRadius'];
123+
/** @platform ios web */
124+
borderEndStartRadius?: TextStyle['borderEndStartRadius'];
125+
/** @platform ios web */
126+
borderLeftColor?: ColorValue;
127+
/** @platform ios web */
128+
borderRadius?: TextStyle['borderRadius'];
129+
/** @platform ios web */
130+
borderRightColor?: ColorValue;
131+
/** @platform ios web */
132+
borderStartColor?: ColorValue;
133+
/** @platform ios web */
134+
borderStartEndRadius?: TextStyle['borderStartEndRadius'];
135+
/** @platform ios web */
136+
borderStartStartRadius?: TextStyle['borderStartStartRadius'];
137+
/** @platform ios web */
138+
borderStyle?: TextStyle['borderStyle'];
139+
/** @platform ios web */
140+
borderTopColor?: ColorValue;
141+
/** @platform ios web */
142+
borderTopEndRadius?: TextStyle['borderTopEndRadius'];
143+
/** @platform ios web */
144+
borderTopLeftRadius?: TextStyle['borderTopLeftRadius'];
145+
/** @platform ios web */
146+
borderTopRightRadius?: TextStyle['borderTopRightRadius'];
147+
/** @platform ios web */
148+
borderTopStartRadius?: TextStyle['borderTopStartRadius'];
149+
boxShadow?: TextStyle['boxShadow'];
150+
/** @platform web */
151+
cursor?: TextStyle['cursor'];
152+
/** @platform android */
153+
elevation?: number;
154+
/** @platform android web */
155+
filter?: TextStyle['filter'];
156+
/** @platform android web */
157+
mixBlendMode?: TextStyle['mixBlendMode'];
158+
opacity?: TextStyle['opacity'];
159+
/** @platform ios web */
160+
outlineColor?: ColorValue;
161+
outlineOffset?: TextStyle['outlineOffset'];
162+
/** @platform android web */
163+
outlineStyle?: TextStyle['outlineStyle'];
164+
outlineWidth?: TextStyle['outlineWidth'];
165+
/** @platform ios web */
166+
pointerEvents?: TextStyle['pointerEvents'];
167+
168+
// Typography
169+
color?: ColorValue;
170+
fontFamily?: string;
171+
fontSize?: number;
172+
fontStyle?: TextStyle['fontStyle'];
173+
fontWeight?: TextStyle['fontWeight'];
174+
lineHeight?: number;
175+
/** @platform web */
176+
letterSpacing?: number;
177+
}
178+
13179
interface HeadingStyle {
14180
fontSize?: number;
15181
bold?: boolean;
@@ -322,3 +488,11 @@ export interface EnrichedTextInputProps extends Omit<ViewProps, 'children'> {
322488
*/
323489
useHtmlNormalizer?: boolean;
324490
}
491+
492+
// Web-only for now. Native will eventually migrate to EnrichedInputStyle too,
493+
// at which point this interface will be removed and EnrichedTextInputProps
494+
// will use EnrichedInputStyle directly.
495+
export interface EnrichedTextInputWebProps
496+
extends Omit<EnrichedTextInputProps, 'style'> {
497+
style?: EnrichedInputStyle;
498+
}

src/web/EnrichedTextInput.css

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
.tiptap.ProseMirror p {
2+
margin-top: 0;
3+
margin-bottom: 0;
4+
}
5+
6+
.tiptap.ProseMirror-focused {
7+
outline: none;
8+
}
9+
110
.eti-editor p.is-editor-empty:first-child::before {
211
color: #adb5bd;
312
content: attr(data-placeholder);
413
float: left;
514
height: 0;
615
pointer-events: none;
716
}
8-
9-
.eti-editor {
10-
min-height: 150px;
11-
max-height: 500px;
12-
}

0 commit comments

Comments
 (0)