UNPKG

interweave

Version:

React library to safely render HTML, filter attributes, autowrap text, autolink, and much more.

166 lines (139 loc) 4.95 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import React from 'react'; declare global { // eslint-disable-next-line no-var, vars-on-top var INTERWEAVE_SSR_POLYFILL: (() => Document | undefined) | undefined; } export type Node = React.ReactElement<unknown> | string | null; export type ChildrenNode = Node[] | string; export interface NodeConfig { // Only children children: string[]; // Children content type content: number; // Invalid children invalid: string[]; // Only parent parent: string[]; // Can render self as a child self: boolean; // HTML tag name tagName: string; // Self content type type: number; // Self-closing tag void: boolean; } export type ConfigMap = Record<string, Partial<NodeConfig>>; export type AttributeValue = boolean | number | object | string; export type Attributes = Record<string, AttributeValue>; export type AfterParseCallback<T> = (content: Node[], props: T) => Node[]; export type BeforeParseCallback<T> = (content: string, props: T) => string; export type TransformCallback = ( node: HTMLElement, children: Node[], config: NodeConfig, ) => React.ReactNode; // MATCHERS export type MatchCallback<T> = (matches: string[]) => T; export type MatchResponse<T> = T & { index: number; length: number; match: string; valid: boolean; void?: boolean; }; export interface MatcherInterface<T = any> { greedy?: boolean; inverseName: string; propName: string; asTag: () => string; createElement: (children: ChildrenNode, props: T) => Node; match: (value: string) => MatchResponse<Partial<T>> | null; onBeforeParse?: (content: string, props: T) => string; onAfterParse?: (content: Node[], props: T) => Node[]; } // FILTERS export type ElementAttributes = React.AllHTMLAttributes<unknown>; export interface FilterInterface { attribute?: <K extends keyof ElementAttributes>( name: K, value: ElementAttributes[K], ) => ElementAttributes[K] | null | undefined; node?: (name: string, node: HTMLElement) => HTMLElement | null; } export type FilterMap = Record<string, number>; // PARSER export type MatcherElementsMap = Record< string, { children: string; matcher: MatcherInterface<{}>; props: object; } >; export interface ParserProps { /** Disable filtering and allow all non-banned HTML attributes. */ allowAttributes?: boolean; /** Disable filtering and allow all non-banned/blocked HTML elements to be rendered. */ allowElements?: boolean; /** List of HTML tag names to allow and render. Defaults to the `ALLOWED_TAG_LIST` constant. */ allowList?: string[]; /** List of HTML tag names to disallow and not render. Overrides allow list. */ blockList?: string[]; /** Disable the conversion of new lines to `<br />` elements. */ disableLineBreaks?: boolean; /** The container element to parse content in. Applies browser semantic rules and overrides `tagName`. */ containerTagName?: string; /** Escape all HTML before parsing. */ escapeHtml?: boolean; /** Strip all HTML while rendering. */ noHtml?: boolean; /** Strip all HTML, except HTML generated by matchers, while rendering. */ noHtmlExceptMatchers?: boolean; /** Transformer ran on each HTML element. Return a new element, null to remove current element, or undefined to do nothing. */ transform?: TransformCallback | null; /** Disable transformer for non-allowList tags. */ transformOnlyAllowList?: boolean; } // INTERWEAVE export interface MarkupProps extends ParserProps { /** HTML attributes to pass to the wrapping element. */ attributes?: Attributes; /** CSS class name to pass to the wrapping element. */ className?: string; /** Content that may contain HTML to safely render. */ content?: string | null; /** Content to render when the `content` prop is empty. */ emptyContent?: React.ReactNode; /** @ignore Pre-parsed content to render. */ parsedContent?: React.ReactNode; /** HTML element to wrap the content. Also accepts 'fragment' (superseded by `noWrap`). */ tagName?: string; /** Don't wrap the content in a new element specified by `tagName`. */ noWrap?: boolean; } export interface InterweaveProps extends MarkupProps { /** Support all the props used by matchers. */ [prop: string]: any; /** Disable all filters from running. */ disableFilters?: boolean; /** Disable all matches from running. */ disableMatchers?: boolean; /** List of filters to apply to the content. */ filters?: FilterInterface[]; /** List of matchers to apply to the content. */ matchers?: MatcherInterface<any>[]; /** Callback fired after parsing ends. Must return an array of React nodes. */ onAfterParse?: AfterParseCallback<InterweaveProps> | null; /** Callback fired beore parsing begins. Must return a string. */ onBeforeParse?: BeforeParseCallback<InterweaveProps> | null; } export interface ElementProps { [prop: string]: any; attributes?: Attributes; className?: string; children?: React.ReactNode; selfClose?: boolean; tagName: string; }