Skip to content

Commit

Permalink
perf: use context to make unitary list style renderers
Browse files Browse the repository at this point in the history
  • Loading branch information
jsamr committed Jun 22, 2021
1 parent 1c05c10 commit 26bdd72
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 56 deletions.
17 changes: 10 additions & 7 deletions packages/render-html/src/RenderHTMLConfigProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import sourceLoaderContext, {
import RenderRegistryProvider from './context/RenderRegistryProvider';
import { useAmbientTRenderEngine } from './TRenderEngineProvider';
import useProfiler from './hooks/useProfiler';
import ListStyleSpecsProvider from './context/ListStyleSepcsProvider';

const childrenRendererContext = {
TChildrenRenderer,
Expand Down Expand Up @@ -67,13 +68,15 @@ export default function RenderHTMLConfigProvider(
renderers={renderers}
elementModels={engine.getHTMLElementsModels()}>
<SharedPropsProvider {...sharedProps}>
<RenderersPropsProvider renderersProps={renderersProps}>
<TChildrenRenderersContext.Provider value={childrenRendererContext}>
<sourceLoaderContext.Provider value={sourceLoaderConfig}>
{children}
</sourceLoaderContext.Provider>
</TChildrenRenderersContext.Provider>
</RenderersPropsProvider>
<ListStyleSpecsProvider>
<RenderersPropsProvider renderersProps={renderersProps}>
<TChildrenRenderersContext.Provider value={childrenRendererContext}>
<sourceLoaderContext.Provider value={sourceLoaderConfig}>
{children}
</sourceLoaderContext.Provider>
</TChildrenRenderersContext.Provider>
</RenderersPropsProvider>
</ListStyleSpecsProvider>
</SharedPropsProvider>
</RenderRegistryProvider>
);
Expand Down
84 changes: 84 additions & 0 deletions packages/render-html/src/context/ListStyleSepcsProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* eslint-disable react-native/no-inline-styles */
import { MarkerBoxProps } from '@jsamr/react-native-li';
import { mapObjIndexed } from 'ramda';
import React, {
createContext,
PropsWithChildren,
useContext,
useMemo
} from 'react';
import { Text, View } from 'react-native';
import defaultListStyleSpecs from '../elements/defaultListStyleSpecs';
import { ListStyleSpec, UnitaryListStyleSpec } from '../shared-types';
import { useSharedProps } from './SharedPropsProvider';

const listStyleSpecsContext = createContext<
Record<
string,
ListStyleSpec & { renderMarker?: (props: MarkerBoxProps) => any }
>
>(defaultListStyleSpecs);

export function useListStyleSpecs() {
return useContext(listStyleSpecsContext);
}

function createSymbolicMarkerRenderer({
Component,
counterStyleRenderer
}: UnitaryListStyleSpec) {
const prefix = counterStyleRenderer.renderPrefix();
const suffix = counterStyleRenderer.renderSuffix();
return ({
style,
markerTextStyle,
counterIndex,
rtlMarkerReversed
}: MarkerBoxProps) => {
return (
<View
style={[
style,
{
flexDirection: rtlMarkerReversed ? 'row-reverse' : 'row',
justifyContent: 'flex-end'
}
]}>
{!!prefix && <Text style={markerTextStyle}>{prefix}</Text>}
{React.createElement(Component, {
...(markerTextStyle as any),
index: counterIndex
})}
{!!suffix && <Text style={markerTextStyle}>{suffix}</Text>}
</View>
);
};
}

const makeMarkerRenderers = mapObjIndexed((value: ListStyleSpec) => {
if (value.type === 'unitary') {
return {
...value,
renderMarker: createSymbolicMarkerRenderer(value)
};
}
return value;
});

export default function ListStyleSpecsProvider({
children
}: PropsWithChildren<{}>) {
const { customListStyleSpecs } = useSharedProps();
const mergedListStyleSpecs = useMemo(() => {
return makeMarkerRenderers(
customListStyleSpecs != null
? { ...defaultListStyleSpecs, ...customListStyleSpecs }
: defaultListStyleSpecs
);
}, [customListStyleSpecs]);
return (
<listStyleSpecsContext.Provider value={mergedListStyleSpecs}>
{children}
</listStyleSpecsContext.Provider>
);
}
53 changes: 6 additions & 47 deletions packages/render-html/src/elements/ListElement.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
/* eslint-disable react-native/no-inline-styles */
import { StyleSheet, Text, View } from 'react-native';
import { StyleSheet, View } from 'react-native';
import React from 'react';
import { TBlock, TNode } from '@native-html/transient-render-engine';
import {
MarkedListItem,
useMarkedList,
MarkerBoxProps
} from '@jsamr/react-native-li';
import { MarkedListItem, useMarkedList } from '@jsamr/react-native-li';
import type {
DefaultSupportedListStyleType,
InternalRendererProps,
ListElementConfig,
ListStyleSpec,
TChildProps,
UnitaryListStyleSpec
TChildProps
} from '../shared-types';
import { useTChildrenRenderer } from '../context/TChildrenRendererContext';
import { DEFAULT_TEXT_COLOR } from '../constants';
import pick from 'ramda/src/pick';
import { useListStyleSpecs } from '../context/ListStyleSepcsProvider';

export interface ListElementProps<T extends 'ol' | 'ul'>
extends InternalRendererProps<TBlock>,
ListElementConfig {
listType: T;
listStyleSpecs: Record<string, ListStyleSpec>;
}

function getStartIndex(tnode: TNode) {
Expand All @@ -33,38 +27,6 @@ function getStartIndex(tnode: TNode) {
return Number.isNaN(parsedIndex) ? 1 : parsedIndex;
}

function createSymbolicMarkerRenderer(
component: UnitaryListStyleSpec['Component']
) {
return ({
style,
markerTextStyle,
counterRenderer,
counterIndex,
rtlMarkerReversed
}: MarkerBoxProps) => {
const prefix = counterRenderer.renderPrefix();
const suffix = counterRenderer.renderSuffix();
return (
<View
style={[
style,
{
flexDirection: rtlMarkerReversed ? 'row-reverse' : 'row',
justifyContent: 'flex-end'
}
]}>
{<Text style={markerTextStyle}>{prefix}</Text>}
{React.createElement(component, {
...(markerTextStyle as any),
index: counterIndex
})}
{<Text style={markerTextStyle}>{suffix}</Text>}
</View>
);
};
}

const pickMarkerTextStyles = pick([
'fontStyle',
'fontSize',
Expand Down Expand Up @@ -117,9 +79,9 @@ export default function ListElement({
enableRemoveTopMarginIfNested = true,
enableRemoveBottomMarginIfNested = true,
enableDynamicMarkerBoxWidth = false,
listStyleSpecs,
...props
}: ListElementProps<'ol' | 'ul'>) {
const listStyleSpecs = useListStyleSpecs();
const markers = tnode.markers;
const nestLevel =
listType === 'ol' ? markers.olNestLevel : markers.ulNestLevel;
Expand Down Expand Up @@ -174,10 +136,7 @@ export default function ListElement({
rtlMarkerReversed: rtl,
length: tnode.children.length,
dynamicMarkerBoxWidth: enableDynamicMarkerBoxWidth,
renderMarker:
spec.type === 'unitary'
? createSymbolicMarkerRenderer(spec.Component)
: undefined
renderMarker: spec.renderMarker
});
const markerWidth = itemProps.markerTextWidth;
const fixedPaddingRule = rtl
Expand Down
2 changes: 0 additions & 2 deletions packages/render-html/src/renderers/ULRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ function getFallbackListStyleTypeFromNestLevel(
export function useULElementProps(
props: InternalRendererProps<TBlock>
): ULElementProps {
const listStyleSpecs = props.sharedProps.customListStyleSpecs;
const config = useRendererProps('ul');
return {
...props,
listStyleSpecs,
getFallbackListStyleTypeFromNestLevel,
...config
};
Expand Down

0 comments on commit 26bdd72

Please sign in to comment.