Skip to content

Commit 31afa3d

Browse files
committed
feat: support multiple text nodes
1 parent d63d587 commit 31afa3d

4 files changed

Lines changed: 21 additions & 50 deletions

File tree

src/config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ import type { Config } from './syntax-highlight-component.types';
44
export const configDefaults: Config = {
55
languages: ['markup', 'css', 'html', 'javascript', 'typescript'],
66
tokenTypes,
7-
languageTokens: {},
87
tokenize,
98
};

src/cssHighlight.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,13 @@
11
/**
22
* Initializes CSS Custom Highlights for a given set of token types.
33
*
4-
* This function iterates through a list of common token types and optional
5-
* language-specific token types, creating and registering a new `Highlight`
6-
* object for each one in the `CSS.highlights` registry. This pre-registration
7-
* is a necessary step for applying styles to code tokens using the
8-
* CSS Custom Highlight API.
9-
*
104
* @param tokenTypes An array of strings representing common token types (e.g., 'keyword', 'string').
11-
* @param options An object containing additional configuration.
12-
* @param options.languageTokens An optional object mapping language identifiers to their specific token types.
135
* These are registered with a name in the format `${language}-${tokenType}`.
146
* ```
157
* @see https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API
168
*/
17-
export function setupTokenHighlights(
18-
tokenTypes: string[],
19-
{ languageTokens }: { languageTokens?: { [language: string]: string[] } },
20-
) {
9+
export function setupTokenHighlights(tokenTypes: string[]) {
2110
for (const tokenType of tokenTypes) {
2211
CSS.highlights.set(tokenType, new Highlight());
2312
}
24-
25-
if (languageTokens) {
26-
for (const language in languageTokens) {
27-
for (const tokenType of languageTokens[language]) {
28-
CSS.highlights.set(`${language}-${tokenType}`, new Highlight());
29-
}
30-
}
31-
}
3213
}

src/syntax-highlight-component.ts

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {
55
type Language,
66
type Theme,
77
} from './syntax-highlight-component.types';
8-
import { setupTokenHighlights } from './cssHighlight';
98
import { configDefaults } from './config';
9+
import { setupTokenHighlights } from './cssHighlight';
1010

1111
/**
1212
* A web component for syntax highlighting code blocks using the CSS Custom Highlight API.
@@ -80,9 +80,7 @@ export default class SyntaxHighlightComponent extends LitElement {
8080
super();
8181
this._internals = this.attachInternals();
8282
this._internals.role = 'code';
83-
setupTokenHighlights(configDefaults.tokenTypes, {
84-
languageTokens: configDefaults.languageTokens,
85-
});
83+
setupTokenHighlights(configDefaults.tokenTypes);
8684
}
8785

8886
get contentElement(): HTMLElement {
@@ -223,36 +221,30 @@ export default class SyntaxHighlightComponent extends LitElement {
223221
return html`<slot @slotchange=${this.paintTokenHighlights}></slot>`;
224222
}
225223

226-
async paintTokenHighlights() {
224+
paintTokenHighlights() {
227225
this.clearTokenHighlights();
228226
if (!CSS.highlights) return;
229227

230-
const text = this.contentElement.innerText;
231-
const tokens = await SyntaxHighlightComponent._config.tokenize(
232-
text,
233-
this.language,
234-
);
235-
const languageTokenTypes =
236-
SyntaxHighlightComponent._config.languageTokens?.[this.language] || [];
237-
238-
let pos = 0;
239-
for (const token of tokens) {
240-
if (token.type) {
241-
const tokenType = languageTokenTypes.includes(token.type)
242-
? `${this.language}-${token.type}`
243-
: token.type;
244-
245-
const range = new Range();
246-
if (this.contentElement.firstChild) {
247-
range.setStart(this.contentElement.firstChild, pos);
248-
range.setEnd(this.contentElement.firstChild, pos + token.length);
228+
this.contentElement.childNodes.forEach(async (node) => {
229+
let pos = 0;
230+
const tokens = await SyntaxHighlightComponent._config.tokenize(
231+
node.textContent || '',
232+
this.language,
233+
);
234+
for (const token of tokens) {
235+
if (token.type) {
236+
const range = new Range();
237+
if (node && node.textContent?.length) {
238+
range.setStart(node, pos);
239+
range.setEnd(node, pos + token.length);
249240

250-
CSS.highlights.get(tokenType)?.add(range);
251-
this._highlights.add({ tokenType, range });
241+
CSS.highlights.get(token.type)?.add(range);
242+
this._highlights.add({ tokenType: token.type, range });
243+
}
252244
}
245+
pos += token.length;
253246
}
254-
pos += token.length;
255-
}
247+
});
256248
}
257249

258250
protected clearTokenHighlights() {

src/syntax-highlight-component.types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
export type Config = {
22
languages: Language[];
33
tokenTypes: string[];
4-
languageTokens: Record<string, string[]>;
54
tokenize: (text: string, language: Language) => Promise<FlatToken[]>;
65
};
76

0 commit comments

Comments
 (0)