react-native-richify 1.0.1 → 1.0.3
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.
- package/lib/commonjs/components/OverlayText.d.js +6 -0
- package/lib/commonjs/components/OverlayText.d.js.map +1 -0
- package/lib/commonjs/components/OverlayText.js +51 -0
- package/lib/commonjs/components/OverlayText.js.map +1 -0
- package/lib/commonjs/components/RichTextInput.d.js +6 -0
- package/lib/commonjs/components/RichTextInput.d.js.map +1 -0
- package/lib/commonjs/components/RichTextInput.js +163 -0
- package/lib/commonjs/components/RichTextInput.js.map +1 -0
- package/lib/commonjs/components/Toolbar.d.js +6 -0
- package/lib/commonjs/components/Toolbar.d.js.map +1 -0
- package/lib/commonjs/components/Toolbar.js +96 -0
- package/lib/commonjs/components/Toolbar.js.map +1 -0
- package/lib/commonjs/components/ToolbarButton.d.js +6 -0
- package/lib/commonjs/components/ToolbarButton.d.js.map +1 -0
- package/lib/commonjs/components/ToolbarButton.js +63 -0
- package/lib/commonjs/components/ToolbarButton.js.map +1 -0
- package/lib/commonjs/constants/defaultStyles.d.js +6 -0
- package/lib/commonjs/constants/defaultStyles.d.js.map +1 -0
- package/lib/commonjs/constants/defaultStyles.js +172 -0
- package/lib/commonjs/constants/defaultStyles.js.map +1 -0
- package/lib/commonjs/context/RichTextContext.d.js +6 -0
- package/lib/commonjs/context/RichTextContext.d.js.map +1 -0
- package/lib/commonjs/context/RichTextContext.js +61 -0
- package/lib/commonjs/context/RichTextContext.js.map +1 -0
- package/lib/commonjs/hooks/useFormatting.d.js +6 -0
- package/lib/commonjs/hooks/useFormatting.d.js.map +1 -0
- package/lib/commonjs/hooks/useFormatting.js +82 -0
- package/lib/commonjs/hooks/useFormatting.js.map +1 -0
- package/lib/commonjs/hooks/useRichText.d.js +6 -0
- package/lib/commonjs/hooks/useRichText.d.js.map +1 -0
- package/lib/commonjs/hooks/useRichText.js +142 -0
- package/lib/commonjs/hooks/useRichText.js.map +1 -0
- package/lib/commonjs/hooks/useSelection.d.js +6 -0
- package/lib/commonjs/hooks/useSelection.d.js.map +1 -0
- package/lib/commonjs/hooks/useSelection.js +39 -0
- package/lib/commonjs/hooks/useSelection.js.map +1 -0
- package/lib/commonjs/index.d.js +186 -0
- package/lib/commonjs/index.d.js.map +1 -0
- package/lib/commonjs/index.js +186 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/types/index.d.js +6 -0
- package/lib/commonjs/types/index.d.js.map +1 -0
- package/lib/commonjs/types/index.js +6 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/commonjs/utils/formatter.d.js +13 -0
- package/lib/commonjs/utils/formatter.d.js.map +1 -0
- package/lib/commonjs/utils/formatter.js +229 -0
- package/lib/commonjs/utils/formatter.js.map +1 -0
- package/lib/commonjs/utils/parser.d.js +6 -0
- package/lib/commonjs/utils/parser.d.js.map +1 -0
- package/lib/commonjs/utils/parser.js +221 -0
- package/lib/commonjs/utils/parser.js.map +1 -0
- package/lib/commonjs/utils/styleMapper.d.js +6 -0
- package/lib/commonjs/utils/styleMapper.d.js.map +1 -0
- package/lib/commonjs/utils/styleMapper.js +87 -0
- package/lib/commonjs/utils/styleMapper.js.map +1 -0
- package/lib/module/components/OverlayText.d.js +4 -0
- package/lib/module/components/OverlayText.d.js.map +1 -0
- package/lib/module/components/OverlayText.js +47 -0
- package/lib/module/components/OverlayText.js.map +1 -0
- package/lib/module/components/RichTextInput.d.js +4 -0
- package/lib/module/components/RichTextInput.d.js.map +1 -0
- package/lib/module/components/RichTextInput.js +158 -0
- package/lib/module/components/RichTextInput.js.map +1 -0
- package/lib/module/components/Toolbar.d.js +4 -0
- package/lib/module/components/Toolbar.d.js.map +1 -0
- package/lib/module/components/Toolbar.js +92 -0
- package/lib/module/components/Toolbar.js.map +1 -0
- package/lib/module/components/ToolbarButton.d.js +4 -0
- package/lib/module/components/ToolbarButton.d.js.map +1 -0
- package/lib/module/components/ToolbarButton.js +59 -0
- package/lib/module/components/ToolbarButton.js.map +1 -0
- package/lib/module/constants/defaultStyles.d.js +4 -0
- package/lib/module/constants/defaultStyles.d.js.map +1 -0
- package/lib/module/constants/defaultStyles.js +168 -0
- package/lib/module/constants/defaultStyles.js.map +1 -0
- package/lib/module/context/RichTextContext.d.js +4 -0
- package/lib/module/context/RichTextContext.d.js.map +1 -0
- package/lib/module/context/RichTextContext.js +55 -0
- package/lib/module/context/RichTextContext.js.map +1 -0
- package/lib/module/hooks/useFormatting.d.js +11 -0
- package/lib/module/hooks/useFormatting.d.js.map +1 -0
- package/lib/module/hooks/useFormatting.js +78 -0
- package/lib/module/hooks/useFormatting.js.map +1 -0
- package/lib/module/hooks/useRichText.d.js +4 -0
- package/lib/module/hooks/useRichText.d.js.map +1 -0
- package/lib/module/hooks/useRichText.js +138 -0
- package/lib/module/hooks/useRichText.js.map +1 -0
- package/lib/module/hooks/useSelection.d.js +4 -0
- package/lib/module/hooks/useSelection.d.js.map +1 -0
- package/lib/module/hooks/useSelection.js +35 -0
- package/lib/module/hooks/useSelection.js.map +1 -0
- package/lib/module/index.d.js +15 -0
- package/lib/module/index.d.js.map +1 -0
- package/lib/module/index.js +25 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types/index.d.js +4 -0
- package/lib/module/types/index.d.js.map +1 -0
- package/lib/module/types/index.js +4 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/utils/formatter.d.js +30 -0
- package/lib/module/utils/formatter.d.js.map +1 -0
- package/lib/module/utils/formatter.js +217 -0
- package/lib/module/utils/formatter.js.map +1 -0
- package/lib/module/utils/parser.d.js +4 -0
- package/lib/module/utils/parser.d.js.map +1 -0
- package/lib/module/utils/parser.js +211 -0
- package/lib/module/utils/parser.js.map +1 -0
- package/lib/module/utils/styleMapper.d.js +4 -0
- package/lib/module/utils/styleMapper.d.js.map +1 -0
- package/lib/module/utils/styleMapper.js +82 -0
- package/lib/module/utils/styleMapper.js.map +1 -0
- package/lib/typescript/src/components/OverlayText.d.ts +11 -0
- package/lib/typescript/src/components/OverlayText.d.ts.map +1 -0
- package/lib/typescript/src/components/RichTextInput.d.ts +21 -0
- package/lib/typescript/src/components/RichTextInput.d.ts.map +1 -0
- package/lib/typescript/src/components/Toolbar.d.ts +13 -0
- package/lib/typescript/src/components/Toolbar.d.ts.map +1 -0
- package/lib/typescript/src/components/ToolbarButton.d.ts +8 -0
- package/lib/typescript/src/components/ToolbarButton.d.ts.map +1 -0
- package/lib/typescript/src/constants/defaultStyles.d.ts +46 -0
- package/lib/typescript/src/constants/defaultStyles.d.ts.map +1 -0
- package/lib/typescript/src/context/RichTextContext.d.ts +31 -0
- package/lib/typescript/src/context/RichTextContext.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useFormatting.d.ts +26 -0
- package/lib/typescript/src/hooks/useFormatting.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useRichText.d.ts +17 -0
- package/lib/typescript/src/hooks/useRichText.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useSelection.d.ts +14 -0
- package/lib/typescript/src/hooks/useSelection.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +16 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +257 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -0
- package/lib/typescript/src/utils/formatter.d.ts +29 -0
- package/lib/typescript/src/utils/formatter.d.ts.map +1 -0
- package/lib/typescript/src/utils/parser.d.ts +46 -0
- package/lib/typescript/src/utils/parser.d.ts.map +1 -0
- package/lib/typescript/src/utils/styleMapper.d.ts +16 -0
- package/lib/typescript/src/utils/styleMapper.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/OverlayText.tsx +11 -3
- package/src/components/RichTextInput.tsx +11 -5
- package/src/components/Toolbar.d.ts +1 -1
- package/src/components/Toolbar.tsx +5 -5
- package/src/components/ToolbarButton.d.ts +1 -1
- package/src/constants/defaultStyles.d.ts +1 -1
- package/src/hooks/useRichText.ts +11 -4
- package/src/index.d.ts +1 -1
- package/src/index.ts +2 -0
- package/src/types/index.d.ts +22 -10
- package/src/types/index.ts +24 -10
- package/src/utils/formatter.d.ts +2 -2
- package/src/utils/formatter.ts +4 -4
- package/src/utils/parser.d.ts +1 -1
- package/src/utils/parser.ts +2 -2
- package/src/utils/styleMapper.d.ts +1 -1
- package/src/utils/styleMapper.ts +2 -2
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import type { TextStyle, ViewStyle, TextInputProps, ColorValue } from 'react-native';
|
|
2
|
+
/**
|
|
3
|
+
* Supported inline formatting types.
|
|
4
|
+
*/
|
|
5
|
+
export type FormatType = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'code';
|
|
6
|
+
/**
|
|
7
|
+
* Heading level presets.
|
|
8
|
+
*/
|
|
9
|
+
export type HeadingLevel = 'h1' | 'h2' | 'h3' | 'none';
|
|
10
|
+
/**
|
|
11
|
+
* List type for a line/paragraph.
|
|
12
|
+
*/
|
|
13
|
+
export type ListType = 'bullet' | 'ordered' | 'none';
|
|
14
|
+
/**
|
|
15
|
+
* Inline formatting styles attached to a text segment.
|
|
16
|
+
*/
|
|
17
|
+
export interface FormatStyle {
|
|
18
|
+
bold?: boolean;
|
|
19
|
+
italic?: boolean;
|
|
20
|
+
underline?: boolean;
|
|
21
|
+
strikethrough?: boolean;
|
|
22
|
+
code?: boolean;
|
|
23
|
+
color?: string;
|
|
24
|
+
backgroundColor?: string;
|
|
25
|
+
fontSize?: number;
|
|
26
|
+
heading?: HeadingLevel;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A segment of text with uniform formatting.
|
|
30
|
+
* The entire rich text content is an ordered array of these segments.
|
|
31
|
+
*/
|
|
32
|
+
export interface StyledSegment {
|
|
33
|
+
/** The text content of this segment. */
|
|
34
|
+
text: string;
|
|
35
|
+
/** The formatting styles applied to this segment. */
|
|
36
|
+
styles: FormatStyle;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Represents a text selection range within the input.
|
|
40
|
+
*/
|
|
41
|
+
export interface SelectionRange {
|
|
42
|
+
/** Start index (inclusive). */
|
|
43
|
+
start: number;
|
|
44
|
+
/** End index (exclusive). */
|
|
45
|
+
end: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The complete state of the rich text input.
|
|
49
|
+
*/
|
|
50
|
+
export interface RichTextState {
|
|
51
|
+
/** Ordered array of styled text segments. */
|
|
52
|
+
segments: StyledSegment[];
|
|
53
|
+
/** Current selection range. */
|
|
54
|
+
selection: SelectionRange;
|
|
55
|
+
/** The current active styles that will be applied to newly typed text. */
|
|
56
|
+
activeStyles: FormatStyle;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Actions returned by the useRichText hook for controlling the editor.
|
|
60
|
+
*/
|
|
61
|
+
export interface RichTextActions {
|
|
62
|
+
/** Toggle an inline format on the current selection or active styles. */
|
|
63
|
+
toggleFormat: (format: FormatType) => void;
|
|
64
|
+
/** Set a specific style property on the current selection. */
|
|
65
|
+
setStyleProperty: <K extends keyof FormatStyle>(key: K, value: FormatStyle[K]) => void;
|
|
66
|
+
/** Apply a heading level to the current line. */
|
|
67
|
+
setHeading: (level: HeadingLevel) => void;
|
|
68
|
+
/** Set the text color for the current selection. */
|
|
69
|
+
setColor: (color: string) => void;
|
|
70
|
+
/** Set the background color for the current selection. */
|
|
71
|
+
setBackgroundColor: (color: string) => void;
|
|
72
|
+
/** Set the font size for the current selection. */
|
|
73
|
+
setFontSize: (size: number) => void;
|
|
74
|
+
/** Handle text change from TextInput. */
|
|
75
|
+
handleTextChange: (text: string) => void;
|
|
76
|
+
/** Handle selection change from TextInput. */
|
|
77
|
+
handleSelectionChange: (selection: SelectionRange) => void;
|
|
78
|
+
/** Check whether a format is active at the current cursor/selection. */
|
|
79
|
+
isFormatActive: (format: FormatType) => boolean;
|
|
80
|
+
/** Get the effective shared style at the current cursor/selection. */
|
|
81
|
+
getSelectionStyle: () => FormatStyle;
|
|
82
|
+
/** Get the full plain text content. */
|
|
83
|
+
getPlainText: () => string;
|
|
84
|
+
/** Export the segments as a serializable JSON array. */
|
|
85
|
+
exportJSON: () => StyledSegment[];
|
|
86
|
+
/** Import segments from a JSON array, replacing current content. */
|
|
87
|
+
importJSON: (segments: StyledSegment[]) => void;
|
|
88
|
+
/** Clear all content. */
|
|
89
|
+
clear: () => void;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Return value of the useRichText hook.
|
|
93
|
+
*/
|
|
94
|
+
export interface UseRichTextReturn {
|
|
95
|
+
state: RichTextState;
|
|
96
|
+
actions: RichTextActions;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Theme configuration for the RichTextInput component.
|
|
100
|
+
*/
|
|
101
|
+
export interface RichTextTheme {
|
|
102
|
+
/** Style for the outer container. */
|
|
103
|
+
containerStyle?: ViewStyle;
|
|
104
|
+
/** Style for the TextInput. */
|
|
105
|
+
inputStyle?: TextStyle;
|
|
106
|
+
/** Style for the overlay text container. */
|
|
107
|
+
overlayContainerStyle?: ViewStyle;
|
|
108
|
+
/** Base text style applied to all segments before formatting. */
|
|
109
|
+
baseTextStyle?: TextStyle;
|
|
110
|
+
/** Style for the toolbar container. */
|
|
111
|
+
toolbarStyle?: ViewStyle;
|
|
112
|
+
/** Style for toolbar buttons. */
|
|
113
|
+
toolbarButtonStyle?: ViewStyle;
|
|
114
|
+
/** Style for active toolbar buttons. */
|
|
115
|
+
toolbarButtonActiveStyle?: ViewStyle;
|
|
116
|
+
/** Text style for toolbar button labels. */
|
|
117
|
+
toolbarButtonTextStyle?: TextStyle;
|
|
118
|
+
/** Text style for active toolbar button labels. */
|
|
119
|
+
toolbarButtonActiveTextStyle?: TextStyle;
|
|
120
|
+
/** Style for the code format. */
|
|
121
|
+
codeStyle?: TextStyle;
|
|
122
|
+
/** Colors */
|
|
123
|
+
colors?: {
|
|
124
|
+
/** Primary accent color. */
|
|
125
|
+
primary?: string;
|
|
126
|
+
/** Background color of the editor. */
|
|
127
|
+
background?: string;
|
|
128
|
+
/** Text color. */
|
|
129
|
+
text?: string;
|
|
130
|
+
/** Placeholder text color. */
|
|
131
|
+
placeholder?: string;
|
|
132
|
+
/** Toolbar background. */
|
|
133
|
+
toolbarBackground?: string;
|
|
134
|
+
/** Toolbar border color. */
|
|
135
|
+
toolbarBorder?: string;
|
|
136
|
+
/** Cursor / caret color. */
|
|
137
|
+
cursor?: ColorValue;
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A toolbar item configuration.
|
|
142
|
+
*/
|
|
143
|
+
export interface ToolbarItem {
|
|
144
|
+
/** Unique identifier. */
|
|
145
|
+
id: string;
|
|
146
|
+
/** Display label or icon text. */
|
|
147
|
+
label: string;
|
|
148
|
+
/** The format type this button toggles (for inline formats). */
|
|
149
|
+
format?: FormatType;
|
|
150
|
+
/** The heading level this button sets. */
|
|
151
|
+
heading?: HeadingLevel;
|
|
152
|
+
/** Custom action handler (overrides default behavior). */
|
|
153
|
+
onPress?: () => void;
|
|
154
|
+
/** Whether this item is currently active. */
|
|
155
|
+
active?: boolean;
|
|
156
|
+
/** Custom render function for the button. */
|
|
157
|
+
renderButton?: (props: ToolbarButtonRenderProps) => React.ReactElement | null;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Props passed to a custom toolbar button renderer.
|
|
161
|
+
*/
|
|
162
|
+
export interface ToolbarButtonRenderProps {
|
|
163
|
+
active: boolean;
|
|
164
|
+
onPress: () => void;
|
|
165
|
+
label: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Props passed to a custom toolbar renderer.
|
|
169
|
+
*/
|
|
170
|
+
export interface ToolbarRenderProps {
|
|
171
|
+
items: ToolbarItem[];
|
|
172
|
+
state: RichTextState;
|
|
173
|
+
actions: RichTextActions;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Props for the OverlayText component.
|
|
177
|
+
*/
|
|
178
|
+
export interface OverlayTextProps {
|
|
179
|
+
/** The styled segments to render. */
|
|
180
|
+
segments: StyledSegment[];
|
|
181
|
+
/** Base text style. */
|
|
182
|
+
baseTextStyle?: TextStyle;
|
|
183
|
+
/** Theme overrides. */
|
|
184
|
+
theme?: RichTextTheme;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Props for the ToolbarButton component.
|
|
188
|
+
*/
|
|
189
|
+
export interface ToolbarButtonProps {
|
|
190
|
+
/** Button label text. */
|
|
191
|
+
label: string;
|
|
192
|
+
/** Whether the button is currently active. */
|
|
193
|
+
active: boolean;
|
|
194
|
+
/** Press handler. */
|
|
195
|
+
onPress: () => void;
|
|
196
|
+
/** Theme overrides. */
|
|
197
|
+
theme?: RichTextTheme;
|
|
198
|
+
/** Custom render function. */
|
|
199
|
+
renderButton?: ToolbarItem['renderButton'];
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Props for the Toolbar component.
|
|
203
|
+
*/
|
|
204
|
+
export interface ToolbarProps {
|
|
205
|
+
/** The current rich text actions. */
|
|
206
|
+
actions: RichTextActions;
|
|
207
|
+
/** The current rich text state. */
|
|
208
|
+
state: RichTextState;
|
|
209
|
+
/** Custom toolbar items (overrides defaults). */
|
|
210
|
+
items?: ToolbarItem[];
|
|
211
|
+
/** Theme overrides. */
|
|
212
|
+
theme?: RichTextTheme;
|
|
213
|
+
/** Whether to show the toolbar. */
|
|
214
|
+
visible?: boolean;
|
|
215
|
+
/** Custom render function for the entire toolbar. */
|
|
216
|
+
renderToolbar?: (props: ToolbarRenderProps) => React.ReactElement | null;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Props for the main RichTextInput component.
|
|
220
|
+
*/
|
|
221
|
+
export interface RichTextInputProps {
|
|
222
|
+
/** Initial segments to populate the editor with. */
|
|
223
|
+
initialSegments?: StyledSegment[];
|
|
224
|
+
/** Callback when the content changes. */
|
|
225
|
+
onChangeSegments?: (segments: StyledSegment[]) => void;
|
|
226
|
+
/** Callback when the plain text changes. */
|
|
227
|
+
onChangeText?: (text: string) => void;
|
|
228
|
+
/** Placeholder text. */
|
|
229
|
+
placeholder?: string;
|
|
230
|
+
/** Whether the input is editable. */
|
|
231
|
+
editable?: boolean;
|
|
232
|
+
/** Maximum character length. */
|
|
233
|
+
maxLength?: number;
|
|
234
|
+
/** Whether to show the toolbar. */
|
|
235
|
+
showToolbar?: boolean;
|
|
236
|
+
/** Toolbar position relative to the input. */
|
|
237
|
+
toolbarPosition?: 'top' | 'bottom';
|
|
238
|
+
/** Custom toolbar items. */
|
|
239
|
+
toolbarItems?: ToolbarItem[];
|
|
240
|
+
/** Theme configuration. */
|
|
241
|
+
theme?: RichTextTheme;
|
|
242
|
+
/** Whether multiline input is enabled. */
|
|
243
|
+
multiline?: boolean;
|
|
244
|
+
/** Minimum height for the input area. */
|
|
245
|
+
minHeight?: number;
|
|
246
|
+
/** Maximum height for the input area. */
|
|
247
|
+
maxHeight?: number;
|
|
248
|
+
/** Auto-focus the input on mount. */
|
|
249
|
+
autoFocus?: boolean;
|
|
250
|
+
/** Additional TextInput props. */
|
|
251
|
+
textInputProps?: Omit<TextInputProps, 'value' | 'onChangeText' | 'onSelectionChange' | 'multiline' | 'placeholder' | 'editable' | 'maxLength' | 'autoFocus'>;
|
|
252
|
+
/** Custom toolbar render function. */
|
|
253
|
+
renderToolbar?: ToolbarProps['renderToolbar'];
|
|
254
|
+
/** Ref callback to access actions. */
|
|
255
|
+
onReady?: (actions: RichTextActions) => void;
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { StyledSegment, FormatType, FormatStyle, HeadingLevel, SelectionRange } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Toggle an inline format (bold, italic, etc.) on the selected range.
|
|
4
|
+
*
|
|
5
|
+
* If the entire selection already has the format, it is removed.
|
|
6
|
+
* Otherwise, it is applied to the entire selection.
|
|
7
|
+
*
|
|
8
|
+
* Returns the new segments array.
|
|
9
|
+
*/
|
|
10
|
+
export declare function toggleFormatOnSelection(segments: StyledSegment[], selection: SelectionRange, format: FormatType): StyledSegment[];
|
|
11
|
+
/**
|
|
12
|
+
* Set a specific style property on the selected range.
|
|
13
|
+
*/
|
|
14
|
+
export declare function setStyleOnSelection<K extends keyof FormatStyle>(segments: StyledSegment[], selection: SelectionRange, key: K, value: FormatStyle[K]): StyledSegment[];
|
|
15
|
+
/**
|
|
16
|
+
* Apply a heading level to the line containing the cursor/selection.
|
|
17
|
+
*/
|
|
18
|
+
export declare function setHeadingOnLine(segments: StyledSegment[], selection: SelectionRange, level: HeadingLevel): StyledSegment[];
|
|
19
|
+
/**
|
|
20
|
+
* Checks whether the given format is active across the entire selection.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isFormatActiveInSelection(segments: StyledSegment[], selection: SelectionRange, format: FormatType): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Gets the format style that is common across the entire selection.
|
|
25
|
+
* For properties where segments disagree, the value is undefined.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getSelectionStyle(segments: StyledSegment[], selection: SelectionRange): FormatStyle;
|
|
28
|
+
export { createSegment } from '../utils/parser';
|
|
29
|
+
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../../../src/utils/formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACf,MAAM,UAAU,CAAC;AAUlB;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,aAAa,EAAE,EACzB,SAAS,EAAE,cAAc,EACzB,MAAM,EAAE,UAAU,GACjB,aAAa,EAAE,CAgBjB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,WAAW,EAC7D,QAAQ,EAAE,aAAa,EAAE,EACzB,SAAS,EAAE,cAAc,EACzB,GAAG,EAAE,CAAC,EACN,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GACpB,aAAa,EAAE,CAOjB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,aAAa,EAAE,EACzB,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,YAAY,GAClB,aAAa,EAAE,CAWjB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,aAAa,EAAE,EACzB,SAAS,EAAE,cAAc,EACzB,MAAM,EAAE,UAAU,GACjB,OAAO,CAQT;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,aAAa,EAAE,EACzB,SAAS,EAAE,cAAc,GACxB,WAAW,CAwCb;AAgID,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { StyledSegment, FormatStyle } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a new segment with the given text and optional styles.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createSegment(text: string, styles?: FormatStyle): StyledSegment;
|
|
6
|
+
/**
|
|
7
|
+
* Computes the total character length across all segments.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getTotalLength(segments: StyledSegment[]): number;
|
|
10
|
+
/**
|
|
11
|
+
* Converts an array of segments to plain text.
|
|
12
|
+
*/
|
|
13
|
+
export declare function segmentsToPlainText(segments: StyledSegment[]): string;
|
|
14
|
+
/**
|
|
15
|
+
* Finds which segment and character offset a global position corresponds to.
|
|
16
|
+
* Returns { segmentIndex, offsetInSegment }.
|
|
17
|
+
*/
|
|
18
|
+
export declare function findPositionInSegments(segments: StyledSegment[], globalPosition: number): {
|
|
19
|
+
segmentIndex: number;
|
|
20
|
+
offsetInSegment: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Splits a segment at the given offset, returning [before, after].
|
|
24
|
+
* If offset is 0 or at end, one side will have empty text.
|
|
25
|
+
*/
|
|
26
|
+
export declare function splitSegment(segment: StyledSegment, offset: number): [StyledSegment, StyledSegment];
|
|
27
|
+
/**
|
|
28
|
+
* Checks if two FormatStyle objects are deeply equal.
|
|
29
|
+
*/
|
|
30
|
+
export declare function areStylesEqual(a: FormatStyle, b: FormatStyle): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Merges adjacent segments that have identical styles.
|
|
33
|
+
* Returns a new array (does not mutate input).
|
|
34
|
+
*/
|
|
35
|
+
export declare function mergeAdjacentSegments(segments: StyledSegment[]): StyledSegment[];
|
|
36
|
+
/**
|
|
37
|
+
* Given the old segments and new plain text (from TextInput onChange),
|
|
38
|
+
* reconcile the segments to preserve formatting while reflecting the text change.
|
|
39
|
+
*
|
|
40
|
+
* Strategy:
|
|
41
|
+
* 1. Find the diff region between old plain text and new plain text
|
|
42
|
+
* 2. Replace that region in the segment array
|
|
43
|
+
* 3. New text inserted at the diff point inherits the `activeStyles`
|
|
44
|
+
*/
|
|
45
|
+
export declare function reconcileTextChange(oldSegments: StyledSegment[], newText: string, activeStyles: FormatStyle): StyledSegment[];
|
|
46
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../../src/utils/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG3D;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,WAAuC,GAC9C,aAAa,CAEf;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,CAEhE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,CAErE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,aAAa,EAAE,EACzB,cAAc,EAAE,MAAM,GACrB;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAiBnD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,MAAM,GACb,CAAC,aAAa,EAAE,aAAa,CAAC,CAIhC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAYtE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,aAAa,EAAE,GACxB,aAAa,EAAE,CA8BjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,aAAa,EAAE,EAC5B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,WAAW,GACxB,aAAa,EAAE,CAqHjB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TextStyle } from 'react-native';
|
|
2
|
+
import type { FormatStyle, RichTextTheme, StyledSegment } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Maps a FormatStyle to a React Native TextStyle.
|
|
5
|
+
* Applies formatting properties based on the segment's style.
|
|
6
|
+
*/
|
|
7
|
+
export declare function formatStyleToTextStyle(formatStyle: FormatStyle, theme?: RichTextTheme): TextStyle;
|
|
8
|
+
/**
|
|
9
|
+
* Maps an entire segment to its computed TextStyle (base + format).
|
|
10
|
+
*/
|
|
11
|
+
export declare function segmentToTextStyle(segment: StyledSegment, theme?: RichTextTheme): TextStyle;
|
|
12
|
+
/**
|
|
13
|
+
* Batch-maps an array of segments to an array of TextStyles.
|
|
14
|
+
*/
|
|
15
|
+
export declare function segmentsToTextStyles(segments: StyledSegment[], theme?: RichTextTheme): TextStyle[];
|
|
16
|
+
//# sourceMappingURL=styleMapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styleMapper.d.ts","sourceRoot":"","sources":["../../../../src/utils/styleMapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG1E;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EACxB,KAAK,CAAC,EAAE,aAAa,GACpB,SAAS,CAsDX;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,aAAa,EACtB,KAAK,CAAC,EAAE,aAAa,GACpB,SAAS,CAQX;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EAAE,EACzB,KAAK,CAAC,EAAE,aAAa,GACpB,SAAS,EAAE,CAEb"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-richify",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A production-grade, fully customizable React Native Rich Text Input using the Overlay Technique — no WebView required.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -17,21 +17,29 @@ export const OverlayText: React.FC<OverlayTextProps> = React.memo(
|
|
|
17
17
|
const overlayStyle =
|
|
18
18
|
resolvedTheme.overlayContainerStyle ??
|
|
19
19
|
DEFAULT_THEME.overlayContainerStyle;
|
|
20
|
+
const resolvedBaseTextStyle =
|
|
21
|
+
baseTextStyle ??
|
|
22
|
+
resolvedTheme.baseTextStyle ??
|
|
23
|
+
DEFAULT_THEME.baseTextStyle;
|
|
24
|
+
const overlayTheme = {
|
|
25
|
+
...resolvedTheme,
|
|
26
|
+
baseTextStyle: resolvedBaseTextStyle,
|
|
27
|
+
};
|
|
20
28
|
|
|
21
29
|
return (
|
|
22
30
|
<View style={overlayStyle} pointerEvents="none">
|
|
23
|
-
<Text>
|
|
31
|
+
<Text style={resolvedBaseTextStyle}>
|
|
24
32
|
{segments.map((segment, index) => {
|
|
25
33
|
if (segment.text.length === 0 && segments.length > 1) {
|
|
26
34
|
return null;
|
|
27
35
|
}
|
|
28
36
|
|
|
29
|
-
const textStyle = segmentToTextStyle(segment,
|
|
37
|
+
const textStyle = segmentToTextStyle(segment, overlayTheme);
|
|
30
38
|
|
|
31
39
|
return (
|
|
32
40
|
<Text
|
|
33
41
|
key={`${index}-${segment.text.slice(0, 8)}`}
|
|
34
|
-
style={
|
|
42
|
+
style={textStyle}
|
|
35
43
|
>
|
|
36
44
|
{segment.text}
|
|
37
45
|
</Text>
|
|
@@ -89,7 +89,10 @@ export const RichTextInput: React.FC<RichTextInputProps> = ({
|
|
|
89
89
|
// Input style
|
|
90
90
|
const inputStyle = [
|
|
91
91
|
styles.textInput,
|
|
92
|
+
resolvedTheme.baseTextStyle ?? DEFAULT_THEME.baseTextStyle,
|
|
92
93
|
resolvedTheme.inputStyle ?? DEFAULT_THEME.inputStyle,
|
|
94
|
+
textInputProps?.style,
|
|
95
|
+
styles.hiddenInputText,
|
|
93
96
|
];
|
|
94
97
|
|
|
95
98
|
// Toolbar component
|
|
@@ -141,11 +144,12 @@ export const RichTextInput: React.FC<RichTextInputProps> = ({
|
|
|
141
144
|
editable={editable}
|
|
142
145
|
maxLength={maxLength}
|
|
143
146
|
autoFocus={autoFocus}
|
|
147
|
+
underlineColorAndroid="transparent"
|
|
144
148
|
selectionColor={
|
|
145
149
|
resolvedTheme.colors?.cursor ?? DEFAULT_THEME.colors?.cursor
|
|
146
150
|
}
|
|
147
151
|
textAlignVertical="top"
|
|
148
|
-
scrollEnabled={
|
|
152
|
+
scrollEnabled={typeof maxHeight === 'number'}
|
|
149
153
|
/>
|
|
150
154
|
</View>
|
|
151
155
|
|
|
@@ -164,11 +168,13 @@ const styles = StyleSheet.create({
|
|
|
164
168
|
position: 'relative',
|
|
165
169
|
},
|
|
166
170
|
textInput: {
|
|
167
|
-
// The TextInput must be transparent so the overlay text shows through.
|
|
168
|
-
// Only the caret/cursor and selection highlight are visible.
|
|
169
|
-
color: 'transparent',
|
|
170
|
-
// Ensure it matches the overlay text positioning exactly.
|
|
171
171
|
position: 'relative',
|
|
172
172
|
zIndex: 1,
|
|
173
173
|
},
|
|
174
|
+
hiddenInputText: {
|
|
175
|
+
// Keep the editable layer invisible while preserving the caret.
|
|
176
|
+
color: 'transparent',
|
|
177
|
+
backgroundColor: 'transparent',
|
|
178
|
+
textShadowColor: 'transparent',
|
|
179
|
+
},
|
|
174
180
|
});
|
|
@@ -20,17 +20,17 @@ export const Toolbar: React.FC<ToolbarProps> = React.memo(
|
|
|
20
20
|
|
|
21
21
|
// Compute active state for each item
|
|
22
22
|
const enrichedItems: ToolbarItem[] = useMemo(() => {
|
|
23
|
+
const selectionStyle = actions.getSelectionStyle();
|
|
24
|
+
|
|
23
25
|
return toolbarItems.map((item) => {
|
|
24
26
|
let isActive = false;
|
|
25
27
|
|
|
26
28
|
if (item.format) {
|
|
27
|
-
|
|
28
|
-
const { activeStyles } = state;
|
|
29
|
-
isActive = !!activeStyles[item.format];
|
|
29
|
+
isActive = actions.isFormatActive(item.format);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
if (item.heading) {
|
|
33
|
-
isActive =
|
|
33
|
+
isActive = selectionStyle.heading === item.heading;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
return {
|
|
@@ -38,7 +38,7 @@ export const Toolbar: React.FC<ToolbarProps> = React.memo(
|
|
|
38
38
|
active: item.active ?? isActive,
|
|
39
39
|
};
|
|
40
40
|
});
|
|
41
|
-
}, [
|
|
41
|
+
}, [actions, toolbarItems]);
|
|
42
42
|
|
|
43
43
|
// Custom render
|
|
44
44
|
if (renderToolbar) {
|
package/src/hooks/useRichText.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { useState, useCallback, useRef
|
|
1
|
+
import { useState, useCallback, useRef } from 'react';
|
|
2
2
|
import type {
|
|
3
3
|
StyledSegment,
|
|
4
|
-
FormatType,
|
|
5
4
|
FormatStyle,
|
|
6
|
-
HeadingLevel,
|
|
7
5
|
SelectionRange,
|
|
8
6
|
RichTextState,
|
|
9
7
|
RichTextActions,
|
|
@@ -16,6 +14,7 @@ import {
|
|
|
16
14
|
reconcileTextChange,
|
|
17
15
|
findPositionInSegments,
|
|
18
16
|
} from '../utils/parser';
|
|
17
|
+
import { getSelectionStyle } from '../utils/formatter';
|
|
19
18
|
import { useSelection } from '../hooks/useSelection';
|
|
20
19
|
import { useFormatting } from '../hooks/useFormatting';
|
|
21
20
|
|
|
@@ -57,6 +56,8 @@ export function useRichText(
|
|
|
57
56
|
// Refs for stable access in callbacks
|
|
58
57
|
const segmentsRef = useRef(segments);
|
|
59
58
|
segmentsRef.current = segments;
|
|
59
|
+
const selectionRef = useRef(selection);
|
|
60
|
+
selectionRef.current = selection;
|
|
60
61
|
const activeStylesRef = useRef(activeStyles);
|
|
61
62
|
activeStylesRef.current = activeStyles;
|
|
62
63
|
|
|
@@ -86,7 +87,11 @@ export function useRichText(
|
|
|
86
87
|
const handleTextChange = useCallback(
|
|
87
88
|
(newText: string) => {
|
|
88
89
|
const currentSegments = segmentsRef.current;
|
|
89
|
-
const
|
|
90
|
+
const currentSelection = selectionRef.current;
|
|
91
|
+
const currentActiveStyles =
|
|
92
|
+
currentSelection.start === currentSelection.end
|
|
93
|
+
? activeStylesRef.current
|
|
94
|
+
: getSelectionStyle(currentSegments, currentSelection);
|
|
90
95
|
|
|
91
96
|
const newSegments = reconcileTextChange(
|
|
92
97
|
currentSegments,
|
|
@@ -161,6 +166,8 @@ export function useRichText(
|
|
|
161
166
|
setFontSize: formatting.setFontSize,
|
|
162
167
|
handleTextChange,
|
|
163
168
|
handleSelectionChange: onSelectionChange,
|
|
169
|
+
isFormatActive: formatting.isFormatActive,
|
|
170
|
+
getSelectionStyle: formatting.currentSelectionStyle,
|
|
164
171
|
getPlainText,
|
|
165
172
|
exportJSON,
|
|
166
173
|
importJSON,
|
package/src/index.d.ts
CHANGED
|
@@ -12,4 +12,4 @@ export { createSegment, segmentsToPlainText, getTotalLength, mergeAdjacentSegmen
|
|
|
12
12
|
export { toggleFormatOnSelection, setStyleOnSelection, setHeadingOnLine, isFormatActiveInSelection, getSelectionStyle, } from './utils/formatter';
|
|
13
13
|
export { formatStyleToTextStyle, segmentToTextStyle, segmentsToTextStyles, } from './utils/styleMapper';
|
|
14
14
|
export { DEFAULT_COLORS, DEFAULT_THEME, DEFAULT_TOOLBAR_ITEMS, DEFAULT_BASE_TEXT_STYLE, HEADING_FONT_SIZES, EMPTY_FORMAT_STYLE, } from './constants/defaultStyles';
|
|
15
|
-
export type { FormatType, HeadingLevel, ListType, FormatStyle, StyledSegment, SelectionRange, RichTextState, RichTextActions, UseRichTextReturn, RichTextTheme, ToolbarItem, OverlayTextProps, ToolbarButtonProps, ToolbarProps, RichTextInputProps, } from './types';
|
|
15
|
+
export type { FormatType, HeadingLevel, ListType, FormatStyle, StyledSegment, SelectionRange, RichTextState, RichTextActions, UseRichTextReturn, RichTextTheme, ToolbarItem, ToolbarButtonRenderProps, ToolbarRenderProps, OverlayTextProps, ToolbarButtonProps, ToolbarProps, RichTextInputProps, } from './types';
|
package/src/index.ts
CHANGED
package/src/types/index.d.ts
CHANGED
|
@@ -75,6 +75,10 @@ export interface RichTextActions {
|
|
|
75
75
|
handleTextChange: (text: string) => void;
|
|
76
76
|
/** Handle selection change from TextInput. */
|
|
77
77
|
handleSelectionChange: (selection: SelectionRange) => void;
|
|
78
|
+
/** Check whether a format is active at the current cursor/selection. */
|
|
79
|
+
isFormatActive: (format: FormatType) => boolean;
|
|
80
|
+
/** Get the effective shared style at the current cursor/selection. */
|
|
81
|
+
getSelectionStyle: () => FormatStyle;
|
|
78
82
|
/** Get the full plain text content. */
|
|
79
83
|
getPlainText: () => string;
|
|
80
84
|
/** Export the segments as a serializable JSON array. */
|
|
@@ -150,11 +154,23 @@ export interface ToolbarItem {
|
|
|
150
154
|
/** Whether this item is currently active. */
|
|
151
155
|
active?: boolean;
|
|
152
156
|
/** Custom render function for the button. */
|
|
153
|
-
renderButton?: (props:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
renderButton?: (props: ToolbarButtonRenderProps) => React.ReactElement | null;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Props passed to a custom toolbar button renderer.
|
|
161
|
+
*/
|
|
162
|
+
export interface ToolbarButtonRenderProps {
|
|
163
|
+
active: boolean;
|
|
164
|
+
onPress: () => void;
|
|
165
|
+
label: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Props passed to a custom toolbar renderer.
|
|
169
|
+
*/
|
|
170
|
+
export interface ToolbarRenderProps {
|
|
171
|
+
items: ToolbarItem[];
|
|
172
|
+
state: RichTextState;
|
|
173
|
+
actions: RichTextActions;
|
|
158
174
|
}
|
|
159
175
|
/**
|
|
160
176
|
* Props for the OverlayText component.
|
|
@@ -197,11 +213,7 @@ export interface ToolbarProps {
|
|
|
197
213
|
/** Whether to show the toolbar. */
|
|
198
214
|
visible?: boolean;
|
|
199
215
|
/** Custom render function for the entire toolbar. */
|
|
200
|
-
renderToolbar?: (props:
|
|
201
|
-
items: ToolbarItem[];
|
|
202
|
-
state: RichTextState;
|
|
203
|
-
actions: RichTextActions;
|
|
204
|
-
}) => React.ReactElement;
|
|
216
|
+
renderToolbar?: (props: ToolbarRenderProps) => React.ReactElement | null;
|
|
205
217
|
}
|
|
206
218
|
/**
|
|
207
219
|
* Props for the main RichTextInput component.
|