@vandrei977/react-native-render-html
Version:
The hackable, full-featured Open Source HTML rendering solution for React Native.
1,147 lines • 38.5 kB
TypeScript
import type { AccessibilityProps, GestureResponderEvent, StyleProp, TextProps, TextStyle, TouchableHighlightProps, ViewProps, ViewStyle } from 'react-native';
import type { CSSPropertyNameList, Document, DocumentContext as TREDocumentContext, DomVisitorCallbacks, Element, EmbeddedTagNames, HTMLContentModel, HTMLElementModel, MixedStyleDeclaration, MixedStyleRecord, NativeBlockStyles, NativeTextStyles, Node, NodeWithChildren, SetMarkersForTNode, StylessReactNativeProps, TDocument, TNode, TPhrasing, TRenderEngineOptions, TText } from '@native-html/transient-render-engine';
import type { CounterStyleRenderer } from '@jsamr/counter-style';
import type { ComponentType, ReactElement, ReactNode } from 'react';
import type { CustomTagRendererRecord } from './render/render-types';
import type { ParserOptions as HtmlParserOptions } from 'htmlparser2';
/**
* A record of HTMLElementModels.
*
* @public
*/
export type HTMLElementModelRecord = Record<string, HTMLElementModel<string, HTMLContentModel>>;
/**
* @public
*/
export interface ImageDimensions {
height: number;
width: number;
}
/**
* Props for custom Pressable components.
*
* @public
*/
export interface GenericPressableProps extends AccessibilityProps {
borderless?: boolean;
onPress?: TouchableHighlightProps['onPress'];
style?: StyleProp<ViewStyle>;
}
/**
* Configuration for ol and ul.
*
* @public
*/
export interface ListElementConfig {
/**
* When `true`, the width of the marker box will be adapted depending on
* `fontSize` and the highest number of characters in the printed range.
*
* If this length is superior than the left (or right in ltr mode) padding,
* a supplemental space will be added before every list child.
*
* When `false`, the left (or right in ltr mode) padding will be invariable.
*
* @defaultValue false
*/
enableDynamicMarkerBoxWidth?: boolean;
/**
* If `true` and the direction is set to `'rtl'` (either via `dir` attribute
* or `direction` CSS property):
*
* - lists markers will be flushed to the right when `I18nManager.isRtl` is `false`.
* - list markers prefixes and suffixes print order will be reversed.
*
* @remarks Beware that left and right padding of li elements *will not*
* be switched.
*
* @defaultValue false
*/
enableExperimentalRtl?: boolean;
/**
* Remove bottom margin if this element parent is an `li` element and it
* is its last child.
*
* @defaultValue true
*/
enableRemoveBottomMarginIfNested?: boolean;
/**
* Remove top margin if this element parent is an `li` element and it
* is its first child.
*
* @defaultValue true
*/
enableRemoveTopMarginIfNested?: boolean;
/**
* Get default list-style-type given the number of nest level for this list.
*
* @remarks This function will not be used when a list element has its own
* `list-style-type` CSS property, or has inherited this property from
* parents.
*
* @param nestLevel - The number of parents elements with the same tag name.
*/
getFallbackListStyleTypeFromNestLevel?: (nestLevel: number) => DefaultSupportedListStyleType;
/**
* Customize the marker box appearance (the `View` containing the marker,
* e.g. the symbol prefixing list elements).
*
* @remarks This is useful to set some right padding or a different background for example.
*
* @warning **Do not**:
* - Use margin (since the width will match the `<ol>` / `<ul>` padding left)
* - Set width constraints (since the width will match the `<ol>` / `<ul>` padding left)
*/
markerBoxStyle?: StyleProp<ViewStyle>;
/**
* Customize the marker text appearance (the `Text` component in which the marker,
* e.g. the symbol prefixing list elements).
*
* @remarks Useful to set the color, fontFamily, fontSize of the marker.
* Avoid using padding here, take advantage of `markerBoxStyle` instead.
*
* @warning This style must be a style object! Arrays, and `Stylesheet` styles will not work.
*/
markerTextStyle?: TextStyle;
}
/**
* Props for custom renderers. The convention is to declare a field per tag name.
* In doing so, you can benefit from `useRendererProps('tagname')` in custom renderers.
*
* @remarks **Typescript users**: If you need to add fields to the {@link RenderersProps} interface,
* you should use {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation | module augmentation}:
*
* ```ts
* declare module 'react-native-render-html' {
* interface RenderersProps {
* div?: {
* customProp: boolean;
* };
* }
* }
* @public
*/
export interface RenderersProps extends Record<string, any> {
a: {
/**
* A callback to handle anchors presses.
*
* @remarks The `href` argument has been normalized, see {@link useNormalizedUrl}.
*
* @defaultValue A function using React Native `Linking.onpenUrl`.
* @param event - The {@link GestureResponderEvent} event.
* @param href - The normalized href, see {@link useNormalizedUrl}.
* @param htmlAttribs - The attributes of the underlying {@link Element}.
* @param target - The normalized `target` for this hyperlink.
*/
onPress?: (event: GestureResponderEvent, href: string, htmlAttribs: Record<string, string>, target: '_blank' | '_self' | '_parent' | '_top') => void;
};
img: {
/**
* Support for relative percent-widths.
*
* @defaultValue false
*/
enableExperimentalPercentWidth?: boolean;
/**
* Default width and height to display while image's dimensions are being retrieved.
*
* @remarks Changes to this prop will cause a react tree update. Always
* memoize it.
*/
initialDimensions?: ImageDimensions;
};
ol: ListElementConfig;
ul: ListElementConfig;
}
/**
* Props passed to internal and custom renderers.
*
* @public
*/
export interface RenderHTMLPassedProps {
/**
* Props to use in custom renderers with `useRendererProps`.
*
* @remarks
* - When you use the hook, you'll get this object deep-merged with default renderers props.
* - **Typescript users**: If you need to add fields to the {@link RenderersProps} interface,
* you should use {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation | module augmentation}:
*
* ```ts
* declare module 'react-native-render-html' {
* interface RenderersProps {
* div?: {
* customProp: boolean;
* };
* }
* }
* ```
*/
renderersProps?: Partial<RenderersProps>;
}
/**
* A map which defines the type of parameters passed as third argument
* of {@link EmbeddedHeadersProvider}.
*/
export interface EmbeddedWithHeadersParamsMap extends Record<EmbeddedWithHeadersTagName, Record<string, unknown>> {
img: {
/**
* The print height of the image in DPI, if it can be determined beforehand
* (for example, with a _height_ attribute set or an inline style).
*/
printHeight?: number;
/**
* The print width of the image in DPI, if it can be determined beforehand
* (for example, with a _width_ attribute set or an inline style).
*/
printWidth?: number;
};
}
/**
* Tag names eligible for headers provision.
*/
export type EmbeddedWithHeadersTagName = Exclude<EmbeddedTagNames, 'svg' | 'canvas' | 'math'>;
/**
* A function to provide headers to a peculiar embedded element.
*/
export type EmbeddedHeadersProvider = <T extends EmbeddedWithHeadersTagName>(uri: string, tagName: T, params: EmbeddedWithHeadersParamsMap[T]) => Record<string, string> | null | void;
/**
* Props shared across renderers.
*
* @warning Shared props changes will cause all the React tree to invalidate. You should
* always memoize these.
*
* @public
*/
export interface RenderHTMLSharedProps {
/**
* A component used to wrap pressable elements (e.g. when provided `onPress`).
* Note that textual elements will not be wrapped; `TextProps.onPress` will
* be used instead.
*
* @defaultValue A `TouchableNativeFeedback` based component on Android, `TouchableHighlight` based component on other platforms.
*/
GenericPressable?: ComponentType<GenericPressableProps>;
/**
* The WebView component used by plugins (iframe, table)...
* See {@link https://github.com/native-html/plugins | @native-html/plugins}.
*
* @defaultValue `() => null`
*/
WebView?: ComponentType<any>;
/**
* When `true` (default), anonymous {@link TPhrasing} nodes parents of a
* lonely {@link TText} node are not translated as React Native `Text`
* elements. Instead, their child is directly rendered, e.g. with no `Text`
* wrapper.
*
* @example **With `true`:**
*
* ```xml
* <TPhrasing>
* <TText>Hello</TText>
* </TPhrasing>
* ```
*
* is translated to
*
* ```xml
* <Text>Hello</Text>
* ```
*
* **With `false`:**
*
* ```xml
* <TPhrasing>
* <TText>Hello</TText>
* </TPhrasing>
* ```
*
* is translated to
*
* ```xml
* <Text><Text>Hello</Text></Text>
* ```
*
* @warning Unless strictly necessary, this should be left to `true` because
* some styles don't apply to nested React Native `Text` elements
* (`borderRadius`, `padding`...).
*
* @defaultValue true
*/
bypassAnonymousTPhrasingNodes?: boolean;
/**
* A function which takes contentWidth and tagName as arguments and returns a
* new width. Can return Infinity to denote unconstrained widths.
*
* @param contentWidth - The available width in this {@link RenderHTML} component.
* @param tagName - The tagName of this element to render, e.g. "img".
*
* @remarks
* - Take advantage of {@link useComputeMaxWidthForTag} hook inside custom
* renderers to get the maximum width for this tag.
* - Changes to this prop will cause a react tree update. Always
* memoize it.
*
* @defaultValue `(c) => c`
*/
computeEmbeddedMaxWidth?: (contentWidth: number, tagName: string) => number;
/**
* Provide support for list style types which are not supported by this
* library.
*
* @remarks Check the numerous presets provided by
* {@link https://github.com/jsamr/react-native-li/tree/master/packages/counter-style#readme | @jsamr/counter-style}
* as they require zero-effort!
*
* @example
*
* ```js
* import hebrew from '@jsamr/counter-style/presets/hebrew';
*
* const customListStyleSpecs = {
* hebrew: {
* type: 'textual',
* counterStyleRenderer: hebrew
* }
* };
* ```
*/
customListStyleSpecs?: Record<string, ListStyleSpec>;
/**
* Log to the console a snapshot of the rendered {@link TDocument} after each
* transient render tree invalidation.
*
* @defaultValue `false`
*/
debug?: boolean;
/**
* Default props for Text elements in the render tree.
*
* @remarks "style" will be merged into the tnode own styles.
*/
defaultTextProps?: TextProps;
/**
* Default props for View elements in the render tree.
*
* @remarks "style" will be merged into the tnode own styles.
*/
defaultViewProps?: ViewProps;
/**
* Default props for WebView elements in the render tree used by plugins.
*/
defaultWebViewProps?: any;
/**
* Follow closely the HTML standard and ignore `<br>` tags closing an
* inline formatting context.
*
* @example
*
* ```html
* <p>
* Hello<br />
* </p>
* ```
*
* When this flag is set to `true`, one line is printed instead of two on
* native platforms, which is the HTML-compliant behavior.
*
* @defaultValue false
*
* @remarks Recommended value is `true` on non-web platforms. Also note that
* this is an experimental feature, thus subject to behavioral instability.
*/
enableExperimentalBRCollapsing?: boolean;
/**
* React Native doesn't handle lines like we would expect on a web browser.
* For example:
* ```jsx
* <View>
* <Text></Text>
* </View>
* ```
* will span 20 dpi in height. Setting this prop to `true` will make
* the renderer take those React Native oddities into account.
* See also this ticket: https://git.io/JErwX
*
* @remarks This is an experimental feature, thus subject to behavioral
* instability.
*
* @defaultValue false
*/
enableExperimentalGhostLinesPrevention?: boolean;
/**
* Enable or disable margin collapsing CSS behavior (experimental!).
* See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing | MDN docs}.
*
* @remarks Limitations:
* - Only adjacent siblings collapsing is implemented.
* - If one of the margins height is in percent, no collapsing will occur.
* - Will apply indiscriminately to all `display` properties (including
* flex), which is not standard.
* - Might not work well with {@link TPhrasing} nodes having only one child.
*
* This is an experimental feature, thus subject to behavioral instability.
*
* @defaultValue false
*/
enableExperimentalMarginCollapsing?: boolean;
handleSelection?: (content: any) => void;
handleWordTap?: (searchkey: string, word: string) => void;
shouldHandleTap?: boolean;
/**
* Color used for pressable items, either for the ripple effect (Android), or
* highlight (other platforms).
*
* @defaultValue rgba(38, 132, 240, 0.2)
*/
pressableHightlightColor?: string;
/**
* Provide headers for specific embedded elements, such as images, iframes...
*
* @example
*
* ```js
* function provideEmbeddedHeaders(uri, tagName, params) {
* if (tagName === "img" &&
* uri.startsWith("https://example.com")) {
* return {
* Authorization: "Bearer daem6QuaeloopheiD7Oh"
* }
* }
*
* // ...
*
* <RenderHTML provideEmbeddedHeaders={provideEmbeddedHeaders} />
* ```
*/
provideEmbeddedHeaders?: EmbeddedHeadersProvider;
}
type SharedPropsWithoutFallback = Exclude<keyof RenderHTMLSharedProps, 'provideEmbeddedHeaders' | 'GenericPressable' | 'customListStyleSpecs'>;
/**
* Shared props available with {@link useSharedProps} hook or `sharedProp`
* custom renderers prop.
*/
export type RenderHTMLAmbiantSharedProps = Required<Pick<RenderHTMLSharedProps, SharedPropsWithoutFallback>> & Omit<RenderHTMLSharedProps, SharedPropsWithoutFallback>;
/**
* Configuration for the {@link TRenderEngineProvider} component.
*
* @warning When one of these props changes, it will cause the
* {@link TRenderEngine} to be rebuilt, and all transient trees to be
* re-assembled. Beware!
*
* @public
*/
export interface TRenderEngineConfig {
/**
* Whitelist specific inline CSS style properties and ignore the others.
*
* @warning Property names must be camelCased: for example, `background-color`
* should be written `backgroundColor`.
*/
allowedStyles?: CSSPropertyNameList;
/**
* The default style for the document (root). Inheritable styles will be
* transferred to children. That works also for textual styles.
*
* @warning **Do NOT** use the `StyleSheet` API to create those styles.
*
* @remarks Any `fontFamily` used in those styles must be registered with
* {@link TRenderEngineConfig.systemFonts} prop.
*/
baseStyle?: MixedStyleDeclaration;
/**
* Provide mixed styles to target elements selected by CSS classes.
*
* @warning **Do NOT** use the `StyleSheet` API to create those styles.
*
* @remarks Any `fontFamily` used in those styles must be registered with
* {@link TRenderEngineConfig.systemFonts} prop.
*/
classesStyles?: MixedStyleRecord;
/**
* Customize element models for target tags.
*/
customHTMLElementModels?: HTMLElementModelRecord;
/**
* **Experimental**
*
* Disable hoisting. Especially useful for rendering with react-native-web.
* Note that your layout might break in native!
*
* @defaultValue false
*/
dangerouslyDisableHoisting?: boolean;
/**
* **Experimental**
*
* Disable whitespace collapsing. Especially useful if your html is
* being pre-processed server-side with a minifier.
*
* @defaultValue false
*/
dangerouslyDisableWhitespaceCollapsing?: boolean;
/**
* An object which callbacks will be invoked when a DOM element or text node
* has been parsed and its children attached. This is great to tamper the dom,
* remove children, insert nodes, change text nodes data... etc.
*
* @remark Each callback is applied during DOM parsing, thus with very little
* overhead. However, it means that one node next siblings won't be available
* since it has not yet been parsed. If you need some siblings logic, apply
* this logic to the children of this node.
*/
domVisitors?: DomVisitorCallbacks;
/**
* The default value in pixels for 1em.
*/
emSize?: number;
/**
* Enable or disable inline CSS processing of inline styles.
*
* @remarks If you want to allow or disallow specific properties, use
* `allowedStyles` or `ignoredStyles` props.
*
* @defaultValue true
*/
enableCSSInlineProcessing?: boolean;
/**
* Enable or disable fallback styles for each tag. For example, `pre` tags
* will have `whiteSpace` set to 'pre' by default.
*
* @defaultValue true
*/
enableUserAgentStyles?: boolean;
/**
* A record for specific CSS fonts.
*
* @remarks Use `Plaform.select({ ios: ..., android: ..., default: ...})`.
*/
fallbackFonts?: FallbackFontsDefinitions;
/**
* ParserOptions for {@link https://github.com/fb55/htmlparser2/wiki/Parser-options | htmlparser2}.
*
* @defaultValue `{ decodeEntities: true }`
*/
htmlParserOptions?: HtmlParserOptions;
/**
* Provide mixed styles to target elements identified by the `id` attribute.
*
* @warning **Do NOT** use the `StyleSheet` API to create those styles.
*
* @remarks Any `fontFamily` used in those styles must be registered with
* {@link TRenderEngineConfig.systemFonts} prop.
*/
idsStyles?: MixedStyleRecord;
/**
* Ignore specific DOM nodes.
*
* @warning When this function is invoked, the node has not yet been attached
* to its parent or siblings. Use the second argument (`parent`) if you
* need to perform logic based on parent.
*
* @remarks
* - The function is applied during DOM parsing, thus with very little
* overhead. However, it means that one node next siblings won't be
* available since it has not yet been parsed.
* - Use `ignoredDomTags` if you just need to target specific tag names.
*
* @returns `true` if this node should not be included in the DOM, anything
* else otherwise.
*
* @param node - The node to check. Beware the parent node is not accessible. Use the second argument.
* @param parent - The parent node.
*/
ignoreDomNode?: (node: Node, parent: NodeWithChildren) => boolean | void | unknown;
/**
* A list of **lowercase tags** which should not be included in the DOM.
*
* @remark The filtering is happening during parsing, thus with very little
* overhead.
*/
ignoredDomTags?: string[];
/**
* Blacklist specific inline CSS style properties and allow the others.
*
* @warning Property names must be camelCased: for example, `background-color`
* should be written `backgroundColor`.
*
* @remarks Note that if you don't want inline style processing at all, you
* should set `enableCSSInlineProcessing` prop to `false`.
*/
ignoredStyles?: CSSPropertyNameList;
/**
* Select the DOM root before TTree generation. For example, you could
* iterate over children until you reach an article element and return this
* element.
*
* @remarks Applied after DOM parsing, before normalization and TTree
* construction. Before normalization implies that a body will be added in
* the tree **after** selecting root.
*/
selectDomRoot?: TRenderEngineOptions['selectDomRoot'];
/**
* Set custom markers from a {@link TNode} and all its descendants. {@link Markers} will be
* accessible in custom renderers via `tnode.markers` prop.
*
* @param targetMarkers - The markers to modify.
* @param parentMarkers - {@link Markers} from the parent {@link TNode}.
* @param tnode - The {@link TNode} to inspect.
*
* @defaultValue `() => null`
*/
setMarkersForTNode?: SetMarkersForTNode;
/**
* A list of fonts available in the current platform. These fonts will be used
* to select the first match in CSS `fontFamily` property, which supports a
* comma-separated list of fonts. By default, a handful of fonts are selected
* per platform.
*
* @remarks
* - You need to specify any font family you wish to use via `*styles` props
* here, otherwise those styles will be ignored.
* - If you are using expo, you should use or extend `Constants.systemFonts`.
*
* @example
* ```tsx
* import RenderHTML, {defaultSystemFonts} from 'react-native-render-html'
* // Replace defaultSystemFonts with Constants.systemFonts if you're using expo
* const systemFonts = [...defaultSystemFonts, 'Mysuperfont']
* // ...
* <RenderHTML systemFonts={systemFonts} ... />
* ```
*/
systemFonts?: string[];
/**
* Provide mixed styles to target HTML tag names.
*
* @warning **Do NOT** use the `StyleSheet` API to create those styles.
*
* @remarks Any `fontFamily` used in those styles must be registered with
* {@link TRenderEngineConfig.systemFonts} prop.
*/
tagsStyles?: MixedStyleRecord;
}
/**
* A source represented by a URI.
*
* @public
*/
export interface HTMLSourceUri {
/**
* The HTTP body to send with the request. This must be a valid
* UTF-8 string, and will be sent exactly as specified, with no
* additional encoding (e.g. URL-escaping or base64) applied.
*/
body?: string;
/**
* Additional HTTP headers to send with the request.
*/
headers?: Record<string, string>;
/**
* The HTTP Method to use. Defaults to GET if not specified.
*/
method?: string;
/**
* The URI to load in the `HTML` component. Can be a local or remote file.
*/
uri: string;
}
/**
* A source which content is provided in-place.
*
* @public
*/
export interface HTMLSourceInline {
/**
* The base URL to resolve relative URLs in the HTML code.
* See {@link useNormalizedUrl}.
*/
baseUrl?: string;
/**
* A static HTML page to display in the HTML component.
*/
html: string;
}
/**
* A source which content is a DOM tree created by the transient render
* engine `parseDocument` method.
*
* See {@link useAmbientTRenderEngine}.
*
* @remarks When you use a DOM source, the `onHTMLLoaded` callback will never
* be invoked for this source, since the source loader hasn't access to the
* HTML source of the DOM.
*
* @public
*/
export interface HTMLSourceDom {
/**
* The base URL to resolve relative URLs in the HTML code.
* See {@link useNormalizedUrl}.
*/
baseUrl?: string;
/**
* A DOM object. This object **must** have been created with
* the transient render engine `parseDocument` method.
*/
dom: Element | Document;
}
/**
* The source to render.
*
* @public
*/
export type HTMLSource = HTMLSourceInline | HTMLSourceDom | HTMLSourceUri;
/**
*
* Props for the {@link RenderHTMLConfigProvider} component.
*
* @public
*/
export interface RenderHTMLConfig extends RenderHTMLSharedProps, RenderHTMLPassedProps {
/**
* Replace the default error if a remote website's content could not be fetched.
*/
remoteErrorView?: (source: HTMLSourceUri) => ReactElement;
/**
* Replace the default loader while fetching a remote website's content.
*/
remoteLoadingView?: (source: HTMLSourceUri) => ReactElement;
/**
* Your custom renderers.
*
* @remarks
*
* **TypeScript users**: To have intellisense for custom renderers, explicitly
* set your custom renderer type to one of {@link CustomBlockRenderer},
* {@link CustomTextualRenderer} or {@link CustomMixedRenderer} depending
* on the {@link HTMLContentModel} defined for this tag (see example below).
*
* @example
*
* A custom renderer for `<div>` tags which trigger an alert on press.
*
* ```tsx
* import React from 'react';
* import RenderHTML, { CustomBlockRenderer } from 'react-native-render-html';
* import { Alert } from 'react-native';
*
* const onPress = () => Alert.alert("I pressed a div!");
*
* // (TypeScript) Notice the type for intellisense
* const DivRenderer: CustomBlockRenderer = function DivRenderer({ TDefaultRenderer, ...props }) {
* return <TDefaultRenderer {...props} onPress={onPress} />;
* }
*
* const renderers = { div: DivRenderer }
*
* //
*
* return <RenderHTML renderers={renderers} />
* ```
*/
renderers?: CustomTagRendererRecord;
}
/**
* Props for the {@link RenderHTMLSource} component.
*
* @public
*/
export interface RenderHTMLSourceProps {
/**
* The width of the HTML content to display. The recommended practice is to pass
* `useWindowDimensions().width` minus any padding or margins.
*
* @defaultValue `Dimensions.get('window').width`
*/
contentWidth?: number;
/**
* Handler invoked when the document metadata is available. It will
* re-trigger on HTML content changes.
*/
onDocumentMetadataLoaded?: (documentMetadata: DocumentMetadata) => void;
/**
* Triggered when HTML is available to the RenderHTML component.
*/
onHTMLLoaded?: (html: string) => void;
/**
* Triggered when the transient render tree changes. Useful for debugging.
*/
onTTreeChange?: (ttree: TDocument) => void;
/**
* The object source to render (either `{ uri }`, `{ html }` or `{ dom }`).
*/
source: HTMLSource;
}
/**
* Props for the {@link RenderHTML} component.
*
* @public
*/
export interface RenderHTMLProps extends RenderHTMLConfig, RenderHTMLSourceProps, TRenderEngineConfig {
}
/**
* An object which keys are keyword font names, and values system fonts.
*
* @public
*/
export interface FallbackFontsDefinitions {
monospace: string;
'sans-serif': string;
serif: string;
}
/**
* Props passed from parents to children.
*
*
* @remarks Anonymous nodes will pass those props from their parents to
* children.
*
*/
export interface PropsFromParent extends Record<string, any> {
collapsedMarginTop: number | null;
}
/**
* Props to render a child.
*
* @public
*/
export interface TChildProps {
/**
* The child element.
*/
childElement: ReactElement;
/**
* The child associated {@link TNode}.
*/
childTnode: TNode;
/**
* The position relative to parent.
*/
index: number;
/**
* The React `key`.
*/
key: string | number;
/**
* Props that have been set via
* {@link TChildrenRendererProps.propsForChildren}.
*/
propsFromParent: PropsFromParent;
}
/**
* Common props for TChildren rendering logic.
*
* @public
*/
export interface TChildrenBaseProps {
/**
* When {@link RenderHTMLProps.enableExperimentalMarginCollapsing} is
* enabled, this prop will be true by default. But you can opt-out when
* rendering children.
*/
disableMarginCollapsing?: boolean;
/**
* Props that will be passed to children renderers via
* {@link CustomRendererProps.propsFromParent}.
*/
propsForChildren?: Partial<PropsFromParent>;
/**
* A React render function to render and wrap individual children.
*/
renderChild?: (props: TChildProps) => ReactNode;
}
/**
* Props for {@link TChildrenRenderer}.
*
* @public
*/
export interface TChildrenRendererProps extends TChildrenBaseProps {
/**
* An array of {@link TNode} to render.
*/
tchildren: ReadonlyArray<TNode>;
}
/**
* Props for {@link TNodeChildrenRenderer}.
*
* @public
*/
export interface TNodeChildrenRendererProps extends TChildrenBaseProps {
/**
* The {@link TNode} from which children will be rendered.
*/
tnode: TNode;
}
/**
* Props for {@link TNodeRenderer} component.
*
* @typeParam T - The concrete type of {@link TNode}.
*/
export interface TNodeRendererProps<T extends TNode> {
/**
* Props passed by direct parents.
*/
propsFromParent?: PropsFromParent;
/**
* The position of this React element relative to the parent React element,
* starting at 0.
*
* @remarks Not to be confused with {@link TNodeShape.index}, which is
* the position of the *TNode* before hoisting. The latter is much closer
* to an intuitive understanding of the position of a DOM node in the DOM
* tree.
*/
renderIndex: number;
/**
* The total number of elements children of this React element parent.
*/
renderLength: number;
/**
* The {@link TNode} to render.
*/
tnode: T;
}
/**
* Abstract interface for renderers.
*
* @typeParam T - The concrete type of {@link TNode}.
*/
export interface RendererBaseProps<T extends TNode> extends TNodeRendererProps<T> {
/**
* Props passed to the underlying React Native element, either `Text` or
* `View`. See also {@link RendererBaseProps.textProps} and
* {@link RendererBaseProps.viewProps}.
*
* @remarks The `prop.style` property will have a greater specificity
* than computed styles for this {@link TNode}. E.g. `style={[computedStyle,
* nativeProps.style, viewProps.style]}`.
*
*/
nativeProps?: StylessReactNativeProps & {
style?: StyleProp<ViewStyle>;
};
/**
* Any default renderer should be able to handle press.
*/
onPress?: (e: GestureResponderEvent) => void;
/**
* Props passed to the underlying `Text` element (`type` must be 'text'). See
* also {@link RendererBaseProps.nativeProps} and
* {@link RendererBaseProps.viewProps}.
*
* @remarks The `textProps.style` property will have a greater specificity than
* computed styles for this {@link TNode}. E.g. `style={[computedStyle,
* nativeProps.style, textProps.style]}`.
*/
textProps: TextProps;
/**
* Is the underlying component `Text` or `View`?
*/
type: 'text' | 'block';
/**
* Props passed to the underlying `View` element (`type` must be 'view'). See
* also {@link RendererBaseProps.nativeProps} and
* {@link RendererBaseProps.textProps}.
*
* @remarks The `viewProps.style` property will have a greater specificity than
* computed styles for this {@link TNode}. E.g. `style={[computedStyle,
* nativeProps.style, viewProps.style]}`.
*/
viewProps: ViewProps;
}
/**
* Props for {@link TDefaultRenderer}.
*
* @typeParam T - The concrete type of {@link TNode}.
* @public
*/
export interface TDefaultRendererProps<T extends TNode> extends RendererBaseProps<T> {
/**
* A component to render children of a `tnode`.
*/
TNodeChildrenRenderer: ComponentType<TNodeChildrenRendererProps>;
/**
* When children is present, renderChildren will not be invoked.
*/
children?: ReactNode;
/**
* Props passed to children nodes. Those props are accessible from children
* renderers as `propsFromParent`
*/
propsForChildren?: Partial<PropsFromParent>;
/**
* The style for this renderer will depend on the type of {@link TNode}.
* You can check if a node is textual with `props.type === 'text'`.
*/
style: T extends TText | TPhrasing ? StyleProp<TextStyle> : StyleProp<ViewStyle>;
}
/**
* Props for {@link InternalRenderer} components.
*
* @typeParam T - The concrete type of {@link TNode}.
* @public
*/
export interface InternalRendererProps<T extends TNode> extends RendererBaseProps<T> {
/**
* Default renderer for this {@link TNode}.
*/
TDefaultRenderer: TDefaultRenderer<T>;
/**
* A component to render children of a `tnode`.
*/
TNodeChildrenRenderer: ComponentType<TNodeChildrenRendererProps>;
/**
* Props shared across the whole render tree.
*/
sharedProps: RenderHTMLAmbiantSharedProps;
/**
* Styles extracted with {@link TNode.getNativeStyles}.
*/
style: T extends TText | TPhrasing ? NativeTextStyles : NativeBlockStyles;
}
/**
* Props for custom renderers, such as provided in the `renderers` prop.
*
* @typeParam T - The concrete type of {@link TNode}.
* @public
*/
export interface CustomRendererProps<T extends TNode> extends InternalRendererProps<T> {
/**
* Internal renderer for this _tagName_, not to be confused with
* {@link TDefaultRenderer}, which is the fallback renderer for any {@link TNode}.
*
* @remarks For example, when rendering `img` tags, `TDefaultRenderer` and
* `InternalRenderer` won't be equal.
*
* When there is no internal renderer for this tag, this prop will fallback
* to `TDefaultRenderer`.
*/
InternalRenderer: InternalRenderer<T>;
}
/**
* Default renderer for any {@link TNode}. The renderer behavior will only
* change given the {@link TNodeType | type} of the {@link TNode}.
*
* @typeParam T - The concrete type of {@link TNode}.
* @public
*/
export type TDefaultRenderer<T extends TNode> = ComponentType<TDefaultRendererProps<T>>;
/**
* An "internal renderer" is an internal custom renderer, adding specific
* features to the fallback `TDefaultRenderer`. For example, `<img/>` tags will
* be rendered via an internal renderer, while `<div>` will fallback to a
* {@link TDefaultRenderer}.
*
* @public
*
* @typeParam T - The concrete type of {@link TNode}.
*/
export type InternalRenderer<T extends TNode> = ComponentType<InternalRendererProps<T>>;
/**
* A custom renderer, such as provided in the {@link RenderHTMLProps.renderers} prop.
*
* @typeParam T - The concrete type of {@link TNode}.
* @public
*/
export type CustomRenderer<T extends TNode> = ComponentType<CustomRendererProps<T>>;
/**
* An object containing meta-data extracted from resource URL and HTML
* `<head>` element.
*
* @public
*/
export interface DocumentMetadata {
/**
* How anchors should be actioned on press?
*
* @remarks By default, `renderersProps.a.onPress` will always open the
* system browser, equivalent to `_blank` target. However, you can customize
* the behavior by providing your own implementation.
*/
baseTarget: TREDocumentContext['baseTarget'];
/**
* The base URL of this resource. It will influence how relative URLs are
* resolved such as `href` and `src` element properties. By order of
* precedence:
*
* 1. `baseUrl` from `<base/>` html element;
* 2. `baseUrl` from `source.baseUrl` prop;
* 3. `baseUrl` as origin of `source.uri` prop.
*/
baseUrl: string;
/**
* The writing direction of this document, extracted from the `dir` attribute
* of `<html/>` element.
*/
dir: 'ltr' | 'rtl';
/**
* The language of this document, extracted from the `lang` attribute of the
* `<html/>` element;
*/
lang: string;
/**
* A data array comprised of attributes from <link> elements.
*/
links: TREDocumentContext['links'];
/**
* A data array comprised of attributes from <meta> elements.
*/
meta: TREDocumentContext['meta'];
/**
* The content of the <title> element.
*/
title: string;
}
/**
* Props for unitary counter renderers.
*
* @public
*/
export type UnitaryCounterRendererProps = {
color: string;
fontSize: number;
index: number;
lineHeight: number;
} & Pick<MixedStyleDeclaration, 'fontFamily' | 'fontStyle' | 'fontWeight' | 'fontVariant'>;
/**
* List style types supported internally.
*
* See {@link https://www.w3.org/TR/css-counter-styles-3 | CSS Counter Styles Level 3}.
*
* @public
*/
export type DefaultSupportedListStyleType = 'none' | 'disc' | 'circle' | 'square' | 'decimal' | 'decimal-leading-zero' | 'lower-roman' | 'upper-roman' | 'lower-greek' | 'lower-alpha' | 'lower-latin' | 'upper-alpha' | 'upper-latin' | 'disclosure-open' | 'disclosure-closed';
/**
* Specs for a list item marker renderer backed by a `CounterStyleRenderer`
* from `@jsamr/counter-style`.
*
* @public
*/
export interface TextualListStyleSpec {
counterStyleRenderer: CounterStyleRenderer;
type: 'textual';
}
/**
* Specs for a list item marker renderer with only one representation. The
* "Component" should render this representation, minus prefix and suffix. The
* rendered component should have a maximum width of `0.6 * fontSize`, and a height of
* `lineHeight`.
*
* @public
*/
export interface UnitaryListStyleSpec {
Component: ComponentType<UnitaryCounterRendererProps>;
counterStyleRenderer: CounterStyleRenderer;
type: 'unitary';
}
/**
* An object to specify how to render list markers.
*
* @public
*/
export type ListStyleSpec = TextualListStyleSpec | UnitaryListStyleSpec;
export {};
//# sourceMappingURL=shared-types.d.ts.map