Skip to content

Commit

Permalink
🥌 no component wrapping, base node renderers now doing tha' thing
Browse files Browse the repository at this point in the history
  • Loading branch information
stevejpurves committed Mar 30, 2023
1 parent a487a0a commit 62bc3f7
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 87 deletions.
13 changes: 12 additions & 1 deletion packages/myst-to-react/src/code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { CopyIcon } from './components/CopyIcon';
type Props = {
value: string;
lang?: string;
executable?: boolean;
showCopy?: boolean;
showLineNumbers?: boolean;
startingLineNumber?: number;
Expand All @@ -24,6 +25,7 @@ export function CodeBlock(props: Props) {
const {
value,
lang,
executable,
emphasizeLines,
showLineNumbers,
className,
Expand Down Expand Up @@ -76,16 +78,25 @@ export function CodeBlock(props: Props) {
<CopyIcon text={value} />
</div>
)}
{executable && (
<div className="absolute hidden bottom-1 right-1 group-hover:block">
<div>RUN</div>
</div>
)}
</div>
);
}

const code: NodeRenderer<Code> = (node) => {
const code: NodeRenderer<Code & { executable: boolean }> = (node) => {
return (
<CodeBlock
key={node.key}
// data-cell-id={node.executable ? parentId : undefined}
data-mdast-node-type={node.type}
data-mdast-node-id={node.key}
value={node.value || ''}
lang={node.lang}
executable={node.executable}
emphasizeLines={node.emphasizeLines}
showLineNumbers={node.showLineNumbers}
startingLineNumber={node.startingLineNumber}
Expand Down
27 changes: 27 additions & 0 deletions packages/providers/src/block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { useContext } from 'react';
import type { KINDS } from './types';

type BlockContextType = {
parent: string;
context: KINDS;
};

const BlockContext = React.createContext<BlockContextType | undefined>(undefined);

export function BlockContextProvider({
id,
pageKind,
children,
}: React.PropsWithChildren<{ id: string; pageKind: KINDS }>) {
return (
<BlockContext.Provider value={{ parent: id, context: pageKind }}>
{children}
</BlockContext.Provider>
);
}

export function useBlockContext() {
const context = useContext(BlockContext);
if (!context) console.debug('useBlockContext used outside of a BlockContextProvider');
return context;
}
1 change: 1 addition & 0 deletions packages/providers/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './tabs';
export * from './xref';
export * from './types';
export * from './notebook';
export * from './block';
15 changes: 0 additions & 15 deletions packages/providers/src/notebook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,6 @@ export function NotebookProvider({
if (!core || !config || notebook) return;
if (page.kind !== KINDS.Notebook) return;
const nb = notebookFromMdast(core, config, page.mdast as GenericParent);

// this could be included in notebookFromMdast but keeping it separate to illustrate
// how this could be handled in a separate hook from the actual notebook loading

// nb.cells.forEach((cell: IThebeCell) => {
// const item = Object.entries(cellRefs.current).find(([id]) => id === cell.id);
// if (item) {
// const [_, el] = item;
// console.debug(`Attached cell ${cell.id} to DOM at:`, { el, connected: el.isConnected });
// cell.attachToDOM(el);
// } else {
// console.debug(`No cell ref found for ${cell.id} or type ${typeof cell}`);
// }
// });

setNotebook(nb);
}, [core, config, page]);

Expand Down
101 changes: 31 additions & 70 deletions packages/site/src/components/ContentBlocks.tsx
Original file line number Diff line number Diff line change
@@ -1,109 +1,70 @@
import { useParse, DEFAULT_RENDERERS } from 'myst-to-react';
import type { GenericNode, GenericParent } from 'myst-common';
import type { NodeRenderer } from '@myst-theme/providers';
import type { GenericParent } from 'myst-common';
import { useNodeRenderers } from '@myst-theme/providers';
import classNames from 'classnames';
import { CellRun } from './CellRun';
import { KINDS } from '../types';
import { BlockContextProvider } from '@myst-theme/providers';

function activeCodeRendererFactory(parentId: string, BaseRenderer: NodeRenderer<any>) {
return function ActiveCode(node: GenericNode) {
const code = BaseRenderer(node);
return (
<div
className="relative"
key={node.key}
data-cell-id={parentId}
data-mdast-node-type={node.type}
data-mdast-node-id={node.key}
>
{code}
{node.kind !== 'inline' && <CellRun id={parentId} />}
</div>
);
};
}

function ensureCodeBlocksHaveAnOutput(node: GenericParent) {
if (node.children.length === 1 && node.children[0].type === 'code') {
return {
...node,
children: [
...node.children,
{
type: 'output',
key: 'injected',
data: [],
},
],
};
}
if (
node.children.length === 2 &&
node.children[0].type === 'code' &&
node.children[1].type === 'output'
)
return node;

return {
...node,
children: node.children.map((n) => (n.type === 'code' ? { ...n, kind: 'inline' } : n)),
};
}

function addParentKey(parent: string, node: GenericParent): GenericParent {
// maybe better in a react provider
function addParentKeyAndContext(parent: string, node: GenericParent): GenericParent {
return {
...node,
children: node.children.map((child) => ({ ...child, parent, context: KINDS.Notebook })),
};
}

function Block({ id, node, className }: { id: string; node: GenericParent; className?: string }) {
const { code, ...otherRenderers } = useNodeRenderers() ?? DEFAULT_RENDERERS;
function Block({
id,
pageKind,
node,
className,
}: {
id: string;
pageKind: KINDS;
node: GenericParent;
className?: string;
}) {
const renderers = useNodeRenderers() ?? DEFAULT_RENDERERS;

// TODO - do we need these wrapper components? are we able to push the custom logic
// down into the standard code/output renderers and we decorate the node with data we need?
const children = useParse(addParentKey(id, ensureCodeBlocksHaveAnOutput(node)), {
...otherRenderers,
code: activeCodeRendererFactory(id, code),
// output: activeOutputRendererFactory(id, output),
});
const children = useParse(addParentKeyAndContext(id, node), renderers);
const subGrid = 'article-grid article-subgrid-gap col-screen';
const dataClassName = typeof node.data?.class === 'string' ? node.data?.class : undefined;
// Hide the subgrid if either the dataClass or the className exists and includes `col-`
const noSubGrid =
(dataClassName && dataClassName.includes('col-')) || (className && className.includes('col-'));
return (
<div
key={id}
id={id}
className={classNames(className, dataClassName, {
[subGrid]: !noSubGrid,
})}
>
{/* <pre className="text-xs">
block {node.type} | # children: {node.children.length} |
{node.children.map((n) => ` ${n.type} |`)}
</pre> */}
{children}
</div>
<BlockContextProvider id={id} pageKind={pageKind}>
<div
key={id}
id={id}
className={classNames(className, dataClassName, {
[subGrid]: !noSubGrid,
})}
>
{children}
</div>
</BlockContextProvider>
);
}

export function ContentBlocks({
name,
pageKind,
mdast,
className,
}: {
name: string;
pageKind: KINDS;
mdast: GenericParent;
className?: string;
}) {
const blocks = mdast.children as GenericParent[];
return (
<>
{blocks.map((node) => (
<Block key={node.key} id={node.key} node={node} className={className} />
<Block key={node.key} id={node.key} pageKind={pageKind} node={node} className={className} />
))}
</>
);
Expand Down
6 changes: 5 additions & 1 deletion packages/site/src/pages/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export function ArticlePage({ article }: { article: PageLoader }) {
</EnableCompute>
)}
</div>
<ContentBlocks name={article.slug} mdast={article.mdast as GenericParent} />
<ContentBlocks
name={article.slug}
pageKind={article.kind}
mdast={article.mdast as GenericParent}
/>
<Bibliography />
{!hide_footer_links && <FooterLinksBlock links={article.footer} />}
</NotebookProvider>
Expand Down

0 comments on commit 62bc3f7

Please sign in to comment.