import type { RefObject } from 'react';
import type {
ColorValue,
DimensionValue,
NativeMethods,
NativeSyntheticEvent,
ReturnKeyTypeOptions,
TargetedEvent,
TextStyle,
ViewProps,
} from 'react-native';
/**
* Allowed container styles for ``'s `style` prop.
*
* Represents the supported subset of React Native
* [`TextStyle`](https://reactnative.dev/docs/text-style-props).
* Some properties are not supported on all platforms. In such cases a property
* is annotated with a `@platform` directive.
*/
export interface EnrichedInputStyle {
// Layout / FlexStyle
alignSelf?: TextStyle['alignSelf'];
aspectRatio?: number | string;
borderBottomWidth?: number;
borderEndWidth?: number;
borderLeftWidth?: number;
borderRightWidth?: number;
borderStartWidth?: number;
borderTopWidth?: number;
borderWidth?: number;
bottom?: DimensionValue;
boxSizing?: TextStyle['boxSizing'];
display?: TextStyle['display'];
end?: DimensionValue;
flex?: number;
flexBasis?: DimensionValue;
flexGrow?: number;
flexShrink?: number;
height?: DimensionValue;
inset?: DimensionValue;
insetBlock?: DimensionValue;
insetBlockEnd?: DimensionValue;
insetBlockStart?: DimensionValue;
insetInline?: DimensionValue;
insetInlineEnd?: DimensionValue;
insetInlineStart?: DimensionValue;
left?: DimensionValue;
margin?: DimensionValue;
marginBlock?: DimensionValue;
marginBlockEnd?: DimensionValue;
marginBlockStart?: DimensionValue;
marginBottom?: DimensionValue;
marginEnd?: DimensionValue;
marginHorizontal?: DimensionValue;
marginInline?: DimensionValue;
marginInlineEnd?: DimensionValue;
marginInlineStart?: DimensionValue;
marginLeft?: DimensionValue;
marginRight?: DimensionValue;
marginStart?: DimensionValue;
marginTop?: DimensionValue;
marginVertical?: DimensionValue;
maxHeight?: DimensionValue;
maxWidth?: DimensionValue;
minHeight?: DimensionValue;
minWidth?: DimensionValue;
padding?: DimensionValue;
paddingBlock?: DimensionValue;
paddingBlockEnd?: DimensionValue;
paddingBlockStart?: DimensionValue;
paddingBottom?: DimensionValue;
paddingEnd?: DimensionValue;
paddingHorizontal?: DimensionValue;
paddingInline?: DimensionValue;
paddingInlineEnd?: DimensionValue;
paddingInlineStart?: DimensionValue;
paddingLeft?: DimensionValue;
paddingRight?: DimensionValue;
paddingStart?: DimensionValue;
paddingTop?: DimensionValue;
paddingVertical?: DimensionValue;
position?: TextStyle['position'];
right?: DimensionValue;
start?: DimensionValue;
top?: DimensionValue;
width?: DimensionValue;
zIndex?: number;
// Shadows
/** @platform ios */
shadowColor?: ColorValue;
/** @platform ios */
shadowOffset?: TextStyle['shadowOffset'];
/** @platform ios */
shadowOpacity?: TextStyle['shadowOpacity'];
/** @platform ios */
shadowRadius?: number;
// Transforms
transform?: TextStyle['transform'];
transformOrigin?: TextStyle['transformOrigin'];
// View appearance
/** @platform ios web */
backfaceVisibility?: TextStyle['backfaceVisibility'];
backgroundColor?: ColorValue;
/** @platform ios web */
borderBlockColor?: ColorValue;
/** @platform ios web */
borderBlockEndColor?: ColorValue;
/** @platform ios web */
borderBlockStartColor?: ColorValue;
/** @platform ios web */
borderBottomColor?: ColorValue;
/** @platform ios web */
borderBottomEndRadius?: TextStyle['borderBottomEndRadius'];
/** @platform ios web */
borderBottomLeftRadius?: TextStyle['borderBottomLeftRadius'];
/** @platform ios web */
borderBottomRightRadius?: TextStyle['borderBottomRightRadius'];
/** @platform ios web */
borderBottomStartRadius?: TextStyle['borderBottomStartRadius'];
/** @platform ios web */
borderColor?: ColorValue;
/** @platform ios web */
borderEndColor?: ColorValue;
/** @platform ios web */
borderEndEndRadius?: TextStyle['borderEndEndRadius'];
/** @platform ios web */
borderEndStartRadius?: TextStyle['borderEndStartRadius'];
/** @platform ios web */
borderLeftColor?: ColorValue;
/** @platform ios web */
borderRadius?: TextStyle['borderRadius'];
/** @platform ios web */
borderRightColor?: ColorValue;
/** @platform ios web */
borderStartColor?: ColorValue;
/** @platform ios web */
borderStartEndRadius?: TextStyle['borderStartEndRadius'];
/** @platform ios web */
borderStartStartRadius?: TextStyle['borderStartStartRadius'];
/** @platform ios web */
borderStyle?: TextStyle['borderStyle'];
/** @platform ios web */
borderTopColor?: ColorValue;
/** @platform ios web */
borderTopEndRadius?: TextStyle['borderTopEndRadius'];
/** @platform ios web */
borderTopLeftRadius?: TextStyle['borderTopLeftRadius'];
/** @platform ios web */
borderTopRightRadius?: TextStyle['borderTopRightRadius'];
/** @platform ios web */
borderTopStartRadius?: TextStyle['borderTopStartRadius'];
boxShadow?: TextStyle['boxShadow'];
/** @platform web */
cursor?: TextStyle['cursor'];
/** @platform android */
elevation?: number;
/** @platform android web */
filter?: TextStyle['filter'];
/** @platform android web */
mixBlendMode?: TextStyle['mixBlendMode'];
opacity?: TextStyle['opacity'];
/** @platform ios web */
outlineColor?: ColorValue;
outlineOffset?: TextStyle['outlineOffset'];
/** @platform android web */
outlineStyle?: TextStyle['outlineStyle'];
outlineWidth?: TextStyle['outlineWidth'];
/** @platform ios web */
pointerEvents?: TextStyle['pointerEvents'];
// Typography
color?: ColorValue;
fontFamily?: string;
fontSize?: number;
fontStyle?: TextStyle['fontStyle'];
fontWeight?: TextStyle['fontWeight'];
lineHeight?: number;
/** @platform web */
letterSpacing?: number;
}
interface HeadingStyle {
fontSize?: number;
bold?: boolean;
}
export interface MentionStyleProperties {
color?: ColorValue;
backgroundColor?: ColorValue;
textDecorationLine?: 'underline' | 'none';
}
export interface HtmlStyle {
h1?: HeadingStyle;
h2?: HeadingStyle;
h3?: HeadingStyle;
h4?: HeadingStyle;
h5?: HeadingStyle;
h6?: HeadingStyle;
blockquote?: {
borderColor?: ColorValue;
borderWidth?: number;
gapWidth?: number;
color?: ColorValue;
};
codeblock?: {
color?: ColorValue;
borderRadius?: number;
backgroundColor?: ColorValue;
};
code?: {
color?: ColorValue;
backgroundColor?: ColorValue;
};
a?: {
color?: ColorValue;
textDecorationLine?: 'underline' | 'none';
};
mention?: Record | MentionStyleProperties;
ol?: {
gapWidth?: number;
marginLeft?: number;
markerFontWeight?: TextStyle['fontWeight'];
markerColor?: ColorValue;
};
ul?: {
bulletColor?: ColorValue;
bulletSize?: number;
marginLeft?: number;
gapWidth?: number;
};
ulCheckbox?: {
boxSize?: number;
gapWidth?: number;
marginLeft?: number;
boxColor?: ColorValue;
};
}
export type TextShortcutStyle =
| 'bold'
| 'italic'
| 'underline'
| 'strikethrough'
| 'inline_code'
| 'h1'
| 'h2'
| 'h3'
| 'h4'
| 'h5'
| 'h6'
| 'blockquote'
| 'codeblock'
| 'unordered_list'
| 'ordered_list'
| 'checkbox_list';
export interface TextShortcut {
trigger: string;
style: TextShortcutStyle;
}
// Event types
export interface OnChangeTextEvent {
value: string;
}
export interface OnChangeHtmlEvent {
value: string;
}
export interface OnChangeStateEvent {
bold: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
italic: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
underline: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
strikeThrough: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
inlineCode: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
h1: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
h2: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
h3: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
h4: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
h5: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
h6: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
codeBlock: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
blockQuote: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
orderedList: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
unorderedList: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
link: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
image: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
mention: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
checkboxList: {
isActive: boolean;
isConflicting: boolean;
isBlocking: boolean;
};
alignment: string;
}
export interface OnLinkDetected {
text: string;
url: string;
start: number;
end: number;
}
export interface OnMentionDetected {
text: string;
indicator: string;
attributes: Record;
}
export interface OnChangeSelectionEvent {
start: number;
end: number;
text: string;
}
export interface OnKeyPressEvent {
key: string;
}
export interface OnPasteImagesEvent {
images: {
uri: string;
type: string;
width: number;
height: number;
}[];
}
export interface OnSubmitEditing {
text: string;
}
// Component types
export type FocusEvent = NativeSyntheticEvent;
export type BlurEvent = NativeSyntheticEvent;
export interface EnrichedTextInputInstance extends NativeMethods {
// General commands
focus: () => void;
blur: () => void;
setValue: (value: string) => void;
setSelection: (start: number, end: number) => void;
getHTML: () => Promise;
// Text formatting commands
toggleBold: () => void;
toggleItalic: () => void;
toggleUnderline: () => void;
toggleStrikeThrough: () => void;
toggleInlineCode: () => void;
toggleH1: () => void;
toggleH2: () => void;
toggleH3: () => void;
toggleH4: () => void;
toggleH5: () => void;
toggleH6: () => void;
toggleCodeBlock: () => void;
toggleBlockQuote: () => void;
toggleOrderedList: () => void;
toggleUnorderedList: () => void;
toggleCheckboxList: (checked: boolean) => void;
setLink: (start: number, end: number, text: string, url: string) => void;
removeLink: (start: number, end: number) => void;
setImage: (src: string, width: number, height: number) => void;
startMention: (indicator: string) => void;
setMention: (
indicator: string,
text: string,
attributes?: Record
) => void;
setTextAlignment: (
alignment: 'left' | 'center' | 'right' | 'justify' | 'auto'
) => void;
}
export interface ContextMenuItem {
text: string;
onPress: ({
text,
selection,
styleState,
}: {
text: string;
selection: { start: number; end: number };
styleState: OnChangeStateEvent;
}) => void;
visible?: boolean;
}
export interface OnChangeMentionEvent {
indicator: string;
text: string;
}
export interface EnrichedTextInputProps extends Omit {
ref?: RefObject;
autoFocus?: boolean;
editable?: boolean;
mentionIndicators?: string[];
defaultValue?: string;
placeholder?: string;
placeholderTextColor?: ColorValue;
cursorColor?: ColorValue;
selectionColor?: ColorValue;
autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters';
htmlStyle?: HtmlStyle;
style?: EnrichedInputStyle;
scrollEnabled?: boolean;
linkRegex?: RegExp | null;
returnKeyType?: ReturnKeyTypeOptions;
returnKeyLabel?: string;
submitBehavior?: 'submit' | 'blurAndSubmit' | 'newline';
onFocus?: (e: FocusEvent) => void;
onBlur?: (e: BlurEvent) => void;
onChangeText?: (e: NativeSyntheticEvent) => void;
onChangeHtml?: (e: NativeSyntheticEvent) => void;
onChangeState?: (e: NativeSyntheticEvent) => void;
onLinkDetected?: (e: OnLinkDetected) => void;
onMentionDetected?: (e: OnMentionDetected) => void;
onStartMention?: (indicator: string) => void;
onChangeMention?: (e: OnChangeMentionEvent) => void;
onEndMention?: (indicator: string) => void;
onChangeSelection?: (e: NativeSyntheticEvent) => void;
onKeyPress?: (e: NativeSyntheticEvent) => void;
onSubmitEditing?: (e: NativeSyntheticEvent) => void;
/**
* Web: each `images[].uri` is a `blob:` URL from `URL.createObjectURL`. If you keep
* URIs around (or replace them after upload), call `URL.revokeObjectURL(uri)` when done
* to avoid retaining blob memory. Native uses non-blob URIs; revoke does not apply.
*/
onPasteImages?: (e: NativeSyntheticEvent) => void;
contextMenuItems?: ContextMenuItem[];
textShortcuts?: TextShortcut[];
/**
* If true, Android will use experimental synchronous events.
* This will prevent from input flickering when updating component size.
* However, this is an experimental feature, which has not been thoroughly tested.
* We may decide to enable it by default in a future release.
* Disabled by default.
*/
androidExperimentalSynchronousEvents?: boolean;
/**
* If true, external HTML (e.g. from Google Docs, Word, web pages) will be
* normalized through the HTML normalizer before being applied.
* This converts arbitrary HTML into the canonical tag subset that the enriched
* parser understands.
* Disabled by default.
*/
useHtmlNormalizer?: boolean;
/**
* If true, fonts will scale to respect the system's accessibility text size.
* Enabled by default.
*/
allowFontScaling?: boolean;
}
export interface EnrichedTextInstance extends NativeMethods {}
export interface EnrichedTextProps extends ViewProps {
ref?: RefObject;
children: string;
style?: TextStyle;
htmlStyle?: EnrichedTextHtmlStyle;
useHtmlNormalizer?: boolean;
ellipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
numberOfLines?: number;
selectable?: boolean;
selectionColor?: ColorValue;
/**
* If true, fonts will scale to respect the system's accessibility text size.
* Enabled by default.
*/
allowFontScaling?: boolean;
onLinkPress?: (event: OnLinkPressEvent) => void;
onMentionPress?: (event: OnMentionPressEvent) => void;
}
interface EnrichedTextMentionStyleProperties extends MentionStyleProperties {
pressColor?: ColorValue;
pressBackgroundColor?: ColorValue;
}
export interface EnrichedTextHtmlStyle
extends Omit {
a?: HtmlStyle['a'] & {
pressColor?: ColorValue;
};
mention?:
| Record
| EnrichedTextMentionStyleProperties;
}
export interface OnLinkPressEvent {
url: string;
}
export interface OnMentionPressEvent {
text: string;
indicator: string;
attributes: Record;
}