Skip to content

Commit

Permalink
feat: new setMarkersForTNode prop
Browse files Browse the repository at this point in the history
Thanks to this function, you can take advantage of the Markers API in
your own renderers!
  • Loading branch information
jsamr committed Jun 4, 2021
1 parent 10dfc82 commit 63caa4d
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 6 deletions.
16 changes: 15 additions & 1 deletion packages/render-html/src/TNodeRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,29 @@ import TPhrasingRenderer from './TPhrasingRenderer';
import TTextRenderer from './TTextRenderer';
import { Markers, TNodeRendererProps } from './shared-types';
import { getMarkersFromTNode } from './helpers/getMarkersFromTNode';
import { useSharedProps } from './context/SharedPropsContext';

export type { TNodeRendererProps } from './shared-types';

const TNodeRenderer = function TNodeRenderer(
props: Omit<TNodeRendererProps<any>, 'markers'> & { parentMarkers: Markers }
) {
const { tnode } = props;
const { setMarkersForTNode } = useSharedProps();
const markers = getMarkersFromTNode(tnode, props.parentMarkers);
const tnodeProps = { ...props, markers: markers || props.parentMarkers };
const customMarkers = setMarkersForTNode(tnode, props.parentMarkers);
const resolvedMarkers =
markers && !customMarkers
? markers
: !markers && customMarkers
? { ...props.parentMarkers, ...customMarkers }
: markers && customMarkers
? ({ ...markers, ...customMarkers } as Markers)
: null;
const tnodeProps = {
...props,
markers: resolvedMarkers || props.parentMarkers
};
if (tnode instanceof TBlock) {
return React.createElement(TBlockRenderer, tnodeProps);
}
Expand Down
16 changes: 16 additions & 0 deletions packages/render-html/src/__tests__/component.render-html.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@ describe('RenderHTML', () => {
const em = UNSAFE_getByType(EmRenderer);
expect(em.props.markers.lang).toBe('test');
});
it('should handle setMarkersForTNode prop', () => {
const { UNSAFE_getByType } = render(
<RenderHTML
source={{
html: '<em>Two</em>'
}}
debug={false}
setMarkersForTNode={(tnode) =>
tnode.tagName === 'em' ? { em: true } : null
}
contentWidth={100}
/>
);
const em = UNSAFE_getByType(TTextRenderer);
expect(em.props.markers.em).toBe(true);
});
});
describe('regarding propsFromParent', () => {
it('should pass propsForChildren to children', () => {
Expand Down
3 changes: 2 additions & 1 deletion packages/render-html/src/context/SharedPropsContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export const defaultSharedPropsContext: Required<RenderHTMLSharedProps> = {
return null;
},
defaultWebViewProps: {},
renderersProps: {}
renderersProps: {},
setMarkersForTNode: () => null
};

const SharedPropsContext = React.createContext<Required<RenderHTMLSharedProps>>(
Expand Down
21 changes: 17 additions & 4 deletions packages/render-html/src/shared-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,20 @@ export interface RenderHTMLSharedProps<
* See [@native-html/plugins](https://github.com/native-html/plugins).
*/
WebView?: ComponentType<any>;
/**
* Set custom markers from a TNode and all its descendants. Markers will be
* accessible in custom renderers via `markers` prop.
*
* @param tnode - The TNode to inspect
* @param parentMarkers - Markers from the parent TNode.
*
* @returns a record of markers if one or many markers should be added,
* `null` otherwise.
*/
setMarkersForTNode?: (
tnode: TNode,
parentMarkers: Markers
) => Partial<Markers> | null;
}

export interface TransientRenderEngineConfig {
Expand Down Expand Up @@ -377,10 +391,9 @@ export interface FallbackFontsDefinitions {

/**
* Markers form an abstraction in which one node provides semantic information
* to itself and all its descendants by the mean of its name or attributes. For
* example, `ins` elements, which stand for "insertion" of content in the
* context of an edit will provide the { edits: 'ins' } marker to all its
* descendants.
* to itself and all its descendants. For example, `ins` elements, which stand
* for "insertion" of content in the context of an edit will provide the {
* edits: 'ins' } marker to all its descendants.
*
* Custom renderers can use markers to change their layout and convey their
* semantic meaning. Markers can be derived from attributes, such as `lang` and
Expand Down

0 comments on commit 63caa4d

Please sign in to comment.