;
17 | }
18 |
19 | export type PropsWithStyle = {
20 | style?: StyleProp;
21 | } & P;
22 |
23 | export type PropsWithStringChild = Omit<
24 | Target,
25 | 'children'
26 | > & { children: string };
27 |
28 | export type RefProps = Omit & {
29 | name: T;
30 | };
31 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/nucleons/useContentWidthContext.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import contentWidthContextNucleon from './contentWidthContextNucleon';
3 |
4 | export function useNuclearContentWidth() {
5 | return React.useContext(contentWidthContextNucleon);
6 | }
7 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/nucleons/useSelectorPropsNucleon.ts:
--------------------------------------------------------------------------------
1 | import { useMemo } from 'react';
2 | import { SelectorItem } from './types';
3 |
4 | export default function useSelectorItemsNucleon(
5 | items: ReadonlyArray> | ReadonlyArray
6 | ) {
7 | return useMemo>>>(
8 | () =>
9 | (items || []).map((item: SelectorItem | V) =>
10 | typeof item !== 'string' && typeof item !== 'number'
11 | ? {
12 | value: (item as any).value,
13 | label: String((item as any).label || (item as any).value)
14 | }
15 | : { value: item as V, label: String(item) }
16 | ),
17 | [items]
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/nucleons/useSurfaceBackgroundStyleNucleon.ts:
--------------------------------------------------------------------------------
1 | import { useMemo } from 'react';
2 | import { useColorRoles } from '../../theme/colorSystem';
3 |
4 | export default function useSurfaceBackgroundStyleNucleon() {
5 | const { surface } = useColorRoles();
6 | return useMemo(
7 | () => ({
8 | backgroundColor: surface.background
9 | }),
10 | [surface.background]
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/screens/HomeDrawerScreen/DrawerPlaygroundHeader.tsx:
--------------------------------------------------------------------------------
1 | import { DrawerHeaderProps } from '@react-navigation/drawer/lib/typescript/src/types';
2 | import React from 'react';
3 | import UIAppbarActionAtom from '../../UIAppbarActionAtom';
4 | import UIAppbarContentAtom from '../../UIAppbarContentAtom';
5 | import UIHeaderAtom from '../../UIHeaderAtom';
6 |
7 | export type StandardHeaderOrganismProps = DrawerHeaderProps;
8 |
9 | export default function DrawerPlaygroundHeader({
10 | scene
11 | }: StandardHeaderOrganismProps) {
12 | const {
13 | descriptor: { options, navigation }
14 | } = scene;
15 | const onMenuPress = React.useCallback(
16 | () => (navigation as any).openDrawer(),
17 | [navigation]
18 | );
19 | return (
20 |
21 |
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/screens/HomeDrawerScreen/VersionDisplay.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-native/no-inline-styles */
2 | import * as React from 'react';
3 | import { View } from 'react-native';
4 | import { useSafeAreaInsets } from 'react-native-safe-area-context';
5 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6 | // @ts-ignore
7 | import version from '../../../../version';
8 | import TextRoleNucleon from '../../nucleons/TextRoleNucleon';
9 | import { useColorRoles } from '../../../theme/colorSystem';
10 |
11 | export default function VersionDisplay() {
12 | const { bottom, left, right } = useSafeAreaInsets();
13 | const { surface } = useColorRoles();
14 | return (
15 |
23 |
24 | Discovery {version.demo}
25 | {'\n'}
26 | rnrh {version.lib}
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/screens/HomeDrawerScreen/groupBy.ts:
--------------------------------------------------------------------------------
1 | export default function groupBy(xs: Array, key: K) {
2 | return xs.reduce(function (rv, x) {
3 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
4 | //@ts-ignore
5 | (rv[x[key]] = rv[x[key]] || []).push(x);
6 | return rv;
7 | }, {} as T[K] extends string ? Record> : never);
8 | }
9 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/selectedRadioItemContextAtom.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | const selectedRadioItemContextAtom = createContext('');
4 |
5 | export default selectedRadioItemContextAtom;
6 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/ArticleTemplate/AnimatedContextProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, { PropsWithChildren, useContext } from 'react';
2 | import Animated, {
3 | useAnimatedScrollHandler,
4 | useSharedValue
5 | } from 'react-native-reanimated';
6 |
7 | const animatedContext = React.createContext<{
8 | scrollAnim: Animated.SharedValue;
9 | onScroll: (...args: any[]) => void;
10 | }>(null as any);
11 |
12 | export function useAnimatedContext() {
13 | return useContext(animatedContext);
14 | }
15 |
16 | export default function AnimatedContextProvider({
17 | children
18 | }: PropsWithChildren<{}>) {
19 | const scrollAnim = useSharedValue(0);
20 | const onScroll = useAnimatedScrollHandler((event) => {
21 | scrollAnim.value = event.contentOffset.y;
22 | });
23 | return (
24 |
25 | {children}
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/ArticleTemplate/ScrollerProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | PropsWithChildren,
3 | RefObject,
4 | useContext,
5 | useMemo
6 | } from 'react';
7 | import Animated from 'react-native-reanimated';
8 | import Scroller from './Scroller';
9 |
10 | const scrollerContext = React.createContext(null as any);
11 |
12 | export function useScroller() {
13 | return useContext(scrollerContext);
14 | }
15 |
16 | export default function ScrollerProvider({
17 | children,
18 | scrollRef
19 | }: PropsWithChildren<{
20 | scrollRef: RefObject;
21 | }>) {
22 | const index = useMemo(() => new Scroller(scrollRef), [scrollRef]);
23 | return (
24 |
25 | {children}
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/Playground.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { TNode } from 'react-native-render-html';
3 | import PlaygroundStoreProvider, {
4 | PlaygroundInitParams
5 | } from './playgroundStore';
6 | import Sheet, { SheetProps } from './Sheet';
7 | import PlaygroundDisplay from './PlaygroundDisplay';
8 | import CardColorRolesProvider from '../../croles/CardColorRolesProvider';
9 |
10 | export interface PlaygroundTemplateProps
11 | extends PlaygroundInitParams {
12 | children: SheetProps['children'];
13 | }
14 |
15 | export default function PlaygroundTemplate({
16 | children,
17 | ...storeInitParams
18 | }: PlaygroundTemplateProps) {
19 | const [ttree, setTtree] = useState();
20 | return (
21 | <>
22 |
23 |
24 |
25 | {children}
26 |
27 |
28 | >
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetControlsPortal.ts:
--------------------------------------------------------------------------------
1 | import { demoControlsContext } from './contexts';
2 | import createPortal from './createPortal';
3 |
4 | const SheetControlsPortal = createPortal(
5 | demoControlsContext,
6 | 'SheetControlsPortal'
7 | );
8 |
9 | export default SheetControlsPortal;
10 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetDescriptionPortal.ts:
--------------------------------------------------------------------------------
1 | import { demoDescriptionContext } from './contexts';
2 | import createPortal from './createPortal';
3 |
4 | const SheetDescriptionPortal = createPortal(
5 | demoDescriptionContext,
6 | 'SheetDescriptionPortal'
7 | );
8 |
9 | export default SheetDescriptionPortal;
10 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetNavigatorPortal.ts:
--------------------------------------------------------------------------------
1 | import { demoNavigatorContext } from './contexts';
2 | import createPortal from './createPortal';
3 |
4 | const SheetNavigatorPortal = createPortal(
5 | demoNavigatorContext,
6 | 'SheetNavigatorPortal'
7 | );
8 |
9 | export default SheetNavigatorPortal;
10 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetRouteColor.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useColorRoles } from '../../../theme/colorSystem';
3 | import UIColorPickerControlAtom from '../../UIColorPickerControlAtom';
4 | import {
5 | usePlaygroundStateSlice,
6 | usePlaygroundSetter
7 | } from './playgroundStore';
8 |
9 | export default function SheetRouteColor() {
10 | const color = usePlaygroundStateSlice('color');
11 | const { surface } = useColorRoles();
12 | const setColor = usePlaygroundSetter('color');
13 | return (
14 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetRouteContainer.tsx:
--------------------------------------------------------------------------------
1 | import { BottomSheetScrollView } from '@gorhom/bottom-sheet';
2 | import React, { PropsWithChildren } from 'react';
3 | import { StyleSheet } from 'react-native';
4 |
5 | const styles = StyleSheet.create({
6 | flex: { flexGrow: 1 }
7 | });
8 |
9 | export default function SheetRouteContainer({
10 | children
11 | }: PropsWithChildren<{}>) {
12 | return (
13 |
16 | {children}
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetRouteControls.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { demoControlsContext } from './contexts';
3 | import SheetRouteContainer from './SheetRouteContainer';
4 |
5 | export default function SheetRouteControls() {
6 | const controls = useContext(demoControlsContext);
7 | return {controls};
8 | }
9 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetRouteFontFamily.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import UIRadioListControlMolecule, {
3 | RadioListControlProps
4 | } from '../../UIRadioListControlMolecule';
5 | import {
6 | usePlaygroundStateSlice,
7 | usePlaygroundSetter
8 | } from './playgroundStore';
9 | import { SYSTEM_FONTS } from '../../../constants';
10 |
11 | const getLabelStyle: RadioListControlProps['labelStyle'] = ({
12 | value
13 | }) => ({
14 | fontFamily: value
15 | });
16 |
17 | export default function SheetRouteFontFamily() {
18 | const fontFamily = usePlaygroundStateSlice('fontFamily');
19 | const setFontFamily = usePlaygroundSetter('fontFamily');
20 | return (
21 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetRouteOlListType.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import UIRadioListControlMolecule from '../../UIRadioListControlMolecule';
3 | import {
4 | usePlaygroundStateSlice,
5 | usePlaygroundSetter,
6 | olListTypes
7 | } from './playgroundStore';
8 |
9 | export default function SheetRouteOlListType() {
10 | const olListType = usePlaygroundStateSlice('olListType');
11 | const setListType = usePlaygroundSetter('olListType');
12 | return (
13 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetRouteUlListType.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import UIRadioListControlMolecule from '../../UIRadioListControlMolecule';
3 | import {
4 | usePlaygroundStateSlice,
5 | usePlaygroundSetter,
6 | ulListTypes
7 | } from './playgroundStore';
8 |
9 | export default function SheetRouteUlListType() {
10 | const ulListType = usePlaygroundStateSlice('ulListType');
11 | const setUlListType = usePlaygroundSetter('ulListType');
12 | return (
13 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/SheetStack.tsx:
--------------------------------------------------------------------------------
1 | import { createStackNavigator } from '@react-navigation/stack';
2 |
3 | const SheetStack = createStackNavigator();
4 |
5 | export default SheetStack;
6 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/contexts.ts:
--------------------------------------------------------------------------------
1 | import { createContext, ReactNode } from 'react';
2 | import { TNode } from 'react-native-render-html';
3 |
4 | export const demoDescriptionContext = createContext(null);
5 | export const demoControlsContext = createContext(null);
6 | export const demoNavigatorContext = createContext(null);
7 | export const demoStateContext = createContext<{ html: string; ttree?: TNode }>({
8 | html: '',
9 | ttree: undefined
10 | });
11 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/createPortal.ts:
--------------------------------------------------------------------------------
1 | import React, { Context, PropsWithChildren, ReactNode } from 'react';
2 |
3 | type PortalProps = PropsWithChildren<{ _tpChildren?: ReactNode }>;
4 |
5 | export default function createPortal(
6 | context: Context,
7 | name: string
8 | ) {
9 | const Portal = function ({ children, _tpChildren }: PortalProps) {
10 | return React.createElement(
11 | context.Provider,
12 | {
13 | value: children
14 | },
15 | _tpChildren
16 | );
17 | };
18 | Portal.displayName = name;
19 | Portal.portalId = Symbol(name);
20 | return Portal;
21 | }
22 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/index.tsx:
--------------------------------------------------------------------------------
1 | import PlaygroundTemplate from './Playground';
2 | import SheetControlsPortal from './SheetControlsPortal';
3 | import SheetDescriptionPortal from './SheetDescriptionPortal';
4 | import SheetNavigatorPortal from './SheetNavigatorPortal';
5 | import SheetRouteContainer from './SheetRouteContainer';
6 | import SheetStack from './SheetStack';
7 |
8 | const PlaygroundScreen = SheetStack.Screen;
9 |
10 | export {
11 | SheetControlsPortal as PlaygroundControls,
12 | SheetDescriptionPortal as PlaygroundDescription,
13 | SheetNavigatorPortal as PlaygroundNavigator,
14 | SheetRouteContainer as PlaygroundRouteContainer,
15 | PlaygroundScreen
16 | };
17 |
18 | export default PlaygroundTemplate;
19 |
--------------------------------------------------------------------------------
/apps/discovery/src/components/templates/PlaygroundTemplate/sheetSnapPoints.ts:
--------------------------------------------------------------------------------
1 | const sheetSnapPoints = [240, '50%', '65%'];
2 |
3 | export default sheetSnapPoints;
4 |
--------------------------------------------------------------------------------
/apps/discovery/src/constants/index.ts:
--------------------------------------------------------------------------------
1 | import Constants from 'expo-constants';
2 |
3 | import uniq from 'ramda/es/uniq';
4 | import pipe from 'ramda/es/pipe';
5 | import filter from 'ramda/es/filter';
6 |
7 | const normalizeFonts = pipe(
8 | uniq,
9 | filter(
10 | (c: string) =>
11 | !c.match(
12 | /bold|italic|semi|regular|extra|ultra|light|black|medium|thin|-/i
13 | )
14 | )
15 | );
16 |
17 | const SYSTEM_FONTS = normalizeFonts([...Constants.systemFonts, 'space-mono']);
18 | const BODY_CHAPTER_SPACING = 16;
19 | const BODY_VERTICAL_SPACING = 12;
20 | const BODY_HZ_SPACING = 2;
21 | const BODY_PARAGRAPH_SPACING = 8;
22 | const HEADER_COLL_HEIGHT = 54;
23 | export {
24 | SYSTEM_FONTS,
25 | BODY_CHAPTER_SPACING,
26 | BODY_PARAGRAPH_SPACING,
27 | BODY_HZ_SPACING,
28 | BODY_VERTICAL_SPACING,
29 | HEADER_COLL_HEIGHT
30 | };
31 |
--------------------------------------------------------------------------------
/apps/discovery/src/highlight/StylesheetsProvider.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { PropsWithChildren } from 'react';
3 | import highlighterStylesheetsContext from './highlighterStylesheetsContext';
4 | import lazyStylesheetRegistry, {
5 | HighlightJsStyles
6 | } from './lazyStylesheetRegistry';
7 |
8 | export { HighlightJsStyles };
9 |
10 | export default function StylesheetsProvider({
11 | children,
12 | style
13 | }: PropsWithChildren<{
14 | style: HighlightJsStyles;
15 | }>) {
16 | const value = lazyStylesheetRegistry[style];
17 | if (!value) {
18 | console.warn(
19 | `There is no corresponding highlight.js style with name "${style}".`
20 | );
21 | return null;
22 | }
23 | return (
24 |
25 | {children}
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/apps/discovery/src/highlight/createStylesheets.ts:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'react';
2 | import { StyleSheet, TextStyle } from 'react-native';
3 | import normalizeStylesheet from './normalizeStylesheet';
4 |
5 | type HljsStylsheet = Record;
6 |
7 | export type HighlighterStylesheets = ReturnType;
8 |
9 | export default function createStylesheets(hljsStylesheet: HljsStylsheet) {
10 | const normalizedStyles = normalizeStylesheet(hljsStylesheet);
11 | const { backgroundColor, color } = normalizedStyles.hljs;
12 | const containerStylesheet = StyleSheet.create({
13 | container: { backgroundColor: backgroundColor as string },
14 | text: { color }
15 | });
16 | const contentStylesheet = StyleSheet.create(
17 | normalizedStyles as Record
18 | );
19 | return {
20 | containerStylesheet,
21 | contentStylesheet
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/apps/discovery/src/highlight/highlighterStylesheetsContext.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 | import { HighlighterStylesheets } from './createStylesheets';
3 |
4 | const highlighterStylesheetsContext = createContext(
5 | {} as any
6 | );
7 |
8 | export default highlighterStylesheetsContext;
9 |
--------------------------------------------------------------------------------
/apps/discovery/src/highlight/lazyStylesheetRegistry.ts:
--------------------------------------------------------------------------------
1 | import createStylesheets, { HighlighterStylesheets } from './createStylesheets';
2 | import * as styles from 'react-syntax-highlighter/dist/esm/styles/hljs';
3 |
4 | export type HighlightJsStyles = keyof typeof styles;
5 |
6 | const lazyStylesheetRegistry = new Proxy<
7 | Record
8 | >({} as any, {
9 | get(target, prop: HighlightJsStyles) {
10 | if (prop in target) {
11 | return target[prop];
12 | }
13 | const hlstylesheet = styles[prop];
14 | if (!hlstylesheet) {
15 | return;
16 | }
17 | target[prop] = createStylesheets(hlstylesheet);
18 | return target[prop];
19 | }
20 | });
21 |
22 | export default lazyStylesheetRegistry;
23 |
--------------------------------------------------------------------------------
/apps/discovery/src/highlight/normalizeStylesheet.ts:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'react';
2 |
3 | type HljsStylsheet = Record;
4 |
5 | export default function normalizeStylesheet(hljsStylesheet: HljsStylsheet) {
6 | return Object.fromEntries(
7 | Object.entries(hljsStylesheet).map(
8 | ([
9 | className,
10 | { color, background, backgroundColor, fontWeight, fontStyle }
11 | ]) => [
12 | className,
13 | {
14 | color,
15 | backgroundColor: background ?? backgroundColor,
16 | fontWeight,
17 | fontStyle
18 | }
19 | ]
20 | )
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/apps/discovery/src/hooks/useOnLinkPress.ts:
--------------------------------------------------------------------------------
1 | import React, { useCallback } from 'react';
2 | import onLinkPressContext from '../state/onLinkPressContext';
3 |
4 | function useOnLinkPress(uri: string): () => void;
5 | function useOnLinkPress(): (uri: string) => void;
6 | function useOnLinkPress(uri?: string) {
7 | const onLinkPress = React.useContext(onLinkPressContext);
8 | if (uri) {
9 | // eslint-disable-next-line react-hooks/rules-of-hooks
10 | return useCallback(() => onLinkPress(uri), [onLinkPress, uri]);
11 | }
12 | return onLinkPress;
13 | }
14 |
15 | export default useOnLinkPress;
16 |
--------------------------------------------------------------------------------
/apps/discovery/src/navigation/RootNavigator.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {
3 | createStackNavigator,
4 | StackNavigationOptions
5 | } from '@react-navigation/stack';
6 | import HomeScreen from '../components/screens/HomeDrawerScreen';
7 | import StackHeader from './StackHeader';
8 | import useSurfaceBackgroundStyleNucleon from '../components/nucleons/useSurfaceBackgroundStyleNucleon';
9 |
10 | const Stack = createStackNavigator();
11 |
12 | export default function RootNavigator() {
13 | const cardStyle = useSurfaceBackgroundStyleNucleon();
14 | const screenOptions = React.useMemo(
15 | () => ({
16 | animationTypeForReplace: 'pop',
17 | animationEnabled: false,
18 | header: (props) => ,
19 | cardStyle: cardStyle
20 | }),
21 | [cardStyle]
22 | );
23 | return (
24 |
25 |
30 |
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/apps/discovery/src/navigation/StackHeader.tsx:
--------------------------------------------------------------------------------
1 | import { StackHeaderProps } from '@react-navigation/stack';
2 | import React from 'react';
3 | import UIAppbarActionAtom from '../components/UIAppbarActionAtom';
4 | import UIAppbarContentAtom from '../components/UIAppbarContentAtom';
5 | import UIHeaderAtom from '../components/UIHeaderAtom';
6 |
7 | export { StackHeaderProps };
8 |
9 | export default function StackHeader(props: StackHeaderProps) {
10 | const { scene } = props;
11 | const {
12 | descriptor: { options, navigation }
13 | } = scene;
14 | const onMenuPress = React.useCallback(
15 | () => navigation.goBack(),
16 | [navigation]
17 | );
18 | return (
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/apps/discovery/src/navigation/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { NavigationContainer } from '@react-navigation/native';
3 | import { View } from 'react-native';
4 | import RootNavigator from './RootNavigator';
5 | import { useTheme } from '../theme/ThemeProvider';
6 |
7 | const linking = {
8 | prefixes: ['https://meliorence.github.io/react-native-render-html']
9 | };
10 |
11 | export default function Navigation() {
12 | const theme = useTheme();
13 | return (
14 |
15 |
16 |
17 |
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/apps/discovery/src/state/ColorSchemeProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, { PropsWithChildren, useState } from 'react';
2 |
3 | export interface ColorSchemeState {
4 | colorScheme: 'light' | 'dark';
5 | setColorScheme: (colorScheme: 'light' | 'dark') => void;
6 | }
7 |
8 | const ColorSchemeContext = React.createContext({
9 | colorScheme: 'light',
10 | setColorScheme: () => {}
11 | });
12 |
13 | export function useColorScheme() {
14 | return React.useContext(ColorSchemeContext).colorScheme;
15 | }
16 |
17 | export function useColorSchemeSetter() {
18 | return React.useContext(ColorSchemeContext).setColorScheme;
19 | }
20 |
21 | export default function ColorSchemeProvider({
22 | initialColorScheme,
23 | children
24 | }: PropsWithChildren<{
25 | initialColorScheme: ColorSchemeState['colorScheme'];
26 | }>) {
27 | const [colorScheme, setColorScheme] =
28 | useState(initialColorScheme);
29 | return (
30 |
31 | {children}
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/apps/discovery/src/state/onLinkPressContext.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | const onLinkPressContext = createContext<(uri: string) => void>(
4 | () => undefined as void
5 | );
6 |
7 | export default onLinkPressContext;
8 |
--------------------------------------------------------------------------------
/apps/discovery/src/state/store.tsx:
--------------------------------------------------------------------------------
1 | import create from 'zustand';
2 |
3 | interface State extends Record {
4 | legacyMode: boolean;
5 | // Actions
6 | toggleLegacyMode: () => void;
7 | }
8 |
9 | const useStore = create((set) => {
10 | return {
11 | legacyMode: false,
12 | // Actions
13 | toggleLegacyMode: () => set((s) => ({ legacyMode: !s.legacyMode }))
14 | };
15 | });
16 |
17 | const legacyMode = (s: State) => s.legacyMode;
18 | const toggleLegacyMode = (s: State) => s.toggleLegacyMode;
19 |
20 | export const useLegacyMode = () => useStore(legacyMode);
21 | export const useToggleLegacyMode = () => useStore(toggleLegacyMode);
22 |
--------------------------------------------------------------------------------
/apps/discovery/src/svg.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg' {
2 | import { SvgComponent } from '@doc/svg-component';
3 | const content: SvgComponent;
4 | export default content;
5 | }
6 |
--------------------------------------------------------------------------------
/apps/discovery/src/svgAssetsIndex.ts:
--------------------------------------------------------------------------------
1 | import { SvgAssetType } from '@doc/pages';
2 | import DataFlow from '../assets/svg/data-flow.svg';
3 | import Logo from '../assets/svg/logo.svg';
4 |
5 | const svgAssetsIndex: Record = {
6 | 'data-flow': DataFlow,
7 | logo: Logo
8 | };
9 |
10 | export default svgAssetsIndex;
11 |
--------------------------------------------------------------------------------
/apps/discovery/src/theme/alphaMixColor.ts:
--------------------------------------------------------------------------------
1 | import Color from 'color';
2 |
3 | export default function alphaMixColor(
4 | color: string,
5 | alpha: number,
6 | background = 'white'
7 | ) {
8 | return Color(color).alpha(alpha).mix(Color(background)).hex();
9 | }
10 |
--------------------------------------------------------------------------------
/apps/discovery/src/theme/shiftColor.ts:
--------------------------------------------------------------------------------
1 | import Color from 'color';
2 |
3 | function shiftColor(color: string, ratio: number): string;
4 | function shiftColor(
5 | color: string,
6 | ratioDark: number,
7 | ratioLight: number
8 | ): string;
9 |
10 | function shiftColor(
11 | color: string,
12 | ratioDarkOrBoth: number,
13 | ratioLight?: number
14 | ) {
15 | const c = Color(color);
16 | if (c.isDark()) {
17 | return c.lighten(ratioDarkOrBoth).hex();
18 | }
19 | return c.darken(ratioLight ?? ratioDarkOrBoth).hex();
20 | }
21 |
22 | export default shiftColor;
23 |
--------------------------------------------------------------------------------
/apps/discovery/svgr.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@doc/svgr-conf');
2 |
--------------------------------------------------------------------------------
/apps/discovery/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "jsx": "react-native",
5 | "lib": [
6 | "dom",
7 | "esnext"
8 | ],
9 | "moduleResolution": "node",
10 | "noEmit": true,
11 | "skipLibCheck": true,
12 | "resolveJsonModule": true,
13 | "strict": true
14 | },
15 | "extends": "expo/tsconfig.base"
16 | }
17 |
--------------------------------------------------------------------------------
/apps/discovery/types.tsx:
--------------------------------------------------------------------------------
1 | import { RenderHTMLProps } from 'react-native-render-html';
2 |
3 | export type RootStackParamList = {
4 | Root: undefined;
5 | NotFound: undefined;
6 | };
7 |
8 | export type BottomTabParamList = {
9 | TabOne: undefined;
10 | TabTwo: undefined;
11 | };
12 |
13 | export type TabOneParamList = {
14 | TabOneScreen: undefined;
15 | };
16 |
17 | export type TabTwoParamList = {
18 | TabTwoScreen: undefined;
19 | };
20 |
21 | export interface SnippetDeclaration {
22 | name: string;
23 | codeSource: string;
24 | supportsLegacy: boolean;
25 | props?: RenderHTMLProps;
26 | }
27 |
--------------------------------------------------------------------------------
/apps/discovery/version.js:
--------------------------------------------------------------------------------
1 | const json = require('react-native-render-html/package.json');
2 |
3 | module.exports = {
4 | demo: '4.0.1',
5 | lib: json.version
6 | };
7 |
--------------------------------------------------------------------------------
/apps/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
22 | # Typedoc
23 | /apisidebar.json
24 |
25 | /api/**/*.mdx
26 |
--------------------------------------------------------------------------------
/apps/website/README.md:
--------------------------------------------------------------------------------
1 | # Website
2 |
3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.
4 |
5 | ## Installation
6 |
7 | ```console
8 | yarn install
9 | ```
10 |
11 | ## Local Development
12 |
13 | ```console
14 | yarn start
15 | ```
16 |
17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18 |
19 | ## Build
20 |
21 | ```console
22 | yarn build
23 | ```
24 |
25 | This command generates static content into the `build` directory and can be served using any static contents hosting service.
26 |
27 | ## Deployment
28 |
29 | ```console
30 | GIT_USER= USE_SSH=true yarn deploy
31 | ```
32 |
33 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
34 |
--------------------------------------------------------------------------------
/apps/website/api/.gitignore:
--------------------------------------------------------------------------------
1 | *.mdx
--------------------------------------------------------------------------------
/apps/website/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')]
3 | };
4 |
--------------------------------------------------------------------------------
/apps/website/docs/.gitignore:
--------------------------------------------------------------------------------
1 | **/*.mdx
2 | **/*.md
3 | !migration-guide.mdx
--------------------------------------------------------------------------------
/apps/website/docs/content/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Content",
3 | "position": 2
4 | }
5 |
--------------------------------------------------------------------------------
/apps/website/docs/flow/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Flow",
3 | "position": 3
4 | }
5 |
--------------------------------------------------------------------------------
/apps/website/docs/guides/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Guides",
3 | "position": 2
4 | }
5 |
--------------------------------------------------------------------------------
/apps/website/sidebars.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Creating a sidebar enables you to:
3 | - create an ordered group of docs
4 | - render a sidebar for each doc of that group
5 | - provide next/previous navigation
6 |
7 | The sidebars can be generated from the filesystem, or explicitly defined here.
8 |
9 | Create as many sidebars as you want.
10 | */
11 |
12 | module.exports = {
13 | // By default, Docusaurus generates a sidebar from the docs folder structure
14 | docSidebar: [
15 | { type: 'autogenerated', dirName: '.' },
16 | {
17 | type: 'link',
18 | label: 'Props',
19 | href: '/api/renderhtmlprops'
20 | }
21 | ]
22 |
23 | // But you can create a sidebar manually
24 | /*
25 | tutorialSidebar: [
26 | {
27 | type: 'category',
28 | label: 'Tutorial',
29 | items: ['hello'],
30 | },
31 | ],
32 | */
33 | };
34 |
--------------------------------------------------------------------------------
/apps/website/src/components/APIReference.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Reference from './Reference';
3 | import useBaseUrl from '@docusaurus/useBaseUrl';
4 |
5 | export default function APIReference({
6 | name,
7 | member,
8 | full = false
9 | }: {
10 | name: string;
11 | member?: string;
12 | full?: boolean;
13 | }) {
14 | const memberSuffix = member ? `#${member.toLowerCase()}` : '';
15 | return (
16 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/apps/website/src/components/Badges.module.scss:
--------------------------------------------------------------------------------
1 | .badge {
2 | height: 20px;
3 | overflow: hidden;
4 | > img {
5 | display: block;
6 | }
7 | }
8 |
9 | .stats {
10 | display: flex;
11 | display: none;
12 | align-items: center;
13 | justify-content: flex-end;
14 | gap: 1rem;
15 | }
16 |
17 | .stats {
18 | @media screen and (max-width: 450px) {
19 | & {
20 | position: relative;
21 | flex-direction: column;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/apps/website/src/components/Badges.tsx:
--------------------------------------------------------------------------------
1 | import TwitterFollow from './TwitterFollow';
2 | import React from 'react';
3 | import classes from './Badges.module.scss';
4 |
5 | export default function Badges() {
6 | return (
7 |
8 |
9 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/apps/website/src/components/DiscoveryFrame.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 | margin-bottom: var(--ifm-leading);
6 | }
7 |
8 | .button {
9 | align-self: center;
10 | display: flex;
11 | justify-content: center;
12 | }
13 |
--------------------------------------------------------------------------------
/apps/website/src/components/ExpoBlogCard.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TryOnExpoCard from './TryOnExpoCard';
3 |
4 | export default function ExpoBlogCard({ className }: { className?: string }) {
5 | return (
6 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/apps/website/src/components/ExpoDiscoveryCard.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TryOnExpoCard from './TryOnExpoCard';
3 |
4 | export default function ExpoDiscoveryCard({
5 | className
6 | }: {
7 | className?: string;
8 | }) {
9 | return (
10 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/apps/website/src/components/ExpoSnippet.module.scss:
--------------------------------------------------------------------------------
1 | .expoIframe {
2 | display: block;
3 | width: 100%;
4 | height: 100%;
5 | }
6 |
--------------------------------------------------------------------------------
/apps/website/src/components/HomepageFeatures.module.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable docusaurus/copyright-header */
2 |
3 | .features {
4 | display: flex;
5 | align-items: center;
6 | padding: 2rem 0;
7 | width: 100%;
8 | }
9 |
10 | .featureSvg {
11 | height: 200px;
12 | width: 200px;
13 | }
14 |
--------------------------------------------------------------------------------
/apps/website/src/components/IPhoneFrame.tsx:
--------------------------------------------------------------------------------
1 | import clsx from 'clsx';
2 | import React from 'react';
3 | import classes from './IPhoneFrame.module.scss';
4 |
5 | export default function IPhoneFrame({
6 | children,
7 | scale = 1,
8 | style,
9 | className
10 | }: {
11 | children: any;
12 | style?: React.CSSProperties;
13 | scale?: number;
14 | className?: string;
15 | }) {
16 | return (
17 |
20 |
21 | {React.cloneElement(children, {
22 | ...children.props,
23 | className: classes['device-content']
24 | })}
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/apps/website/src/components/Reference.module.scss:
--------------------------------------------------------------------------------
1 | @import '../css/shared.scss';
2 |
3 | a.ref {
4 | text-decoration-color: var(--ifm-link-color);
5 | text-decoration: none;
6 | &:hover {
7 | color: var(--ifm-link-color);
8 | text-decoration: underline;
9 | }
10 | > code {
11 | color: var(--ifm-link-color);
12 | }
13 | &--rnrh-prop, &--api-def {
14 | @extend .reference;
15 | white-space: pre;
16 | text-decoration: none !important;
17 | font-weight: bolder;
18 | --ifm-alert-color: var(--syntax-color-type);
19 | code {
20 | color: var(--syntax-color-type);
21 | }
22 | &:hover {
23 | text-decoration: none;
24 | }
25 | }
26 | &--html-attr {}
27 | &--html-el {}
28 | &--es-symbol {}
29 | &--css-prop {}
30 | &--rn-symbol {}
31 | &--library {
32 | color: var(--reference-color-lib);
33 | }
34 | &--doc {
35 | text-decoration: solid underline;
36 | color: var(--reference-color-doc);
37 | font-weight: bolder;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/apps/website/src/components/Reference.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import type { RefType } from '@doc/pages';
3 | import clsx from 'clsx';
4 | import styles from './Reference.module.scss';
5 | import Link from '@docusaurus/Link';
6 |
7 | export default function Reference({
8 | url,
9 | type,
10 | member,
11 | name,
12 | full,
13 | plural
14 | }: {
15 | name: string;
16 | member?: string;
17 | url: string;
18 | full: boolean;
19 | type: RefType | 'rnrh-prop' | 'api-def';
20 | plural?: boolean;
21 | }) {
22 | const shouldWrapCode = type !== 'doc';
23 | const pluralMark = plural ? 's' : '';
24 | const fullName =
25 | (member && full ? `${name}.${member}` : member ? member : name) +
26 | pluralMark;
27 | return (
28 |
29 | {shouldWrapCode ? {fullName}
: fullName}
30 |
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/apps/website/src/components/Screenshot.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-hooks/rules-of-hooks */
2 | import React from 'react';
3 | import IPhoneFrame from './IPhoneFrame';
4 | import useBaseUrl from '@docusaurus/useBaseUrl';
5 |
6 | export default function Screenshot({
7 | scale,
8 | url,
9 | webpUrl,
10 | alt,
11 | style,
12 | frameStyle,
13 | className
14 | }: {
15 | scale?: number;
16 | style?: any;
17 | className?: any;
18 | frameStyle?: any;
19 | url: string;
20 | webpUrl?: string;
21 | alt?: string;
22 | }) {
23 | return (
24 |
25 |
26 |
27 | {webpUrl && }
28 |
29 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/apps/website/src/components/SvgFigure.module.scss:
--------------------------------------------------------------------------------
1 | @import '../css/shared.scss';
2 |
3 | .figure {
4 | @extend .figure;
5 | margin: 0 0 var(--ifm-leading) 0;
6 | padding: 0;
7 | }
8 |
9 | .figure__title {
10 | @extend .figure__title;
11 | }
12 |
13 | .figure__caption {
14 | @extend .figure__caption;
15 | background-color: var(--theme-surface-bg);
16 | }
17 |
18 | .svgContainer {
19 | padding: var(--ifm-leading);
20 | background-color: var(--ifm-code-background);
21 | background-color: rgba(125,125,125,0.15);
22 | }
23 |
--------------------------------------------------------------------------------
/apps/website/src/components/TNodeTransformDisplay.module.scss:
--------------------------------------------------------------------------------
1 | @import '../css/shared.scss';
2 |
3 | .arrow {
4 | text-align: center;
5 | font-size: 50px;
6 | padding-bottom: var(--ifm-leading);
7 | }
8 |
9 | .figure {
10 | @extend .figure, .figure--card;
11 | }
12 |
13 | .figure__caption {
14 | @extend .figure__caption;
15 | }
16 |
17 | .figure__title {
18 | @extend .figure__title;
19 | }
20 |
--------------------------------------------------------------------------------
/apps/website/src/components/TNodeTransformDisplay.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import CodeBlock from '@theme/CodeBlock';
3 | import styles from './TNodeTransformDisplay.module.scss';
4 |
5 | export default function TNodeTransformDisplay({
6 | html,
7 | snapshot,
8 | caption,
9 | title
10 | }: {
11 | title?: string;
12 | caption?: string;
13 | html: string;
14 | snapshot: string;
15 | }) {
16 | const normalHtml = decodeURIComponent(html);
17 | const normalSnapshot = decodeURIComponent(snapshot);
18 | return (
19 | <>
20 | {title && {title}
}
21 |
22 | {normalHtml}
23 | ↓
24 | {normalSnapshot}
25 | {caption && (
26 | {caption}
27 | )}
28 |
29 | >
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/apps/website/src/components/TryOnExpoCard.module.scss:
--------------------------------------------------------------------------------
1 | html[data-theme='dark'] .expoBox--themed, .expoBox--white {
2 | img {
3 | filter: invert(1) opacity(80%);
4 | }
5 | }
6 | .expoBox {
7 | display: flex;
8 | flex-direction: column;
9 | align-items: center;
10 | text-align: center;
11 | line-height: 1.4;
12 | &__logo {
13 | margin-bottom: 0.5rem;
14 | }
15 | &__qr {
16 | margin-top: 0.5rem;
17 | align-self: center;
18 | }
19 | }
20 |
21 | .img {
22 | width: 120px;
23 | height: 120px;
24 | }
25 |
--------------------------------------------------------------------------------
/apps/website/src/components/TwitterFollow.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classes from './TwitterFollow.module.scss';
3 | import clsx from 'clsx';
4 |
5 | export default function TwitterFollow({ className }: { className?: string }) {
6 | return (
7 |
11 |
12 | Follow @jsamrn
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/apps/website/src/png.d.ts:
--------------------------------------------------------------------------------
1 | declare module '@site/static/img/lists/*.png' {
2 | const content: string;
3 | export default content;
4 | }
5 |
--------------------------------------------------------------------------------
/apps/website/src/scss.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg' {
2 | import { SvgComponent } from '@doc/svg-component';
3 | const content: SvgComponent;
4 | export default content;
5 | }
6 |
--------------------------------------------------------------------------------
/apps/website/src/svg.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.scss' {
2 | const content: Record;
3 | export default content;
4 | }
5 |
--------------------------------------------------------------------------------
/apps/website/src/svg/.gitignore:
--------------------------------------------------------------------------------
1 | *.svg
--------------------------------------------------------------------------------
/apps/website/src/theme/BlogPostItem/styles.module.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | .blogPostTitle {
9 | font-size: 3rem;
10 | }
11 |
12 | .blogPostData {
13 | font-size: 0.9rem;
14 | }
15 |
16 | .blogPostDetailsFull {
17 | flex-direction: column;
18 | }
19 |
--------------------------------------------------------------------------------
/apps/website/src/theme/CodeBlock/parseCodeBlockTitle.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 | const codeBlockTitleRegex = /title=(["'])(.*?)\1/;
8 |
9 | const parseCodeBlockTitle = (metastring) => {
10 | return (metastring && metastring.match(codeBlockTitleRegex)?.[2]) || '';
11 | };
12 |
13 | export default parseCodeBlockTitle;
14 |
--------------------------------------------------------------------------------
/apps/website/src/typeui/Badges.tsx:
--------------------------------------------------------------------------------
1 | import React, { PropsWithChildren } from 'react';
2 | import styles from './styles.module.scss';
3 | import clsx from 'clsx';
4 |
5 | export default function Badges({
6 | definitions,
7 | children
8 | }: PropsWithChildren<{
9 | definitions: Array<{ label: string; title?: string } | null | false>;
10 | }>) {
11 | return (
12 |
13 | {children}
14 |
15 | {definitions
16 | .filter((d) => !!d)
17 | .map(({ label, title }: { label: string; title?: string }) => (
18 |
22 | {label}
23 |
24 | ))}
25 |
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/apps/website/src/typeui/Indent.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function Indent({ indent }: { indent: number }) {
4 | const whitespaces = [];
5 | for (let i = 0; i < indent; i++) {
6 | whitespaces.push(<> >);
7 | }
8 | return {whitespaces}
;
9 | }
10 |
--------------------------------------------------------------------------------
/apps/website/src/typeui/reduceReflectionsWith.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import type { JSONOutput } from 'typedoc';
3 | import Params from './Params';
4 | import { TokenPunctuation } from './tokens';
5 | import Indent from './Indent';
6 |
7 | export default function reduceReflectionsWith(
8 | punct: string | null,
9 | params: Params,
10 | renderCurrent: (curr: JSONOutput.DeclarationReflection, p: Params) => any,
11 | shouldBreak?: boolean
12 | ) {
13 | return (prev: any, curr: JSONOutput.DeclarationReflection) => (
14 | <>
15 | {prev}
16 | {prev && punct && {punct}}
17 | {shouldBreak && (
18 | <>
19 |
20 |
21 | >
22 | )}
23 | {renderCurrent(curr, params)}
24 | >
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/apps/website/src/typeui/useReflection.ts:
--------------------------------------------------------------------------------
1 | import useReflectionIndex from './useReflectionIndex';
2 |
3 | export default function useReflection(reflectionId: number) {
4 | const index = useReflectionIndex();
5 | return index[reflectionId];
6 | }
7 |
--------------------------------------------------------------------------------
/apps/website/src/typeui/useReflectionIndex.tsx:
--------------------------------------------------------------------------------
1 | import type { JSONOutput } from 'typedoc';
2 | import { usePluginData } from '@docusaurus/useGlobalData';
3 |
4 | export default function useReflectionIndex() {
5 | return usePluginData('doc-docusaurus-typedoc-plugin') as Record<
6 | number,
7 | JSONOutput.DeclarationReflection
8 | >;
9 | }
10 |
--------------------------------------------------------------------------------
/apps/website/static/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/.nojekyll
--------------------------------------------------------------------------------
/apps/website/static/favicons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/apple-touch-icon.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #000040
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/apps/website/static/favicons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/favicon-16x16.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/favicon-32x32.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/favicon.ico
--------------------------------------------------------------------------------
/apps/website/static/favicons/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/mstile-144x144.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/mstile-150x150.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/mstile-310x150.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/mstile-310x310.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/favicons/mstile-70x70.png
--------------------------------------------------------------------------------
/apps/website/static/favicons/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Discover RNRH",
3 | "short_name": "Discover RNRH",
4 | "icons": [
5 | {
6 | "src": "/react-native-render-html/favicons/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/react-native-render-html/favicons/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#8181ff",
17 | "background_color": "#8181ff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/apps/website/static/img/appaling-react-native-text-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/appaling-react-native-text-bg.png
--------------------------------------------------------------------------------
/apps/website/static/img/article-6.2-release-notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/article-6.2-release-notes.png
--------------------------------------------------------------------------------
/apps/website/static/img/article-body-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/article-body-dark.png
--------------------------------------------------------------------------------
/apps/website/static/img/article-body-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/article-body-light.png
--------------------------------------------------------------------------------
/apps/website/static/img/article-create-webviewfree-blog-app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/article-create-webviewfree-blog-app.png
--------------------------------------------------------------------------------
/apps/website/static/img/article-side-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/article-side-dark.png
--------------------------------------------------------------------------------
/apps/website/static/img/article-side-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/article-side-light.png
--------------------------------------------------------------------------------
/apps/website/static/img/banner.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/banner.webp
--------------------------------------------------------------------------------
/apps/website/static/img/blog-article-body-code-fixed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/blog-article-body-code-fixed.png
--------------------------------------------------------------------------------
/apps/website/static/img/blog-article-body-code-issue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/blog-article-body-code-issue.png
--------------------------------------------------------------------------------
/apps/website/static/img/blog-article-body-refined.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/blog-article-body-refined.png
--------------------------------------------------------------------------------
/apps/website/static/img/blog-article-body-unstyled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/blog-article-body-unstyled.png
--------------------------------------------------------------------------------
/apps/website/static/img/blog-article-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/blog-article-home.png
--------------------------------------------------------------------------------
/apps/website/static/img/blog-article-side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/blog-article-side.png
--------------------------------------------------------------------------------
/apps/website/static/img/blog-expo-qr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/blog-expo-qr.png
--------------------------------------------------------------------------------
/apps/website/static/img/discover-screenshot.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/discover-screenshot.jpeg
--------------------------------------------------------------------------------
/apps/website/static/img/discover-screenshot.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/discover-screenshot.webp
--------------------------------------------------------------------------------
/apps/website/static/img/discovery-expo-qr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/discovery-expo-qr.png
--------------------------------------------------------------------------------
/apps/website/static/img/foundry-announcement.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/foundry-announcement.png
--------------------------------------------------------------------------------
/apps/website/static/img/home-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/home-dark.png
--------------------------------------------------------------------------------
/apps/website/static/img/home-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/home-light.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/circle.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/disc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/disc.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/disclosure-closed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/disclosure-closed.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/disclosure-open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/disclosure-open.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/lower-alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/lower-alpha.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/lower-greek.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/lower-greek.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/lower-roman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/lower-roman.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/numeric.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/numeric.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/rtl-arabic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/rtl-arabic.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/rtl-bullet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/rtl-bullet.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/russian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/russian.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/square.png
--------------------------------------------------------------------------------
/apps/website/static/img/lists/thai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/lists/thai.png
--------------------------------------------------------------------------------
/apps/website/static/img/react-native-blog-anchors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/react-native-blog-anchors.png
--------------------------------------------------------------------------------
/apps/website/static/img/tutorial/docsVersionDropdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/tutorial/docsVersionDropdown.png
--------------------------------------------------------------------------------
/apps/website/static/img/tutorial/localeDropdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/img/tutorial/localeDropdown.png
--------------------------------------------------------------------------------
/apps/website/static/video/discovery.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/apps/website/static/video/discovery.webm
--------------------------------------------------------------------------------
/apps/website/svgr.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@doc/svgr-conf');
2 |
--------------------------------------------------------------------------------
/apps/website/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@tsconfig/docusaurus/tsconfig.json",
3 | "include": ["src/"]
4 | }
5 |
--------------------------------------------------------------------------------
/assets/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/assets/demo.gif
--------------------------------------------------------------------------------
/assets/discovery-expo-qr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meliorence/react-native-render-html/8325646fc8b39cf4ec8576b297a718ad2e1c44bc/assets/discovery-expo-qr.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset']
3 | };
4 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = { extends: ['@commitlint/config-conventional'] };
2 |
--------------------------------------------------------------------------------
/doc-tools/doc-constants/index.d.ts:
--------------------------------------------------------------------------------
1 | const WEBSITE_ROOT: string;
2 | const WEBSITE_BASE: string;
3 | const WEBSITE_URL: string;
4 | export { WEBSITE_ROOT, WEBSITE_BASE, WEBSITE_URL };
5 |
--------------------------------------------------------------------------------
/doc-tools/doc-constants/index.js:
--------------------------------------------------------------------------------
1 | const WEBSITE_ROOT = 'https://meliorence.github.io';
2 | const WEBSITE_BASE = '/react-native-render-html/';
3 | const WEBSITE_URL = WEBSITE_ROOT + WEBSITE_BASE;
4 |
5 | module.exports = { WEBSITE_ROOT, WEBSITE_BASE, WEBSITE_URL };
6 |
--------------------------------------------------------------------------------
/doc-tools/doc-constants/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@doc/constants",
3 | "type": "commonjs",
4 | "main": "index.js",
5 | "types": "index.d.ts"
6 | }
7 |
--------------------------------------------------------------------------------
/doc-tools/doc-docsusaurus-rfg-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "doc-docusaurus-rfg-plugin",
3 | "type": "commonjs",
4 | "main": "lib/index.js",
5 | "scripts": {
6 | "build": "tsc -p ."
7 | },
8 | "dependencies": {
9 | "htmlparser2": "^7.1.2",
10 | "rfg-api": "^0.5.2"
11 | },
12 | "devDependencies": {
13 | "@docusaurus/core": "2.0.0-beta.759298296",
14 | "@docusaurus/plugin-content-docs": "2.0.0-beta.759298296",
15 | "@docusaurus/types": "2.0.0-beta.759298296",
16 | "typescript": "4.2.2"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/doc-tools/doc-docsusaurus-rfg-plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "./lib",
4 | "module": "CommonJS",
5 | "target": "ES2015",
6 | "noEmit": false,
7 | "noImplicitAny": false,
8 | "lib": ["ES2019"],
9 | "types": ["node"],
10 | "moduleResolution": "Node",
11 | "isolatedModules": false,
12 | "esModuleInterop": true
13 | },
14 | "include": ["src/"],
15 | "exclude": ["node_modules", "**/__tests__", "lib", "types"]
16 | }
17 |
--------------------------------------------------------------------------------
/doc-tools/doc-docusaurus-typedoc-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "doc-docusaurus-typedoc-plugin",
3 | "type": "commonjs",
4 | "main": "src/index.js",
5 | "dependencies": {
6 | "typedoc": "^0.20.36"
7 | },
8 | "devDependencies": {
9 | "@docusaurus/core": "2.0.0-beta.759298296",
10 | "@docusaurus/plugin-content-docs": "2.0.0-beta.759298296",
11 | "@docusaurus/types": "2.0.0-beta.759298296",
12 | "typescript": "4.2.2"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/doc-tools/doc-docusaurus-typedoc-plugin/src/typedoc-init.js:
--------------------------------------------------------------------------------
1 | //@ts-check
2 |
3 | // Forked from https://github.com/TypeStrong/typedoc/blob/master/bin/typedoc
4 | const td = require('typedoc');
5 |
6 | /**
7 | * @param {import('typedoc').TypeDocOptions} options
8 | * @returns {import('typedoc').Application}
9 | */
10 | module.exports = function init(options) {
11 | const app = new td.Application();
12 |
13 | app.options.addReader(new td.TypeDocReader());
14 | app.options.addReader(new td.TSConfigReader());
15 |
16 | app.bootstrap(options);
17 |
18 | if (app.logger.hasErrors()) {
19 | throw new Error('Typedoc plugin is misconfigured.');
20 | }
21 |
22 | if (app.options.getValue('entryPoints').length === 0) {
23 | app.logger.error('No entry points provided');
24 | throw new Error('Typedoc plugin is missing entryPoints.');
25 | }
26 |
27 | return app;
28 | };
29 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/.gitignore:
--------------------------------------------------------------------------------
1 | /bin
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/build.js:
--------------------------------------------------------------------------------
1 | const esbuild = require('esbuild');
2 | const alias = require('esbuild-plugin-alias');
3 |
4 | esbuild.build({
5 | entryPoints: ['src/index.tsx'],
6 | outfile: 'bin/bundle.js',
7 | bundle: true,
8 | platform: 'node',
9 | minify: false,
10 | define: {
11 | __DEV__: false
12 | },
13 | plugins: [
14 | alias({
15 | 'react-native': require.resolve('react-native-web')
16 | })
17 | ]
18 | });
19 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@doc/mdx-gen-cli",
3 | "private": true,
4 | "type": "commonjs",
5 | "bin": {
6 | "doc-mdx-gen-cli": "bin/bundle.js"
7 | },
8 | "scripts": {
9 | "build": "node ./build.js",
10 | "prepack": "yarn build"
11 | },
12 | "dependencies": {
13 | "@doc/pages": "workspace:*",
14 | "@types/fbjs": "^3.0.0",
15 | "@types/react-reconciler": "^0.26.1",
16 | "commander": "^7.2.0",
17 | "fbjs": "^3.0.0",
18 | "html-entities": "^2.3.2",
19 | "react-reconciler": "^0.26.2"
20 | },
21 | "devDependencies": {
22 | "@tsconfig/react-native": "^1.0.3",
23 | "@types/react": "^17.0.4",
24 | "esbuild": "^0.12.0",
25 | "esbuild-plugin-alias": "^0.1.2",
26 | "eslint": "^7.29.0",
27 | "react": "17.0.2",
28 | "react-native-web": "^0.16.3",
29 | "react-test-renderer": "17.0.2",
30 | "typescript": "4.2.2"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/genPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import path from 'path';
3 | import { PageSpecs } from '@doc/pages';
4 | import MdxToolkitProvider from './MdxToolkitProvider';
5 | import { renderMdx } from './render';
6 |
7 | export default async function genPage(pageSpecs: PageSpecs, genFolder: string) {
8 | const genPath =
9 | pageSpecs.group === 'root'
10 | ? [genFolder, `${pageSpecs.id}.mdx`]
11 | : [genFolder, pageSpecs.group, `${pageSpecs.id}.mdx`];
12 | return renderMdx(
13 |
15 | {React.createElement(pageSpecs.component)}
16 | ,
17 | pageSpecs,
18 | path.join(...genPath)
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/index.tsx:
--------------------------------------------------------------------------------
1 | import genPage from './genPage';
2 | import { pagesSpecs } from '@doc/pages';
3 | import { program } from 'commander';
4 | import path from 'path';
5 | import fs from 'fs/promises';
6 |
7 | async function docMdxGen(outDir: string) {
8 | const dirPath = path.join(process.cwd(), outDir);
9 | try {
10 | const dir = await fs.opendir(dirPath);
11 | await dir.close();
12 | } catch (e) {
13 | console.warn(`${outDir} cannot be read or isn't a directory.`);
14 | process.exit(1);
15 | }
16 | const specs = Object.values(pagesSpecs);
17 | await Promise.all(specs.map((s) => genPage(s, dirPath)));
18 | }
19 |
20 | program
21 | .version('0.1.0')
22 | .arguments('')
23 | .description('@doc/mdx-gen-cli command', {
24 | outDir: 'the directory in which mdx files should be generated'
25 | })
26 | .action(docMdxGen);
27 |
28 | program.parseAsync().catch((e) => {
29 | console.error(e);
30 | });
31 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/AdmonitionElement.ts:
--------------------------------------------------------------------------------
1 | import type { PropsWithChildren } from 'react';
2 | import NodeWithChildren from './NodeWithChildren';
3 |
4 | export type AdmonitionProps = PropsWithChildren<{
5 | type: string;
6 | title?: string;
7 | }>;
8 |
9 | export default class AdmonitionElement extends NodeWithChildren {
10 | props: AdmonitionProps;
11 | constructor(props: AdmonitionProps) {
12 | super();
13 | this.props = props;
14 | }
15 |
16 | toMdx(): string {
17 | const { type, title } = this.props;
18 | return `\n\n:::${type} ${title || ''}
19 |
20 | ${this.childrenToMdx()}
21 |
22 | :::\n\n`;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/AnchorElement.ts:
--------------------------------------------------------------------------------
1 | import NodeWithChildren from './NodeWithChildren';
2 | import assert from 'assert';
3 |
4 | export type AnchorElementProps = React.AnchorHTMLAttributes;
5 |
6 | export default class AnchorElement extends NodeWithChildren {
7 | props: AnchorElementProps;
8 | constructor(props: AnchorElementProps) {
9 | super();
10 | this.props = props;
11 | }
12 |
13 | toMdx(): string {
14 | const { href, children } = this.props;
15 | assert.strictEqual(
16 | typeof children,
17 | 'string',
18 | 'Anchor child must be a string'
19 | );
20 | return `[${this.childrenToMdx()}](${href})`;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/CodeBlockElement.ts:
--------------------------------------------------------------------------------
1 | import NodeWithChildren from './NodeWithChildren';
2 |
3 | export type CodeBlockElementProps = {
4 | lang: string;
5 | content: string;
6 | title?: string;
7 | showLineNumbers: boolean;
8 | };
9 |
10 | export default class CodeBlockElement extends NodeWithChildren {
11 | props: CodeBlockElementProps;
12 | constructor(props: CodeBlockElementProps) {
13 | super();
14 | this.props = props;
15 | }
16 |
17 | toMdx(): string {
18 | const { lang, title, content, showLineNumbers } = this.props;
19 | return `\n\n\`\`\`${lang} ${title ? `title="${title}"` : ''}
22 | ${content}
23 | \`\`\`\n\n
`;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/CodeElement.ts:
--------------------------------------------------------------------------------
1 | import NodeWithChildren from './NodeWithChildren';
2 | import assert from 'assert';
3 |
4 | export type CodeElementProps = React.AnchorHTMLAttributes;
5 |
6 | export default class CodeElement extends NodeWithChildren {
7 | props: CodeElementProps;
8 | constructor(props: CodeElementProps) {
9 | super();
10 | this.props = props;
11 | }
12 |
13 | toMdx(): string {
14 | const { children } = this.props;
15 | assert.strictEqual(
16 | typeof children,
17 | 'string',
18 | 'Code child must be a string'
19 | );
20 | return `\`${this.childrenToMdx(false)}\``;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/H2Element.ts:
--------------------------------------------------------------------------------
1 | import NodeWithChildren from './NodeWithChildren';
2 |
3 | export default class H2Element extends NodeWithChildren {
4 | constructor() {
5 | super();
6 | }
7 |
8 | toMdx(): string {
9 | return `\n\n## ${this.childrenToMdx()}\n\n`;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/H3Element.ts:
--------------------------------------------------------------------------------
1 | import NodeWithChildren from './NodeWithChildren';
2 |
3 | export default class H3Element extends NodeWithChildren {
4 | constructor() {
5 | super();
6 | }
7 |
8 | toMdx(): string {
9 | return `\n\n### ${this.childrenToMdx()}\n\n`;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/HTMLElement.ts:
--------------------------------------------------------------------------------
1 | import NodeWithChildren from './NodeWithChildren';
2 |
3 | class HTMLElement extends NodeWithChildren {
4 | props: any;
5 | tagName: string;
6 | inlineTags = ['abbr'];
7 | constructor(tagName: string, props: any) {
8 | super();
9 | this.props = props || {};
10 | this.tagName = tagName;
11 | }
12 |
13 | toMdx(): string {
14 | const identifiers = [this.tagName, ...this.getInlineProps(this.props)];
15 | const tagOpen = `<${identifiers.join(' ')}>`;
16 | const tagClose = `${this.tagName}>`;
17 | if (this.inlineTags.includes(this.tagName)) {
18 | // Circumvent MDX bug, see https://git.io/J3GEt
19 | return `​${tagOpen}${this.childrenToMdx()}${tagClose}`;
20 | }
21 | // Surround children with a line gap for proper Markdown parsing.
22 | return `${tagOpen}
23 |
24 | ${this.childrenToMdx()}
25 |
26 | ${tagClose}`;
27 | }
28 | }
29 |
30 | export default HTMLElement;
31 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/ParagraphElement.ts:
--------------------------------------------------------------------------------
1 | import NodeWithChildren from './NodeWithChildren';
2 |
3 | export type ParagraphElementProps = React.AnchorHTMLAttributes;
4 |
5 | export default class ParagraphElement extends NodeWithChildren {
6 | props: ParagraphElementProps;
7 | constructor(props: ParagraphElementProps) {
8 | super();
9 | this.props = props;
10 | }
11 |
12 | toMdx(): string {
13 | return `\n\n${this.childrenToMdx()}\n\n`;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/ReferenceElement.ts:
--------------------------------------------------------------------------------
1 | import MDXDocument from './MDXDocument';
2 | import NodeWithChildren from './NodeWithChildren';
3 |
4 | export interface ReferenceElementProps {
5 | name: string;
6 | full: boolean;
7 | url: string;
8 | member?: string;
9 | type: string;
10 | library?: string;
11 | plural?: boolean;
12 | }
13 |
14 | export default class ReferenceElement extends NodeWithChildren {
15 | props: ReferenceElementProps;
16 | constructor(props: ReferenceElementProps, root: MDXDocument) {
17 | super();
18 | this.props = props;
19 | root.registerImport('Reference');
20 | }
21 |
22 | toMdx(): string {
23 | const tagName = 'Reference';
24 | const identifiers = [tagName, ...this.getInlineProps(this.props)];
25 | return `​<${identifiers.join(' ')} />`;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/StrongElement.ts:
--------------------------------------------------------------------------------
1 | import NodeWithChildren from './NodeWithChildren';
2 | import assert from 'assert';
3 |
4 | export type StrongElementProps = React.AnchorHTMLAttributes;
5 |
6 | export default class StrongElement extends NodeWithChildren {
7 | props: StrongElementProps;
8 | constructor(props: StrongElementProps) {
9 | super();
10 | this.props = props;
11 | }
12 |
13 | toMdx(): string {
14 | const { children } = this.props;
15 | assert.strictEqual(
16 | typeof children,
17 | 'string',
18 | 'Bold children must be a string'
19 | );
20 | return `**${this.childrenToMdx()}**`;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/SvgFigureElement.ts:
--------------------------------------------------------------------------------
1 | import { SvgAssetType } from '@doc/pages';
2 | import MDXDocument from './MDXDocument';
3 | import NodeWithChildren from './NodeWithChildren';
4 |
5 | export type SvgFigureElementProps = {
6 | asset: SvgAssetType;
7 | description: string;
8 | title: string;
9 | };
10 |
11 | export default class SvgFigureElement extends NodeWithChildren {
12 | props: SvgFigureElementProps;
13 | constructor(props: SvgFigureElementProps, root: MDXDocument) {
14 | super();
15 | this.props = props;
16 | root.registerImport('SvgFigure');
17 | }
18 |
19 | toMdx(): string {
20 | const tagName = 'SvgFigure';
21 | const identifiers = [tagName, ...this.getInlineProps(this.props)];
22 | return `\n<${identifiers.join(' ')} />\n`;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/components/TNodeTransformDisplayElement.ts:
--------------------------------------------------------------------------------
1 | import MDXDocument from './MDXDocument';
2 | import NodeWithChildren from './NodeWithChildren';
3 |
4 | export interface TNodeTransformDisplayElementProps {
5 | title?: string;
6 | caption?: string;
7 | html: string;
8 | snapshot: string;
9 | }
10 |
11 | export default class TNodeTransformDisplayElement extends NodeWithChildren {
12 | props: TNodeTransformDisplayElementProps;
13 | constructor(props: TNodeTransformDisplayElementProps, root: MDXDocument) {
14 | super();
15 | this.props = props;
16 | root.registerImport('TNodeTransformDisplay');
17 | }
18 |
19 | toMdx(): string {
20 | const tagName = 'TNodeTransformDisplay';
21 | const { snapshot, html, ...inlineProps } = this.props;
22 | const identifiers = [tagName, ...this.getInlineProps(inlineProps)];
23 | return `\n<${identifiers.join(' ')} html="${encodeURIComponent(
24 | html
25 | )}" snapshot="${encodeURIComponent(snapshot)}" />\n`;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/encodeAttributeVal.ts:
--------------------------------------------------------------------------------
1 | import { encode } from 'html-entities';
2 |
3 | export default function encodeAttributeVal(attrVal: string) {
4 | return encode(attrVal);
5 | }
6 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/src/render/index.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | import { AdmonitionProps } from './components/AdmonitionElement';
3 | import { CodeBlockElementProps } from './components/CodeBlockElement';
4 | import { ReferenceElementProps } from './components/ReferenceElement';
5 | import { RenderHTMLCardElementProps } from './components/RenderHTMLCardElement';
6 | import { SvgFigureElementProps } from './components/SvgFigureElement';
7 | import { TNodeTransformDisplayElementProps } from './components/TNodeTransformDisplayElement';
8 | export { default as renderMdx } from './renderMdx';
9 |
10 | declare global {
11 | namespace JSX {
12 | interface IntrinsicElements {
13 | admonition: AdmonitionProps;
14 | codeblockds: CodeBlockElementProps;
15 | renderhtmlcard: RenderHTMLCardElementProps;
16 | svgfigure: SvgFigureElementProps;
17 | tnodetransformdisplay: TNodeTransformDisplayElementProps;
18 | reference: ReferenceElementProps;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/doc-tools/doc-mdx-gen-cli/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig-base.json",
3 | "compilerOptions": {
4 | "outDir": "./lib",
5 | "module": "CommonJS",
6 | "noEmit": false,
7 | "noImplicitAny": false,
8 | "lib": ["ES2019"],
9 | "jsx": "react"
10 | },
11 | "exclude": ["node_modules", "**/__tests__", "lib", "types"]
12 | }
13 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | /lib
3 | /types
4 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/.gitignore:
--------------------------------------------------------------------------------
1 | # CocoaPods
2 | /ios/Pods/
3 |
4 | # Jest code coverage
5 | /coverage
6 |
7 | # This library
8 | /lib/
9 |
10 | # api-extractor
11 | /temp
12 |
13 | # Types must be bundled with api-extractor, not included in the repo
14 | /types
15 |
16 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/README.md:
--------------------------------------------------------------------------------
1 | Documentation primitives for both mobile app and website.
--------------------------------------------------------------------------------
/doc-tools/doc-pages/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('../../babel-config-base');
2 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('../../jest-config-base');
2 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/Page.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment, PropsWithChildren } from 'react';
2 | import useToolkit from './toolkit/useToolkit';
3 |
4 | export default function Page({ children }: PropsWithChildren<{}>) {
5 | const { Container = Fragment } = useToolkit();
6 | return {children};
7 | }
8 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/__tests__/dummy.test.ts:
--------------------------------------------------------------------------------
1 | test('hello', () => {
2 | expect(true).toBe(true);
3 | });
4 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/acronymsIndex.ts:
--------------------------------------------------------------------------------
1 | import { Acronym, AcronymDefinition } from './pages-types';
2 |
3 | const acronymsIndex: Record = {
4 | TRE: {
5 | definition:
6 | 'A module capable of transforming a DOM tree into a Transient Render Tree',
7 | fullName: 'Transient Render Engine',
8 | name: 'TRE'
9 | },
10 | TRT: {
11 | definition: 'Structured data matching closely the React tree to render.',
12 | fullName: 'Transient Render Tree',
13 | name: 'TRT'
14 | },
15 | TNode: {
16 | definition: 'A node of the Transient Render Tree.',
17 | fullName: 'Transient Node',
18 | name: 'TNode'
19 | }
20 | };
21 |
22 | export default acronymsIndex;
23 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/components/InternalRendererAdmonition.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | import React, { PropsWithChildren } from 'react';
3 | import useToolkit from '../toolkit/useToolkit';
4 |
5 | export default function InternalRendererAdmonition({
6 | name,
7 | contentModel,
8 | children
9 | }: PropsWithChildren<{
10 | name: string;
11 | contentModel: 'block' | 'mixed';
12 | }>) {
13 | const { Admonition, RefDoc, RefTRE, Bold } = useToolkit();
14 | return (
15 |
16 | {name} are rendered with an internal renderer. See{' '}
17 | page. The content model of{' '}
18 | {name.toLowerCase()} is{' '}
19 | , see{' '}
20 |
21 | Element Models
22 |
23 | . {children}
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/components/ListItemCode.tsx:
--------------------------------------------------------------------------------
1 | import React, { PropsWithChildren } from 'react';
2 | import useToolkit from '../toolkit/useToolkit';
3 |
4 | export default function ListItemCode({
5 | name,
6 | children
7 | }: PropsWithChildren<{ name: string }>) {
8 | const { ListItem, InlineCode } = useToolkit();
9 | return (
10 |
11 | {name}
12 | {': '}
13 | {children}
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/components/RefCssProcessor.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import useToolkit from '../toolkit/useToolkit';
3 |
4 | const RefCssProcessor = ({}) => {
5 | const { RefLibrary } = useToolkit();
6 | return (
7 |
11 | );
12 | };
13 |
14 | export default RefCssProcessor;
15 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/components/RefHtmlparser2.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import useToolkit from '../toolkit/useToolkit';
3 |
4 | const RefHtmlparser2 = ({}) => {
5 | const { RefLibrary } = useToolkit();
6 | return (
7 |
11 | );
12 | };
13 |
14 | export default RefHtmlparser2;
15 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/components/RefRNRH.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import useToolkit from '../toolkit/useToolkit';
3 |
4 | const RefRNRH = ({}) => {
5 | const { RefLibrary } = useToolkit();
6 | return (
7 |
11 | );
12 | };
13 |
14 | export default RefRNRH;
15 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/components/RefTRE.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import useToolkit from '../toolkit/useToolkit';
3 |
4 | const RefTRE = ({}) => {
5 | const { RefLibrary } = useToolkit();
6 | return (
7 |
11 | );
12 | };
13 |
14 | export default RefTRE;
15 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/figuresIndex.ts:
--------------------------------------------------------------------------------
1 | import { SvgAssetType } from './toolkit/toolkit-types';
2 |
3 | const figuresIndex: Record<
4 | SvgAssetType,
5 | { description: string; title: string }
6 | > = {
7 | 'data-flow': {
8 | title: 'Data Flow Diagram',
9 | description:
10 | 'Depiction of data transformations involved in the rendering of an HTML snippet.'
11 | }
12 | };
13 |
14 | export default figuresIndex;
15 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './pages-types';
2 | export { default as ToolkitProvider } from './toolkit/ToolkitProvider';
3 | export * from './toolkit/toolkit-types';
4 | export { default as useToolkit } from './toolkit/useToolkit';
5 | export { default as pagesSpecs } from './pagesSpecs';
6 |
7 | import React from 'react';
8 | import { SvgProps } from 'react-native-svg';
9 |
10 | export type SvgComponent = React.ComponentType<
11 | SvgProps & {
12 | content: string;
13 | secondaryContent: string;
14 | codeBlockBg: string;
15 | }
16 | >;
17 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/anchorsBlockConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | This text can be clicked.
5 |
6 | An the image too!
7 | `;
8 |
9 | const anchorsBlockConfig: UIRenderHtmlCardProps = {
10 | title: 'Block Anchor Example',
11 | caption: '',
12 | props: {
13 | source: {
14 | html
15 | }
16 | },
17 | preferHtmlSrc: true
18 | };
19 |
20 | export default anchorsBlockConfig;
21 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/anchorsCustomConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 | import { Alert } from 'react-native';
3 |
4 | const html = `
7 | A link to MDN!
8 | `;
9 |
10 | function onPress(event: any, href: string) {
11 | Alert.alert(`You just pressed ${href}`);
12 | }
13 |
14 | const onPressSrc = `function onPress(event, href) {
15 | Alert.alert(\`You just pressed \${href}\`);
16 | }`;
17 |
18 | const anchorsCustomConfig: UIRenderHtmlCardProps = {
19 | title: 'Customizing Anchor Behavior',
20 | caption: '',
21 | props: {
22 | source: {
23 | html
24 | },
25 | renderersProps: {
26 | a: {
27 | onPress
28 | }
29 | }
30 | },
31 | preferHtmlSrc: false,
32 | config: {
33 | importStatements: [{ package: 'react-native', named: ['Alert'] }],
34 | fnSrcMap: {
35 | onPress: onPressSrc
36 | }
37 | }
38 | };
39 |
40 | export default anchorsCustomConfig;
41 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/anchorsMinimalConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
6 | A link to MDN!
7 | `;
8 |
9 | const anchorsMinimalConfig: UIRenderHtmlCardProps = {
10 | title: 'Minimal Anchor Example',
11 | props: {
12 | source: {
13 | html
14 | }
15 | },
16 | preferHtmlSrc: true
17 | };
18 |
19 | export default anchorsMinimalConfig;
20 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/anchorsRelativeConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 |
5 |
6 |
7 |
8 |
19 |
20 | `;
21 |
22 | const anchorsRelativeConfig: UIRenderHtmlCardProps = {
23 | title: 'Relative URLs Resolution Example',
24 | caption:
25 | 'Press any of the anchors and notice that the URL is being normalized from the base URL.',
26 | props: {
27 | source: {
28 | html
29 | }
30 | },
31 | preferHtmlSrc: true
32 | };
33 |
34 | export default anchorsRelativeConfig;
35 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/cssInheritanceConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | This text is centered!
5 |
`;
6 |
7 | const cssInheritanceConfig: UIRenderHtmlCardProps = {
8 | title: 'CSS Inheritance Example',
9 | caption: '',
10 | props: {
11 | source: {
12 | html
13 | }
14 | },
15 | preferHtmlSrc: true
16 | };
17 |
18 | export default cssInheritanceConfig;
19 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/customListThaiConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 | import thaiCounterStyle from '@jsamr/counter-style/presets/thai';
3 |
4 | const html = `
5 | - One
6 | - Two
7 | - Three
8 | - Four
9 | - Five
10 | - Six
11 | - Seven
12 | - Eight
13 |
`;
14 |
15 | const customListThaiConfig: UIRenderHtmlCardProps = {
16 | title: 'Thai List Style Type',
17 | props: {
18 | source: {
19 | html
20 | },
21 | customListStyleSpecs: {
22 | thai: {
23 | type: 'textual',
24 | counterStyleRenderer: thaiCounterStyle
25 | }
26 | }
27 | },
28 | config: {
29 | importStatements: [
30 | {
31 | package: '@jsamr/counter-style/presets/thai',
32 | default: 'thaiCounterStyle'
33 | }
34 | ],
35 | exprSrcMap: {
36 | counterStyleRenderer: 'thaiCounterStyle'
37 | }
38 | }
39 | };
40 |
41 | export default customListThaiConfig;
42 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/fontSelectionArial.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | Lorem ipsum dolor sit amet, consectetur adipiscing
5 | elit, sed do eiusmod tempor incididunt ut labore et
6 | dolore magna aliqua. Ut enim ad minim veniam, quis
7 | nostrud exercitation ullamco laboris nisi ut aliquip
8 | ex ea commodo consequat.
9 |
`;
10 |
11 | const fontSelectionArial: UIRenderHtmlCardProps = {
12 | title: 'Arial Font Selection',
13 | caption:
14 | 'This paragraph font family is set to "Arial" (will match on iOS, MacOS and Windows) and should fallback to sans-serif otherwise.',
15 | props: {
16 | source: {
17 | html
18 | },
19 | enableExperimentalMarginCollapsing: true
20 | },
21 | preferHtmlSrc: true
22 | };
23 |
24 | export default fontSelectionArial;
25 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/fontSelectionCourierNewConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | Lorem ipsum dolor sit amet, consectetur adipiscing
5 | elit, sed do eiusmod tempor incididunt ut labore et
6 | dolore magna aliqua. Ut enim ad minim veniam, quis
7 | nostrud exercitation ullamco laboris nisi ut aliquip
8 | ex ea commodo consequat.
9 |
`;
10 |
11 | const fontSelectionCourierNewConfig: UIRenderHtmlCardProps = {
12 | title: 'Courier New Font Selection',
13 | caption:
14 | 'This paragraph font family is set to "Courier New" (will match on iOS, MacOS and Windows) and should fallback to monospace otherwise.',
15 | props: {
16 | source: {
17 | html
18 | },
19 | enableExperimentalMarginCollapsing: true
20 | },
21 | preferHtmlSrc: true
22 | };
23 |
24 | export default fontSelectionCourierNewConfig;
25 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/ghostLineFixConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 |
5 |
6 |
7 | `;
8 |
9 | const ghostLineFixConfig: UIRenderHtmlCardProps = {
10 | title: 'Ghost lines fix',
11 | caption:
12 | 'enableExperimentalGhostLinePrevention prop will attempt to prevent this odd behavior, including with multiple empty tags and whitespaces.',
13 | props: {
14 | source: {
15 | html
16 | },
17 | enableExperimentalGhostLinesPrevention: true
18 | },
19 | preferHtmlSrc: true
20 | };
21 |
22 | export default ghostLineFixConfig;
23 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/ghostLineOddityConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 |
5 |
6 | `;
7 |
8 | const ghostLineOddityConfig: UIRenderHtmlCardProps = {
9 | title: 'Ghost lines in React Native',
10 | caption:
11 | 'The span element is rendered as an empty Text, but it takes vertical space, approximately 20dpi, independent of font size and line height.',
12 | props: {
13 | source: {
14 | html
15 | }
16 | },
17 | preferHtmlSrc: true
18 | };
19 |
20 | export default ghostLineOddityConfig;
21 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/inlineStylesConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 |
5 | Hello world!
6 |
7 |
`;
8 |
9 | const inlineStylesConfig: UIRenderHtmlCardProps = {
10 | title: 'Minimal Inline Styles Example',
11 | props: {
12 | source: {
13 | html
14 | }
15 | },
16 | preferHtmlSrc: true
17 | };
18 |
19 | export default inlineStylesConfig;
20 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/lineBreakBugConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | A line with a line break closing
5 | an inline formatting context.
6 |
7 | `;
8 |
9 | const lineBreakBugConfig: UIRenderHtmlCardProps = {
10 | title: 'Line break bug in v6',
11 | caption:
12 | 'A line break closing an inline formatting context should not be printed according to WHATWG HTML standard. Notice that there is an extraneous new line at the end of the sentence.',
13 | props: {
14 | source: {
15 | html
16 | }
17 | },
18 | preferHtmlSrc: true
19 | };
20 |
21 | export default lineBreakBugConfig;
22 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/lineBreakFixConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | A line with a line break closing
5 | an inline formatting context.
6 |
7 | `;
8 |
9 | const lineBreakFixConfig: UIRenderHtmlCardProps = {
10 | title: 'A fix to the line break bug',
11 | caption:
12 | 'enableExperimentalBRCollapsing prop prevents this bug from happening',
13 | props: {
14 | source: {
15 | html
16 | },
17 | enableExperimentalBRCollapsing: true
18 | },
19 | preferHtmlSrc: true
20 | };
21 |
22 | export default lineBreakFixConfig;
23 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/olUpperRomanConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | - One
5 | - Two
6 | - Three
7 | - Four
8 | - Five
9 | - Six
10 | - Seven
11 | - Eight
12 |
`;
13 |
14 | const olUpperRomanConfig: UIRenderHtmlCardProps = {
15 | title: 'Upper Roman List Style Type',
16 | caption:
17 | 'Notice how marker pseudo-elements will inherit from the styles of the tag.',
18 | props: {
19 | source: {
20 | html
21 | }
22 | },
23 | preferHtmlSrc: true
24 | };
25 |
26 | export default olUpperRomanConfig;
27 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/preformattedConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 |
5 | ___________________________
6 | < I'm an expert in my field. >
7 | ---------------------------
8 | \\ ^__^
9 | \\ (oo)\\_______
10 | (__)\\ )\\/\\
11 | ||----w |
12 | || ||
13 |
14 |
15 | A cow saying, "I'm an expert in my field." The cow is illustrated using preformatted text characters.
16 |
17 | `;
18 |
19 | const preformattedConfig: UIRenderHtmlCardProps = {
20 | title: 'Preformatted Text',
21 | caption:
22 | 'Notice that every white-space inside the tag is preserved while white-spaces outside are collapsed.',
23 | props: {
24 | source: {
25 | html
26 | }
27 | },
28 | preferHtmlSrc: true
29 | };
30 |
31 | export default preformattedConfig;
32 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/replaceDataConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 |
5 | Hi {{userName}}
6 | you have news today!
7 |
8 | `;
9 |
10 | const onTextSrc = `function onText(text) {
11 | text.data = text.data.replace(/\\{\\{userName\\}\\}/g, 'John Doe');
12 | }`;
13 |
14 | const replaceDataConfig: UIRenderHtmlCardProps = {
15 | title: 'Altering Text Data',
16 | caption:
17 | 'Usage of domVisitors.onText to resolve handlebar-style variable in text nodes data. Note that this example might cost render time on very big documents since it will apply to every text node. You might want to add conditional logic to target text nodes children of specific tags.',
18 | props: {
19 | source: { html },
20 | domVisitors: {
21 | onText(text) {
22 | text.data = text.data.replace(/\{\{userName\}\}/g, 'John Doe');
23 | }
24 | }
25 | },
26 | config: {
27 | fnSrcMap: {
28 | onText: onTextSrc
29 | }
30 | }
31 | };
32 |
33 | export default replaceDataConfig;
34 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/rtlListDiscConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | - واحد
5 | - اثنين
6 | - ثلاثة
7 | - أربعة
8 | - خمسة
9 | - ستة
10 | - سبعة
11 | - ثمانية
12 |
`;
13 |
14 | const rtlListDiscConfig: UIRenderHtmlCardProps = {
15 | title: 'RTL Mode with Arabic Counter Style',
16 | props: {
17 | source: {
18 | html
19 | },
20 | renderersProps: {
21 | ul: {
22 | enableExperimentalRtl: true
23 | }
24 | }
25 | }
26 | };
27 |
28 | export default rtlListDiscConfig;
29 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/selectableTextConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | This text can be selected.
5 | `;
6 |
7 | const selectableTextConfig: UIRenderHtmlCardProps = {
8 | title: 'Selectable text example',
9 | caption: '',
10 | props: {
11 | source: {
12 | html
13 | },
14 | defaultTextProps: {
15 | selectable: true
16 | }
17 | },
18 | preferHtmlSrc: false
19 | };
20 |
21 | export default selectableTextConfig;
22 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/ulSquareConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | - One
5 | - Two
6 | - Three
7 | - Four
8 | - Five
9 | - Six
10 | - Seven
11 | - Eight
12 |
`;
13 |
14 | const ulSquareConfig: UIRenderHtmlCardProps = {
15 | title: 'Square List Style Type',
16 | props: {
17 | source: {
18 | html
19 | }
20 | },
21 | preferHtmlSrc: true
22 | };
23 |
24 | export default ulSquareConfig;
25 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/whiteSpaceNormalConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | This is text!
5 |
6 | This is bold, italics.
7 |
`;
8 |
9 | const whiteSpaceNormalConfig: UIRenderHtmlCardProps = {
10 | title: 'Whitespace Collapsing in Action',
11 | caption:
12 | 'Notice that the four line breaks and the second space after the coma have been removed.',
13 | props: {
14 | source: {
15 | html
16 | }
17 | },
18 | preferHtmlSrc: true
19 | };
20 |
21 | export default whiteSpaceNormalConfig;
22 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/pages/cards/whiteSpacePreConfig.tsx:
--------------------------------------------------------------------------------
1 | import { UIRenderHtmlCardProps } from '../../toolkit/toolkit-types';
2 |
3 | const html = `
4 | This is text!
5 |
6 | This is bold, italics.
7 |
`;
8 |
9 | const whiteSpacePreConfig: UIRenderHtmlCardProps = {
10 | title: 'Whitespace Collapsing Disabled',
11 | caption:
12 | 'Notice that the four line breaks and the second space after the coma have been preserved.',
13 | props: {
14 | source: {
15 | html
16 | }
17 | },
18 | preferHtmlSrc: true
19 | };
20 |
21 | export default whiteSpacePreConfig;
22 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/toolkit/defaultImports.ts:
--------------------------------------------------------------------------------
1 | import { ImportStmt } from './toolkit-types';
2 |
3 | const defaultImports: Record = {
4 | react: {
5 | package: 'react',
6 | default: 'React'
7 | },
8 | 'react-native': {
9 | package: 'react-native',
10 | named: ['useWindowDimensions']
11 | },
12 | 'react-native-render-html': {
13 | package: 'react-native-render-html',
14 | default: 'RenderHtml'
15 | }
16 | };
17 |
18 | export default defaultImports;
19 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/toolkit/toolkitContext.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { UIToolkit } from './toolkit-types';
3 |
4 | const toolkitContext = React.createContext({} as any);
5 |
6 | export default toolkitContext;
7 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/src/toolkit/useToolkit.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { UIToolkit } from './toolkit-types';
3 | import toolkitContext from './toolkitContext';
4 |
5 | export default function useToolkit() {
6 | return React.useContext(toolkitContext) as UIToolkit;
7 | }
8 |
--------------------------------------------------------------------------------
/doc-tools/doc-pages/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig-base.json",
3 | "compilerOptions": {
4 | "outDir": "./lib",
5 | "target": "ESNext",
6 | "noEmit": false,
7 | "rootDir": "src",
8 | "jsx": "react"
9 | },
10 | "include": ["src/"],
11 | "exclude": ["**/__tests__"]
12 | }
13 |
--------------------------------------------------------------------------------
/doc-tools/doc-svg-component/index.d.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { SvgProps } from 'react-native-svg';
3 |
4 | export type SvgComponent = React.ComponentType<
5 | SvgProps & {
6 | content: string;
7 | secondaryContent: string;
8 | codeBlockBg: string;
9 | }
10 | >;
11 |
--------------------------------------------------------------------------------
/doc-tools/doc-svg-component/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@doc/svg-component",
3 | "types": "index.d.ts",
4 | "peerDependencies": {
5 | "react": "*",
6 | "react-native-svg": "*"
7 | },
8 | "devDependencies": {
9 | "react": "^17.0.2",
10 | "react-native-svg": "^12.1.1"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/doc-tools/doc-svgr-conf/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | replaceAttrValues: {
3 | '#f00': '{props.secondaryContent}',
4 | red: '{props.secondaryContent}',
5 | '#00f': '{props.content}',
6 | blue: '{props.content}',
7 | lightgray: '{props.codeBlockBg}',
8 | '#d3d3d3': '{props.codeBlockBg}'
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/doc-tools/doc-svgr-conf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@doc/svgr-conf",
3 | "main": "index.js",
4 | "private": true
5 | }
6 |
--------------------------------------------------------------------------------
/jest-config-base.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'react-native',
3 | moduleFileExtensions: ['ts', 'tsx', 'js', 'json', 'node'],
4 | testRegex: 'src/.*\\.test\\.tsx?$',
5 | coveragePathIgnorePatterns: ['/node_modules/', '__tests__'],
6 | transformIgnorePatterns: [
7 | 'node_modules/(?!(react-native|react-native-webview|ramda|react-native-render-html|@react-native)/)'
8 | ]
9 | };
10 |
--------------------------------------------------------------------------------
/packages/render-html/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/no-var-requires
2 | const defaultConf = require('../../.eslintrc.js');
3 | module.exports = {
4 | ...defaultConf,
5 | rules: {
6 | ...defaultConf.rules,
7 | '@typescript-eslint/member-ordering': [
8 | 'error',
9 | {
10 | default: {
11 | order: 'alphabetically'
12 | }
13 | }
14 | ]
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/packages/render-html/.gitignore:
--------------------------------------------------------------------------------
1 | README.md
--------------------------------------------------------------------------------
/packages/render-html/.release-it.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | git: {
3 | commitMessage: 'chore: release v${version}',
4 | // to release a changelog diff from a specific tag, uncoment
5 | changelog: 'git log --pretty=format:"* %s (%h)" v6.1.0...${to}'
6 | },
7 | npm: {
8 | publish: true
9 | },
10 | github: {
11 | release: true
12 | },
13 | plugins: {
14 | '@release-it/conventional-changelog': {
15 | preset: 'angular',
16 | infile: './CHANGELOG.md'
17 | }
18 | },
19 | hooks: {
20 | 'after:release': './scripts/post-release.sh ${name} ${version}'
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/packages/render-html/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset']
3 | };
4 |
--------------------------------------------------------------------------------
/packages/render-html/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require('../../jest-config-base'),
3 | setupFiles: ['/jest/setup.ts'],
4 | setupFilesAfterEnv: ['/jest/setupAfterEnv.ts']
5 | };
6 |
--------------------------------------------------------------------------------
/packages/render-html/jest/setup.ts:
--------------------------------------------------------------------------------
1 | //@ts-expect-error __DEV__ does not exists at top-level
2 | global.__DEV__ = true;
3 |
4 | //@ts-expect-error performance does not exists at top-level
5 | global.performance = {
6 | now() {
7 | const [seconds, nano] = process.hrtime();
8 | return seconds * 1000000 + nano / 1000;
9 | }
10 | };
11 |
12 | console.warn = () => {};
13 |
--------------------------------------------------------------------------------
/packages/render-html/jest/setupAfterEnv.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-native';
2 | import '@testing-library/jest-native/extend-expect';
3 |
--------------------------------------------------------------------------------
/packages/render-html/scripts/prepack.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cp ../../README.md .
4 | sed -i 's/\.\//https:\/\/github.com\/meliorence\/react-native-render-html\/blob\/master\//g' README.md
--------------------------------------------------------------------------------
/packages/render-html/src/RenderTTree.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import ttreeEventsContext from './context/ttreeEventsContext';
3 | import useTTree from './hooks/useTTree';
4 | import { RenderTTreeProps } from './internal-types';
5 | import TDocumentRenderer from './TDocumentRenderer';
6 |
7 | export default function RenderTTree(props: RenderTTreeProps) {
8 | const ttree = useTTree(props);
9 | const { onDocumentMetadataLoaded } = useContext(ttreeEventsContext);
10 | return (
11 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/packages/render-html/src/SourceLoaderDom.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { SourceLoaderProps } from './internal-types';
3 | import RenderTTree from './RenderTTree';
4 | import { HTMLSourceDom } from './shared-types';
5 |
6 | export type DomSourceLoaderProps = {
7 | source: HTMLSourceDom;
8 | } & SourceLoaderProps;
9 |
10 | export default function SourceLoaderDom(props: DomSourceLoaderProps) {
11 | return React.createElement(RenderTTree, {
12 | document: props.source.dom,
13 | baseUrl: props.source.baseUrl
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/packages/render-html/src/SourceLoaderInline.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { SourceLoaderProps } from './internal-types';
3 | import RenderTTree from './RenderTTree';
4 | import { HTMLSourceInline } from './shared-types';
5 |
6 | export type InlineSourceLoaderProps = {
7 | source: HTMLSourceInline;
8 | } & SourceLoaderProps;
9 |
10 | function useInlineSourceLoader({
11 | source,
12 | onHTMLLoaded
13 | }: InlineSourceLoaderProps) {
14 | const html = source.html;
15 | useEffect(() => {
16 | html && onHTMLLoaded?.call(null, html);
17 | }, [html, onHTMLLoaded]);
18 | return source;
19 | }
20 |
21 | export default function SourceLoaderInline(props: InlineSourceLoaderProps) {
22 | const { html } = useInlineSourceLoader(props);
23 | return React.createElement(RenderTTree, {
24 | document: html,
25 | baseUrl: props.source.baseUrl
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/packages/render-html/src/TChildrenRenderer.tsx:
--------------------------------------------------------------------------------
1 | import { FunctionComponent } from 'react';
2 | import { TChildrenRendererProps } from './shared-types';
3 | import renderChildren from './renderChildren';
4 |
5 | /**
6 | * A component to render collections of tnodes.
7 | * Especially useful when used with {@link useTNodeChildrenProps}.
8 | */
9 | const TChildrenRenderer: FunctionComponent =
10 | renderChildren.bind(null);
11 |
12 | export default TChildrenRenderer;
13 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/__snapshots__/component.render-html.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`RenderHTML regarding customHTMLElementsModels prop should support changing block content model to mixed 1`] = `
4 | "
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | "
14 | `;
15 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/component.generic-pressable.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Platform } from 'react-native';
3 | import { render } from '@testing-library/react-native';
4 | import GenericPressable from '../GenericPressable';
5 | import RenderHTMLConfigProvider from '../RenderHTMLConfigProvider';
6 | import TRenderEngineProvider from '../TRenderEngineProvider';
7 |
8 | describe('GenericPressable', () => {
9 | it('should render TouchableHighlight by default', () => {
10 | render();
11 | });
12 | it('should use provided GenericPressable', () => {
13 | const CustomGenericPressable = jest.fn(() => null);
14 | render(
15 |
16 |
17 |
18 |
19 |
20 | );
21 | expect(CustomGenericPressable).toHaveBeenCalled();
22 | });
23 | it('should render TouchableNativeFeedback on Android', () => {
24 | Platform.OS = 'android';
25 | render();
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.118.white-space-handling.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import RenderHTML from '../RenderHTML';
3 | import renderer from 'react-test-renderer';
4 | import { extractTextFromInstance } from './utils';
5 |
6 | beforeAll(() => {
7 | jest.useFakeTimers();
8 | });
9 |
10 | /**
11 | * https://github.com/meliorence/react-native-render-html/issues/118
12 | */
13 | describe('RenderHTML component', () => {
14 | it('should pass regression #118 regarding handling of CSS white-space', () => {
15 | const testRenderer = renderer.create(
16 | foo\n\nbar baz ' }}
19 | />
20 | );
21 | const renderedText = extractTextFromInstance(testRenderer.root);
22 | expect(renderedText).toEqual('foo bar baz');
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.141.custom-blur-image.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react-native';
3 | import IMGElement from '../elements/IMGElement';
4 |
5 | /**
6 | * https://github.com/meliorence/react-native-render-html/issues/141
7 | */
8 | describe('HTMLImageElement component should pass regression test #141', () => {
9 | it("doesn't display the image prior to receiving original dimensions", async () => {
10 | const source = { uri: 'http://via.placeholder.com/640x360' };
11 | const style = {};
12 | const { findByTestId, getByTestId, queryByTestId } = render(
13 |
14 | );
15 | const placeholder = getByTestId('image-loading');
16 | expect(placeholder).toBeTruthy();
17 | const imageLayout = queryByTestId('image-success');
18 | expect(imageLayout).toBeFalsy();
19 | await expect(
20 | findByTestId('image-success', { timeout: 100 })
21 | ).resolves.toBeTruthy();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.172.custom-image-resize-mode.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react-native';
3 | import RenderHTML from '../RenderHTML';
4 |
5 | /**
6 | * https://github.com/meliorence/react-native-render-html/issues/172
7 | */
8 | describe('HTMLImageElement component should pass regression test #172', () => {
9 | it('passes resizeMode to RN Image component', async () => {
10 | const tagsStyles = {
11 | img: {
12 | resizeMode: 'contain',
13 | width: 100,
14 | height: 100
15 | }
16 | };
17 | const { getByTestId } = render(
18 | '
22 | }}
23 | tagsStyles={tagsStyles as any}
24 | />
25 | );
26 | const image = getByTestId('image-success');
27 | expect(image).toHaveStyle(tagsStyles.img);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.257.css-display-rule.test.tsx:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react-native';
2 | import { expectTranslatedInlineCSSToMatchObject } from './utils';
3 |
4 | /**
5 | * https://github.com/meliorence/react-native-render-html/issues/257
6 | */
7 | describe('HTML component', () => {
8 | it('should pass regression #257 regarding inline display CSS rules', () => {
9 | expectTranslatedInlineCSSToMatchObject({
10 | cssInlineRules: 'display: inline-block;',
11 | render,
12 | reactNativeStyle: {}
13 | });
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.319.css-border-rule.test.tsx:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react-native';
2 | import { expectTranslatedInlineCSSRuleTo } from './utils';
3 |
4 | /**
5 | * https://github.com/meliorence/react-native-render-html/issues/319
6 | */
7 | describe('HTML component', () => {
8 | it('should pass regression #319 regarding inline border-style CSS rules', () => {
9 | expectTranslatedInlineCSSRuleTo({
10 | cssInlineRules: 'border-style: none;',
11 | render,
12 | test: (style) => expect(style.borderStyle).toBeUndefined()
13 | });
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.344.css-inline-inheritance-override.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import RenderHTML from '../RenderHTML';
3 | import { render } from '@testing-library/react-native';
4 |
5 | /**
6 | * https://github.com/meliorence/react-native-render-html/issues/344
7 | */
8 | describe('RenderHTML component should pass regression #344', () => {
9 | it('when anchors nested in paragraphs have their tagStyles overridden by inline inheritance', () => {
10 | const tagsStyles = {
11 | p: {
12 | color: 'red'
13 | },
14 | a: {
15 | color: 'green'
16 | }
17 | };
18 | const { getByTestId } = render(
19 |
foobar
' }}
23 | />
24 | );
25 | const text = getByTestId('a');
26 | expect(text).toHaveStyle({
27 | color: 'green'
28 | });
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.361.css-margin-rule.test.tsx:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react-native';
2 | import { expectTranslatedInlineCSSRuleTo } from './utils';
3 |
4 | /**
5 | * https://github.com/meliorence/react-native-render-html/issues/361
6 | */
7 | describe('HTML component', () => {
8 | it('should pass regression #361 regarding inline margin CSS rules', () => {
9 | expectTranslatedInlineCSSRuleTo({
10 | cssInlineRules: 'margin: none;',
11 | render,
12 | test: (style) => expect(style.margin).toBeUndefined()
13 | });
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.383.html-bloated-anchor.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import RenderHTML from '../RenderHTML';
3 | import { render } from '@testing-library/react-native';
4 |
5 | /**
6 | * https://github.com/meliorence/react-native-render-html/issues/383
7 | **/
8 | describe('RenderHTML component', () => {
9 | describe('should pass regression regarding RenderHTML props passed to anchor renderer', () => {
10 | it('translated anchor elements should not contain a renderers prop', () => {
11 | const { getByText } = render(
12 | bar' }} />
13 | );
14 | const anchor = getByText('bar');
15 | expect(anchor).not.toHaveProp('renderers');
16 | });
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.384.html-bloated-image.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import RenderHTML from '../RenderHTML';
3 | import { render } from '@testing-library/react-native';
4 | import IMGElement from '../elements/IMGElement';
5 |
6 | /**
7 | * https://github.com/meliorence/react-native-render-html/issues/384
8 | **/
9 | describe('RenderHTML component', () => {
10 | describe('should pass regression regarding RenderHTML props passed to image renderer', () => {
11 | it('translated image elements should not contain a renderers prop', () => {
12 | const { UNSAFE_getByType } = render(
13 | ' }}
16 | />
17 | );
18 | const image = UNSAFE_getByType(IMGElement);
19 | expect(image).not.toHaveProp('renderers');
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/regression.408.img-url-two-forward-slashes.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import RenderHTML from '../RenderHTML';
3 | import { render } from '@testing-library/react-native';
4 | import IMGElement from '../elements/IMGElement';
5 |
6 | /**
7 | * https://github.com/meliorence/react-native-render-html/issues/408
8 | */
9 | describe('RenderHTML component', () => {
10 | describe('should pass regression #408 regarding two forward slashes in src', () => {
11 | it("should prepend 'https:' to an image src attribute with two forward slashes", () => {
12 | const { UNSAFE_getByType } = render(
13 | ',
17 | baseUrl: 'https://test.com'
18 | }}
19 | />
20 | );
21 | const image = UNSAFE_getByType(IMGElement);
22 | expect(image).toHaveProp('source', { uri: 'https://domain.com/' });
23 | });
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/packages/render-html/src/__tests__/w3c.html.pre.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import RenderHTML from '../RenderHTML';
3 | import renderer from 'react-test-renderer';
4 | import { extractTextFromInstance } from './utils';
5 |
6 | describe('RenderHTML component regarding tags behaviors', () => {
7 | it('preserves tabs and line breaks', () => {
8 | const testRenderer = renderer.create(
9 | \t\n a
' }} />
10 | );
11 | const renderedText = extractTextFromInstance(testRenderer.root);
12 | expect(renderedText).toEqual('\t\n a');
13 | });
14 | it('preserves indentation and line breaks', () => {
15 | const preContent = `
16 | function myJSFunction() {
17 | console.log("let's go");
18 | console.log("let's go");
19 | console.log("let's go");
20 | }
21 | `;
22 | const testRenderer = renderer.create(
23 | ${preContent}` }} />
24 | );
25 | const renderedText = extractTextFromInstance(testRenderer.root);
26 | expect(renderedText).toEqual(preContent);
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/packages/render-html/src/constants.ts:
--------------------------------------------------------------------------------
1 | const DEFAULT_TEXT_COLOR = 'black';
2 | const DEFAULT_PRESSABLE_RIPPLE_COLOR = 'rgba(38, 132, 240, 0.2)';
3 |
4 | const constants = {
5 | DEFAULT_PRESSABLE_RIPPLE_COLOR,
6 | DEFAULT_TEXT_COLOR
7 | };
8 |
9 | export { DEFAULT_TEXT_COLOR, DEFAULT_PRESSABLE_RIPPLE_COLOR };
10 |
11 | export default constants;
12 |
--------------------------------------------------------------------------------
/packages/render-html/src/context/DocumentMetadataProvider.ts:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { DocumentMetadata } from '../shared-types';
3 |
4 | const DocumentMetadataContext = React.createContext({
5 | baseUrl: '',
6 | baseTarget: '_self',
7 | lang: 'en',
8 | links: [],
9 | meta: [],
10 | title: '',
11 | dir: 'ltr'
12 | });
13 |
14 | const DocumentMetadataProvider = DocumentMetadataContext.Provider;
15 |
16 | /**
17 | * Get access to the parsed HTML metadata anywhere in the render tree.
18 | */
19 | export function useDocumentMetadata() {
20 | return useContext(DocumentMetadataContext);
21 | }
22 |
23 | export default DocumentMetadataProvider;
24 |
--------------------------------------------------------------------------------
/packages/render-html/src/context/TChildrenRendererContext.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import type TNodeChildrenRenderer from '../TNodeChildrenRenderer';
3 | import type TChildrenRenderer from '../TChildrenRenderer';
4 |
5 | /**
6 | * This context allows dependency injection to avoid circular dependencies.
7 | */
8 | const TChildrenRenderersContext = React.createContext<{
9 | TChildrenRenderer: typeof TChildrenRenderer;
10 | TNodeChildrenRenderer: typeof TNodeChildrenRenderer;
11 | }>({
12 | TChildrenRenderer: null as any,
13 | TNodeChildrenRenderer: null as any
14 | });
15 |
16 | export function useTNodeChildrenRenderer() {
17 | return React.useContext(TChildrenRenderersContext).TNodeChildrenRenderer;
18 | }
19 |
20 | export function useTChildrenRenderer() {
21 | return React.useContext(TChildrenRenderersContext).TChildrenRenderer;
22 | }
23 |
24 | export default TChildrenRenderersContext;
25 |
--------------------------------------------------------------------------------
/packages/render-html/src/context/__tests__/defaultRendererProps.test.ts:
--------------------------------------------------------------------------------
1 | import { Linking } from 'react-native';
2 | import { defaultAOnPress } from '../defaultRendererProps';
3 |
4 | describe('defaultRendererProps', () => {
5 | describe('defaultAOnPress', () => {
6 | it('should not throw', async () => {
7 | Linking.canOpenURL = jest.fn(async () => false);
8 | await expect(defaultAOnPress({}, 'hi')).resolves.not.toThrow();
9 | Linking.canOpenURL = jest.fn(async () => true);
10 | await expect(
11 | defaultAOnPress({}, 'https://domain.com')
12 | ).resolves.not.toThrow();
13 | });
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/packages/render-html/src/context/__tests__/useAmbientTRenderEngine.test.ts:
--------------------------------------------------------------------------------
1 | import { renderHook } from '@testing-library/react-hooks';
2 | import { useAmbientTRenderEngine } from '../../TRenderEngineProvider';
3 |
4 | describe('useAmbientTRenderEngine', () => {
5 | it('should warn user when there is no ambient TRenderEngine', () => {
6 | console.error = jest.fn();
7 | renderHook(() => useAmbientTRenderEngine());
8 | expect(console.error).toHaveBeenCalledWith(
9 | 'TRenderEngineProvider is missing in the render tree.'
10 | );
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/packages/render-html/src/context/contentWidthContext.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 |
4 | const contentWidthContext = React.createContext(Dimensions.get('window').width);
5 |
6 | export default contentWidthContext;
7 |
--------------------------------------------------------------------------------
/packages/render-html/src/context/defaultRendererProps.ts:
--------------------------------------------------------------------------------
1 | import { Linking } from 'react-native';
2 | import { RenderersProps } from '../shared-types';
3 |
4 | export async function defaultAOnPress(_e: any, href: string): Promise {
5 | try {
6 | await Linking.openURL(href);
7 | } catch (e) {
8 | console.warn(`Could not open URL "${href}".`, e);
9 | }
10 | return null;
11 | }
12 |
13 | const defaultRendererProps: Required = {
14 | img: {
15 | initialDimensions: {
16 | height: 50,
17 | width: 50
18 | },
19 | enableExperimentalPercentWidth: false
20 | },
21 | a: {
22 | onPress: defaultAOnPress
23 | },
24 | ol: {},
25 | ul: {}
26 | };
27 |
28 | export default defaultRendererProps;
29 |
--------------------------------------------------------------------------------
/packages/render-html/src/context/ttreeEventsContext.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 | import { TTreeEvents } from '../internal-types';
3 |
4 | const ttreeEventsContext = createContext({});
5 |
6 | export default ttreeEventsContext;
7 |
--------------------------------------------------------------------------------
/packages/render-html/src/defaultSystemFonts.android.ts:
--------------------------------------------------------------------------------
1 | const defaultSystemFonts = [
2 | 'Roboto',
3 | 'notoserif',
4 | 'sans-serif-light',
5 | 'sans-serif-thin',
6 | 'sans-serif-medium'
7 | ];
8 |
9 | export default defaultSystemFonts;
10 |
--------------------------------------------------------------------------------
/packages/render-html/src/defaultSystemFonts.ios.ts:
--------------------------------------------------------------------------------
1 | const defaultSystemFonts = [
2 | 'San Francisco',
3 | 'Arial',
4 | 'ArialHebrew',
5 | 'Avenir',
6 | 'Baskerville',
7 | 'Bodoni 72',
8 | 'Bradley Hand',
9 | 'Chalkboard SE',
10 | 'Cochin',
11 | 'Copperplate',
12 | 'Courier',
13 | 'Courier New',
14 | 'Damascus',
15 | 'Didot',
16 | 'Futura',
17 | 'Geeza Pro',
18 | 'Georgia',
19 | 'Gill Sans',
20 | 'Helvetica',
21 | 'Helvetica Neue',
22 | 'Hiragino Sans',
23 | 'Hoefler Text',
24 | 'Iowan Old Style',
25 | 'Kailasa',
26 | 'Khmer Sangam MN',
27 | 'Marker Felt',
28 | 'Menlo',
29 | 'Mishafi',
30 | 'Noteworthy',
31 | 'Optima',
32 | 'Palatino',
33 | 'Papyrus',
34 | 'Savoye LET',
35 | 'Symbol',
36 | 'Thonburi',
37 | 'Times New Roman',
38 | 'Trebuchet MS',
39 | 'Verdana',
40 | 'Zapf Dingbats',
41 | 'Zapfino'
42 | ];
43 |
44 | export default defaultSystemFonts;
45 |
--------------------------------------------------------------------------------
/packages/render-html/src/defaultSystemFonts.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Default system fonts based on current platform.
3 | *
4 | * @remarks If you are using Expo, use `Constants.systemFonts` instead.
5 | */
6 | const defaultSystemFonts = ['Arial', 'Courier New', 'Georgia'];
7 | export default defaultSystemFonts;
8 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/IMGElementContentAlt.tsx:
--------------------------------------------------------------------------------
1 | import React, { PropsWithChildren, ReactElement } from 'react';
2 | import { StyleSheet, Text, View } from 'react-native';
3 | import { IMGElementStateBase } from './img-types';
4 |
5 | const styles = StyleSheet.create({
6 | altBox: {
7 | borderWidth: StyleSheet.hairlineWidth,
8 | overflow: 'hidden',
9 | justifyContent: 'center'
10 | },
11 | altText: { textAlign: 'center', fontStyle: 'italic' }
12 | });
13 |
14 | /**
15 | * Alt view for the {@link IMGElement} component.
16 | */
17 | export default function IMGElementContentAlt({
18 | dimensions,
19 | alt,
20 | altColor,
21 | testID,
22 | children
23 | }: PropsWithChildren): ReactElement {
24 | return (
25 |
30 | {alt}
31 | {children}
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/IMGElementContentError.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactElement } from 'react';
2 | import { IMGElementStateError } from './img-types';
3 | import IMGElementContentAlt from './IMGElementContentAlt';
4 |
5 | /**
6 | * Default error view for the {@link IMGElement} component.
7 | */
8 | export default function IMGElementContentError(
9 | props: IMGElementStateError
10 | ): ReactElement {
11 | return ;
12 | }
13 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/IMGElementContentLoading.tsx:
--------------------------------------------------------------------------------
1 | import React, { PropsWithChildren, ReactElement } from 'react';
2 | import { View } from 'react-native';
3 | import { IMGElementStateLoading } from './img-types';
4 |
5 | /**
6 | * Default loading view for the {@link IMGElement} component.
7 | */
8 | export default function IMGElementContentLoading({
9 | dimensions,
10 | children
11 | }: PropsWithChildren): ReactElement {
12 | return (
13 |
14 | {children}
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/IMGElementContentSuccess.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactElement, useCallback } from 'react';
2 | import {
3 | Image,
4 | ImageErrorEventData,
5 | ImageStyle,
6 | NativeSyntheticEvent
7 | } from 'react-native';
8 | import { IMGElementStateSuccess } from './img-types';
9 |
10 | const defaultImageStyle: ImageStyle = { resizeMode: 'cover' };
11 |
12 | /**
13 | * Default success "image" view for the {@link IMGElement} component.
14 | */
15 | export default function IMGElementContentSuccess({
16 | source,
17 | imageStyle,
18 | dimensions,
19 | onError
20 | }: IMGElementStateSuccess): ReactElement {
21 | const onImageError = useCallback(
22 | ({ nativeEvent: { error } }: NativeSyntheticEvent) =>
23 | onError(error),
24 | [onError]
25 | );
26 | return (
27 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/OLElement.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ListElement, { ListElementProps } from './ListElement';
3 |
4 | export type OLElementProps = Omit, 'listType'>;
5 | export default function OLElement(props: OLElementProps) {
6 | return React.createElement(ListElement, { ...props, listType: 'ol' });
7 | }
8 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/ULElement.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ListElement, { ListElementProps } from './ListElement';
3 |
4 | export type ULElementProps = Omit, 'listType'>;
5 |
6 | export default function ULElement(props: ULElementProps) {
7 | return React.createElement(ListElement, {
8 | ...props,
9 | listType: 'ul'
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/__tests__/getStringPrefixFromIndex.test.ts:
--------------------------------------------------------------------------------
1 | import { getStringPrefixFromIndex } from '../getStringListPrefixFromIndex';
2 |
3 | describe('getStringPrefixFromIndex', () => {
4 | it('should return a one-length caracter when index < modulo', () => {
5 | expect(getStringPrefixFromIndex(0, 97, 26)).toEqual('a');
6 | expect(getStringPrefixFromIndex(1, 97, 26)).toEqual('b');
7 | });
8 | it('should return a two-length caracter when index > 1 mod && index < 2 mod', () => {
9 | expect(getStringPrefixFromIndex(26, 97, 26)).toEqual('aa');
10 | expect(getStringPrefixFromIndex(26 * 8, 97, 26)).toEqual('ha');
11 | expect(getStringPrefixFromIndex(27, 97, 26)).toEqual('ab');
12 | expect(getStringPrefixFromIndex(26 * 2 + 2, 97, 26)).toEqual('bc');
13 | expect(getStringPrefixFromIndex(26 * 27, 97, 26)).toEqual('aaa');
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/defaultInitialImageDimensions.ts:
--------------------------------------------------------------------------------
1 | import { ImageDimensions } from '../shared-types';
2 |
3 | const defaultImageInitialDimensions: ImageDimensions = {
4 | width: 100,
5 | height: 100
6 | };
7 |
8 | export default defaultImageInitialDimensions;
9 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/getDimensionsWithAspectRatio.ts:
--------------------------------------------------------------------------------
1 | export default function getDimensionsWithAspectRatio(
2 | width: number | null,
3 | height: number | null,
4 | aspectRatio: number | undefined
5 | ) {
6 | return {
7 | width: width ?? (aspectRatio && height ? height * aspectRatio : null),
8 | height: height ?? (aspectRatio && width ? width / aspectRatio : null)
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/getStringListPrefixFromIndex.ts:
--------------------------------------------------------------------------------
1 | export function getStringPrefixFromIndex(
2 | index: number,
3 | baseCharcode: number,
4 | modulo: number
5 | ): string {
6 | if (index < modulo) {
7 | return String.fromCharCode(baseCharcode + index);
8 | }
9 | const rest = index % modulo;
10 | const next = (index - rest - modulo) / modulo;
11 | return (
12 | getStringPrefixFromIndex(next, baseCharcode, modulo) +
13 | String.fromCharCode(baseCharcode + rest)
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/symbolic/CircleSymbolRenderer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { UnitaryCounterRendererProps } from '../../shared-types';
4 | import useSymbolicMarkerRendererProps from './useSymbolicMarkerRendererStyles';
5 |
6 | export default function CircleSymbolRenderer(
7 | props: UnitaryCounterRendererProps
8 | ) {
9 | const { prefixSize, prefixStyle } = useSymbolicMarkerRendererProps(props);
10 | const style = {
11 | borderColor: props.color,
12 | borderWidth: prefixSize / 10,
13 | borderRadius: prefixSize,
14 | ...prefixStyle
15 | };
16 | return ;
17 | }
18 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/symbolic/DiscSymbolRenderer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { UnitaryCounterRendererProps } from '../../shared-types';
4 | import useSymbolicMarkerRendererProps from './useSymbolicMarkerRendererStyles';
5 |
6 | export default function DiscSymbolRenderer(props: UnitaryCounterRendererProps) {
7 | const { prefixSize, prefixStyle } = useSymbolicMarkerRendererProps(props);
8 | const style = {
9 | borderRadius: prefixSize,
10 | backgroundColor: props.color,
11 | ...prefixStyle
12 | };
13 | return ;
14 | }
15 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/symbolic/DisclosureClosedSymbolRenderer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { UnitaryCounterRendererProps } from '../../shared-types';
4 | import useSymbolicMarkerRendererProps from './useSymbolicMarkerRendererStyles';
5 |
6 | export default function DisclosureClosedSymbolRenderer(
7 | props: UnitaryCounterRendererProps
8 | ) {
9 | const {
10 | prefixStyle: { top },
11 | prefixSize
12 | } = useSymbolicMarkerRendererProps(props, 1);
13 | return React.createElement(View, {
14 | style: {
15 | top,
16 | width: 0,
17 | height: 0,
18 | borderStyle: 'solid',
19 | borderLeftWidth: prefixSize,
20 | borderLeftColor: props.color,
21 | borderTopWidth: prefixSize / 2,
22 | borderTopColor: 'transparent',
23 | borderBottomWidth: prefixSize / 2,
24 | borderBottomColor: 'transparent'
25 | }
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/symbolic/DisclosureOpenSymbolRenderer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { UnitaryCounterRendererProps } from '../../shared-types';
4 | import useSymbolicMarkerRendererProps from './useSymbolicMarkerRendererStyles';
5 |
6 | export default function DisclosureOpenSymbolRenderer(
7 | props: UnitaryCounterRendererProps
8 | ) {
9 | const {
10 | prefixStyle: { top },
11 | prefixSize
12 | } = useSymbolicMarkerRendererProps(props, 1);
13 | return React.createElement(View, {
14 | style: {
15 | top,
16 | width: 0,
17 | height: 0,
18 | borderStyle: 'solid',
19 | borderTopWidth: prefixSize,
20 | borderTopColor: props.color,
21 | borderLeftWidth: prefixSize / 2,
22 | borderLeftColor: 'transparent',
23 | borderRightWidth: prefixSize / 2,
24 | borderRightColor: 'transparent'
25 | }
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/symbolic/SquareSymbolRenderer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { UnitaryCounterRendererProps } from '../../shared-types';
4 | import useSymbolicMarkerRendererProps from './useSymbolicMarkerRendererStyles';
5 |
6 | export default function SquareSymbolRenderer(
7 | props: UnitaryCounterRendererProps
8 | ) {
9 | const { prefixStyle } = useSymbolicMarkerRendererProps(props, 1.2);
10 | return React.createElement(View, {
11 | style: {
12 | backgroundColor: props.color,
13 | ...prefixStyle
14 | }
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/symbolic/useSymbolicMarkerRendererStyles.ts:
--------------------------------------------------------------------------------
1 | import { UnitaryCounterRendererProps } from '../../shared-types';
2 |
3 | export default function useSymbolicMarkerRendererProps(
4 | props: UnitaryCounterRendererProps,
5 | shrinkFactor = 1
6 | ) {
7 | const prefixSize = props.fontSize / (shrinkFactor * 2.8);
8 | return {
9 | prefixSize,
10 | prefixStyle: {
11 | width: prefixSize,
12 | height: prefixSize,
13 | // center the item vertically, relative to line height
14 | top: (props.lineHeight - prefixSize) / 2
15 | }
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/packages/render-html/src/elements/useIMGNormalizedSource.ts:
--------------------------------------------------------------------------------
1 | import { useMemo, useRef } from 'react';
2 | import { useSharedProps } from '../context/SharedPropsProvider';
3 | import {
4 | IncompleteImageDimensions,
5 | UseIMGElementStateProps
6 | } from './img-types';
7 |
8 | export default function useIMGNormalizedSource({
9 | source,
10 | specifiedDimensions
11 | }: Pick & {
12 | specifiedDimensions: IncompleteImageDimensions;
13 | }) {
14 | const cachedDimensions = useRef(specifiedDimensions);
15 | const { provideEmbeddedHeaders } = useSharedProps();
16 | return useMemo(() => {
17 | if (source.uri && typeof provideEmbeddedHeaders === 'function') {
18 | const headers = provideEmbeddedHeaders(source.uri, 'img', {
19 | printWidth: cachedDimensions.current?.width || undefined,
20 | printHeight: cachedDimensions.current?.height || undefined
21 | });
22 | if (headers) {
23 | return {
24 | headers,
25 | ...source
26 | };
27 | }
28 | }
29 | return source;
30 | }, [provideEmbeddedHeaders, source]);
31 | }
32 |
--------------------------------------------------------------------------------
/packages/render-html/src/helpers/__tests__/selectSharedProps.test.ts:
--------------------------------------------------------------------------------
1 | import selectSharedProps from '../selectSharedProps';
2 |
3 | describe('selectSharedProps', () => {
4 | it('should default to default values', () => {
5 | expect(selectSharedProps({ debug: undefined }).debug).toEqual(false);
6 | });
7 | it('should retain non-nil values', () => {
8 | expect(selectSharedProps({ debug: true }).debug).toEqual(true);
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/packages/render-html/src/helpers/__tests__/splitBoxModelStyle.test.ts:
--------------------------------------------------------------------------------
1 | import splitBoxModelStyle from '../splitBoxModelStyle';
2 |
3 | describe('splitBoxModelStyle', () => {
4 | it('should split styles in two distinct chunks', () => {
5 | const { boxModelStyle, otherStyle } = splitBoxModelStyle({
6 | borderBottomColor: 'red',
7 | color: 'black',
8 | paddingBottom: 10
9 | });
10 | expect(boxModelStyle).toEqual({
11 | borderBottomColor: 'red',
12 | paddingBottom: 10
13 | });
14 | expect(otherStyle).toEqual({
15 | color: 'black'
16 | });
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/packages/render-html/src/helpers/collapseTopMarginForChild.ts:
--------------------------------------------------------------------------------
1 | import { TNode } from '@native-html/transient-render-engine';
2 | import getCollapsedMarginTop from './getCollapsedMarginTop';
3 |
4 | function isCollapsible(tnode: TNode) {
5 | return tnode.type === 'block' || tnode.type === 'phrasing';
6 | }
7 |
8 | /**
9 | * Compute top collapsed margin for the nth {@link TNode}-child of a list of
10 | * TNodes.
11 | *
12 | * @param n - The index for which the top margin should be collapsed.
13 | * @param tchildren - The list of {@link TNode} children.
14 | * @returns `null` when no margin collapsing should apply, a number otherwise.
15 | * @public
16 | */
17 | export default function collapseTopMarginForChild(
18 | n: number,
19 | tchildren: readonly TNode[]
20 | ): number | null {
21 | const childTnode = tchildren[n];
22 | if (isCollapsible(childTnode) && n > 0 && isCollapsible(tchildren[n - 1])) {
23 | return getCollapsedMarginTop(tchildren[n - 1], childTnode);
24 | }
25 | return null;
26 | }
27 |
--------------------------------------------------------------------------------
/packages/render-html/src/helpers/isDomSource.ts:
--------------------------------------------------------------------------------
1 | import { HTMLSource, HTMLSourceDom } from '../shared-types';
2 |
3 | export default function isDomSource(
4 | source: HTMLSource
5 | ): source is HTMLSourceDom {
6 | return 'dom' in source && typeof source.dom === 'object' && !!source.dom;
7 | }
8 |
--------------------------------------------------------------------------------
/packages/render-html/src/helpers/isUriSource.ts:
--------------------------------------------------------------------------------
1 | import { HTMLSource, HTMLSourceUri } from '../shared-types';
2 |
3 | export default function isUriSource(
4 | source: HTMLSource
5 | ): source is HTMLSourceUri {
6 | return 'uri' in source && typeof source.uri === 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/packages/render-html/src/helpers/lookupRecord.ts:
--------------------------------------------------------------------------------
1 | export default function lookupRecord>(
2 | record: T,
3 | key: any
4 | ): key is keyof T {
5 | const value = record[key];
6 | return !!value;
7 | }
8 |
--------------------------------------------------------------------------------
/packages/render-html/src/helpers/mergeCollapsedMargins.ts:
--------------------------------------------------------------------------------
1 | import { TNodeShape, TNodeType } from '@native-html/transient-render-engine';
2 |
3 | export default function mergeCollapsedMargins(
4 | collapsedMarginTop: number | null | undefined,
5 | nativeStyle: ReturnType['getNativeStyles']>
6 | ): ReturnType['getNativeStyles']> {
7 | if (typeof collapsedMarginTop !== 'number') {
8 | return nativeStyle;
9 | }
10 | return {
11 | ...nativeStyle,
12 | marginTop: collapsedMarginTop
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/packages/render-html/src/helpers/normalizeResourceLocator.ts:
--------------------------------------------------------------------------------
1 | import URI from 'urijs';
2 |
3 | /**
4 | * This function normalize relative and protocol-relative URLs to absolute
5 | * URLs as per {@link https://tools.ietf.org/html/rfc1808 | RFC1808}.
6 | *
7 | * @param url - The URL to normalize.
8 | * @param baseUrl - The base URL to resolve relative and protocol-relative URLs.
9 | */
10 | export default function normalizeResourceLocator(
11 | url: string,
12 | baseUrl?: string
13 | ) {
14 | try {
15 | return baseUrl ? URI(url).absoluteTo(URI(baseUrl)).href() : URI(url).href();
16 | } catch (e) {
17 | return url;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/render-html/src/helpers/selectSharedProps.ts:
--------------------------------------------------------------------------------
1 | import pickBy from 'ramda/src/pickBy';
2 | import pick from 'ramda/src/pick';
3 | import pipe from 'ramda/src/pipe';
4 | import mergeRight from 'ramda/src/mergeRight';
5 | import { RenderHTMLProps, RenderHTMLAmbiantSharedProps } from '../shared-types';
6 | import defaultSharedProps from '../context/defaultSharedProps';
7 |
8 | const selectSharedProps: (
9 | props: Partial
10 | ) => RenderHTMLAmbiantSharedProps = pipe(
11 | pick(Object.keys(defaultSharedProps)),
12 | pickBy((val) => val != null),
13 | mergeRight(defaultSharedProps) as any
14 | );
15 |
16 | export default selectSharedProps;
17 |
--------------------------------------------------------------------------------
/packages/render-html/src/hooks/useContentWidth.ts:
--------------------------------------------------------------------------------
1 | import { useContext } from 'react';
2 | import contentWidthContext from '../context/contentWidthContext';
3 |
4 | /**
5 | * A hook to get access to the ambient `contentWidth`.
6 | *
7 | * @returns The contentWidth available in context.
8 | *
9 | * @public
10 | */
11 | export default function useContentWidth() {
12 | return useContext(contentWidthContext);
13 | }
14 |
--------------------------------------------------------------------------------
/packages/render-html/src/hooks/useNormalizedUrl.ts:
--------------------------------------------------------------------------------
1 | import { useDocumentMetadata } from '../context/DocumentMetadataProvider';
2 | import normalizeResourceLocator from '../helpers/normalizeResourceLocator';
3 |
4 | /**
5 | * This hook transforms relative and protocol-relative URLs to absolute URLs as
6 | * per {@link https://tools.ietf.org/html/rfc1808 | RFC1808}. The base URL is
7 | * determined by the `` element, `source.uri` or `source.baseUrl`.
8 | *
9 | * @remarks
10 | * - If there is no `baseUrl` and the initial URL is relative, this hook will
11 | * return the initial URL.
12 | * - If the initial URL is absolute, this hook will return this initial URL.
13 | *
14 | * @param initialUrl - The URL before normalization.
15 | *
16 | * @public
17 | */
18 | export default function useNormalizedUrl(initialUrl: string) {
19 | const { baseUrl } = useDocumentMetadata();
20 | return normalizeResourceLocator(initialUrl, baseUrl);
21 | }
22 |
--------------------------------------------------------------------------------
/packages/render-html/src/internal-types.ts:
--------------------------------------------------------------------------------
1 | import { TNode } from '@native-html/transient-render-engine';
2 | import { Document, Element } from '@native-html/transient-render-engine';
3 | import { ComponentType } from 'react';
4 | import {
5 | RenderHTMLProps,
6 | TNodeRendererProps,
7 | RenderHTMLAmbiantSharedProps,
8 | TNodeChildrenRendererProps
9 | } from './shared-types';
10 |
11 | export type SourceLoaderProps = Pick<
12 | RenderHTMLProps,
13 | 'source' | 'onHTMLLoaded'
14 | >;
15 |
16 | export interface RenderTTreeProps {
17 | baseUrl?: string;
18 | document: string | Document | Element;
19 | }
20 |
21 | export type TTreeEvents = Pick<
22 | RenderHTMLProps,
23 | 'onTTreeChange' | 'onDocumentMetadataLoaded'
24 | >;
25 |
26 | export interface TNodeSubRendererProps
27 | extends TNodeRendererProps {
28 | TNodeChildrenRenderer: ComponentType;
29 | /**
30 | * Props shared across the whole render tree.
31 | */
32 | sharedProps: RenderHTMLAmbiantSharedProps;
33 | }
34 |
--------------------------------------------------------------------------------
/packages/render-html/src/render/internalRenderers.ts:
--------------------------------------------------------------------------------
1 | import ARenderer from '../renderers/ARenderer';
2 | import IMGRenderer from '../renderers/IMGRenderer';
3 | import OLRenderer from '../renderers/OLRenderer';
4 | import ULRenderer from '../renderers/ULRenderer';
5 |
6 | const internalRenderers = {
7 | img: IMGRenderer,
8 | ul: ULRenderer,
9 | ol: OLRenderer,
10 | a: ARenderer
11 | };
12 |
13 | export default internalRenderers;
14 |
--------------------------------------------------------------------------------
/packages/render-html/src/renderBlockContent.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { TDefaultRendererProps } from './shared-types';
3 | import GenericPressable from './GenericPressable';
4 | import getNativePropsForTNode from './helpers/getNativePropsForTNode';
5 | import { View } from 'react-native';
6 | import { TBlock } from '@native-html/transient-render-engine';
7 |
8 | function renderBlockContent(props: TDefaultRendererProps) {
9 | const nativeProps = getNativePropsForTNode(props);
10 | return React.createElement(
11 | typeof nativeProps.onPress === 'function' ? GenericPressable : View,
12 | nativeProps
13 | );
14 | }
15 | export default renderBlockContent;
16 |
--------------------------------------------------------------------------------
/packages/render-html/src/renderTextualContent.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text } from 'react-native';
3 | import { TPhrasing, TText } from '@native-html/transient-render-engine';
4 | import { TDefaultRendererProps } from './shared-types';
5 | import getNativePropsForTNode from './helpers/getNativePropsForTNode';
6 |
7 | const renderTextualContent = (
8 | props: TDefaultRendererProps
9 | ) => {
10 | return React.createElement(Text, getNativePropsForTNode(props));
11 | };
12 |
13 | export default renderTextualContent;
14 |
--------------------------------------------------------------------------------
/packages/render-html/src/renderers/WBRRenderer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text } from 'react-native';
3 | import { InternalTextContentRenderer } from '../render/render-types';
4 |
5 | const emptyProps = {};
6 |
7 | const WBRRenderer: InternalTextContentRenderer = function WordBreakRenderer() {
8 | return React.createElement(Text, emptyProps, '\u200b');
9 | };
10 |
11 | WBRRenderer.isNativeInternalTextRenderer = true;
12 |
13 | export default WBRRenderer;
14 |
--------------------------------------------------------------------------------
/packages/render-html/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "noEmit": false
5 | },
6 | "include": ["src/**/*.ts"],
7 | "exclude": ["node_modules", "**/__tests__"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/render-html/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/tsconfig",
3 | "extends": "../../tsconfig-base.json",
4 | "compilerOptions": {
5 | "experimentalDecorators": true,
6 | "emitDecoratorMetadata": true
7 | },
8 | "include": ["src", "jest"]
9 | }
10 |
--------------------------------------------------------------------------------
/patches/react-native.patch:
--------------------------------------------------------------------------------
1 | diff --git a/jest/setup.js b/jest/setup.js
2 | index 5f85d8602f5a91880d78177c0cfac94eeb530327..6034f5f89b8b0130b463f70097cb22c602fff432 100644
3 | --- a/jest/setup.js
4 | +++ b/jest/setup.js
5 | @@ -17,7 +17,8 @@ jest.requireActual('../Libraries/polyfills/error-guard');
6 |
7 | global.__DEV__ = true;
8 |
9 | -global.Promise = jest.requireActual('promise');
10 | +// See https://github.com/callstack/react-native-testing-library/issues/379#issuecomment-714341282
11 | +// global.Promise = jest.requireActual('promise');
12 | global.regeneratorRuntime = jest.requireActual('regenerator-runtime/runtime');
13 |
14 | global.requestAnimationFrame = function(callback) {
15 |
--------------------------------------------------------------------------------
/tsconfig-base.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/tsconfig",
3 | "extends": "@tsconfig/react-native",
4 | "compilerOptions": {
5 | "declaration": true,
6 | "skipLibCheck": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------