Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 18 additions & 40 deletions src/web/EnrichedMarkdownText.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import {
useState,
useEffect,
useMemo,
Fragment,
type CSSProperties,
} from 'react';
import { useState, useEffect, useMemo, type CSSProperties } from 'react';
import type { EnrichedMarkdownTextProps } from '../types/MarkdownTextProps.web';
import { normalizeMarkdownStyle } from '../normalizeMarkdownStyle.web';
import {
Expand All @@ -18,6 +12,7 @@ import type { ASTNode, RendererCallbacks, RenderCapabilities } from './types';
import { indexTaskItems, markInlineImages } from './utils';
import { loadKaTeX } from './katex';
import type { KaTeXInstance } from './katex';
import { ENRM_TEXT_CLASS, ENRM_SELECTION_BG_VAR } from './globalStyles';

export const EnrichedMarkdownText = ({
markdown,
Expand Down Expand Up @@ -109,31 +104,17 @@ export const EnrichedMarkdownText = ({
...(containerStyle as CSSProperties),
...(selectable ? undefined : { userSelect: 'none' }),
...(selectionColor
? ({ ['--enrm-selection-bg']: selectionColor } as CSSProperties)
? ({ [ENRM_SELECTION_BG_VAR]: selectionColor } as CSSProperties)
: null),
}),
[containerStyle, selectable, selectionColor]
);

const selectionStyle = selectionColor ? (
<style>{`[data-enriched-markdown-text] ::selection {
background-color: var(--enrm-selection-bg);
}`}</style>
) : null;

if (parseError) {
return (
<Fragment>
{selectionStyle}
<div
data-enriched-markdown-text
style={wrapperStyle}
dir={dir}
{...rest}
>
<pre style={parseErrorFallbackStyle}>{markdown}</pre>
</div>
</Fragment>
<div className={ENRM_TEXT_CLASS} style={wrapperStyle} dir={dir} {...rest}>
<pre style={parseErrorFallbackStyle}>{markdown}</pre>
</div>
);
}

Expand All @@ -143,21 +124,18 @@ export const EnrichedMarkdownText = ({
const lastIdx = children.length - 1;

return (
<Fragment>
{selectionStyle}
<div data-enriched-markdown-text style={wrapperStyle} dir={dir} {...rest}>
{children.map((child, index) => (
<RenderNode
key={`${child.type}-${index}`}
node={child}
style={index === lastIdx ? lastChildStyle : normalizedStyle}
styles={index === lastIdx ? lastChildStyles : styles}
callbacks={callbacks}
capabilities={capabilities}
/>
))}
</div>
</Fragment>
<div className={ENRM_TEXT_CLASS} style={wrapperStyle} dir={dir} {...rest}>
{children.map((child, index) => (
<RenderNode
key={`${child.type}-${index}`}
node={child}
style={index === lastIdx ? lastChildStyle : normalizedStyle}
styles={index === lastIdx ? lastChildStyles : styles}
callbacks={callbacks}
capabilities={capabilities}
/>
))}
</div>
);
};

Expand Down
15 changes: 15 additions & 0 deletions src/web/globalStyles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { injectStyleOnce } from './injectStyle';

export const ENRM_TEXT_CLASS = 'enrm-text';
export const ENRM_SELECTION_BG_VAR = '--enrm-selection-bg';

const RULES: ReadonlyArray<readonly [id: string, css: string]> = [
[
'enrm-selection-style',
`.${ENRM_TEXT_CLASS} ::selection { background-color: var(${ENRM_SELECTION_BG_VAR}); }`,
],
];

for (const [id, css] of RULES) {
injectStyleOnce(id, css);
}
17 changes: 17 additions & 0 deletions src/web/injectStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// <reference lib="dom" />

/**
* Idempotently injects a `<style>` rule into `document.head`.
*
* Safe on SSR (no-op when `document` is undefined) and HMR (de-duped by `id`).
* Intended for module-level invocation: `N` mounted components produce a
* single `<style>` tag in the DOM.
*/
export const injectStyleOnce = (id: string, css: string): void => {
if (typeof document === 'undefined') return;
if (document.getElementById(id) != null) return;
const style = document.createElement('style');
style.id = id;
style.textContent = css;
document.head.appendChild(style);
};
Loading