Skip to content

v7.16.0

Choose a tag to compare

@metonym metonym released this 19 Jul 22:24
· 35 commits to master since this release
v7.16.0
768e2ec

Features

  • replace highlight.js runtime with an original highlight engine (85a0706, #461)
  • compile themes to palettes with CSS-variable theming (956cf17, #463)
  • expose the scope-event stream as a public API (1bfe132, #464)
  • add HighlightVirtual for windowed rendering of huge documents (3d452e2, #466)
  • add defineTheme, extendTheme, and a TextMate importer (25a6ab1, #465)
  • add custom gdscript language (8aa6b1e, #471)
  • add custom heex language (79c4080, #471)
  • add custom sparql language (26e4225, #471)

Fixes

  • stop HighlightVirtual's class and sizer from leaking (588c332, #466)
  • scope sub-language continuation state to its own occurrence (ca0c0f5, #463)
  • balance nested delimiters in string interpolation (a48a978, #470)
  • recognize Vue longhand directive arguments (0d77d90, #470)
  • highlight Zig function names (25da324, #470)
  • highlight WGSL unsigned-integer number suffixes (a4ed905, #470)
  • don't shadow Pug control-flow keywords with the tag rule (66554d1, #470)
  • bound Zig fn-name match to avoid runaway scan (00b2282, #470)
  • recognize Razor implicit control-flow blocks (e0e67c5, #470)
  • recognize Marko concise class/id shorthand on tags (71696e4, #470)
  • recognize Marko's else-if hyphen form (ffa164c, #470)
  • don't mistake email addresses for Blade directives (b239a85, #470)
  • handle escaped quotes in Blade strings (efab4e9, #470)
  • recognize Rego function-style rule heads (86c6df6, #470)
  • fix PromQL grouping labels and subquery resolution (b41bb10, #470)
  • don't mistag Nickel let-bound names as record fields (78dc9a3, #470)
  • don't mistake Cypher map values for node labels (8787003, #470)
  • don't tag Solidity inheritance lists as titles (972e7f1, #470)
  • highlight Solidity hex literals with underscores (3e0cb72, #470)
  • don't swallow a trailing hyphen into Svelte stores (63a5ee5, #470)
  • highlight parameterless HLSL attributes (bd46ac0, #470)
  • stop HLSL semantics matching ternary/switch colons (c4199e0, #470)
  • make Typst strong/emphasis respect the whitespace rule (c5dbb00, #470)
  • recognize bare Typst #{ } code blocks (bcf10d5, #470)
  • balance nested braces in Templ legacy script blocks (e663d9f, #470)
  • recognize Just recipe params with function-call defaults (be19bf3, #470)
  • style Astro's closing frontmatter fence (88acf74, #470)
  • highlight Caddy multi-address site headers (4ddfe89, #470)
  • stop Nushell def-env from corrupting the title match (9e50e7e, #470)
  • highlight compound LogQL durations (b5e9cd7, #470)
  • keep MDX JSX tags open through a > inside {...} (882f6b3, #470)
  • don't mistake a Prisma field named type for a declaration (3570394, #470)

Original highlight engine

svelte-highlight no longer ships a highlight.js runtime. Highlighting is handled by an in-package engine that consumes plain-JSON grammar IR. Everyday usage is unchanged: language imports, <Highlight language={…} {code} />, and .hljs / hljs-* class contracts still work.

highlight.js was removed from published dependencies. If you relied on it transitively, install it yourself. Custom languages that used register: (hljs) => mode should migrate to fromHighlightJs from svelte-highlight/compat (optional peer install of highlight.js), or ship converted grammar IR.

<script>
  import Highlight from "svelte-highlight";
  import typescript from "svelte-highlight/languages/typescript";

  const code = "const add = (a: number, b: number) => a + b;";
</script>

<Highlight language={typescript} {code} />
import { fromHighlightJs } from "svelte-highlight/compat";

// requires: npm i highlight.js
const language = await fromHighlightJs("custom-language", (hljs) => ({
  contains: [],
}));

Theme palettes with CSS variables

Every shipped theme is also a typed ThemePalette of --shl-* variables. Pair a palette with svelte-highlight/themes/base.css. Legacy svelte-highlight/styles/* strings still work. HighlightStyle accepts theme / light / dark as a string or palette.

<script>
  import { Highlight, HighlightStyle } from "svelte-highlight";
  import typescript from "svelte-highlight/languages/typescript";
  import atomOneDark from "svelte-highlight/themes/atom-one-dark";
  import "svelte-highlight/themes/base.css";

  const code = "const add = (a: number, b: number) => a + b;";
</script>

<HighlightStyle theme={atomOneDark}>
  <Highlight language={typescript} {code} />
</HighlightStyle>

Scope-event stream API

The engine exposes a balanced scope-event stream (TEXT / OPEN / CLOSE). Components forward it as let:events and on:highlightdetail.events. For headless use, import from svelte-highlight/engine.

import { createRegistry, registerAll, tokenLines } from "svelte-highlight/engine";
import typescript from "svelte-highlight/languages/typescript";

const registry = createRegistry();
registerAll(registry, typescript);
const { events, value } = registry.highlight(code, { language: "typescript" });
const lines = tokenLines(events);
<Highlight language={typescript} {code} let:highlighted let:events>
  <pre><code>{@html highlighted}</code></pre>
</Highlight>

HighlightVirtual for huge documents

HighlightVirtual renders only the viewport (plus overscan) for large static files — a 100k-line dump stays a couple dozen DOM line nodes. SSR emits full plain escaped text; windowed highlighting kicks in after hydration.

<script>
  import { HighlightVirtual } from "svelte-highlight";
  import json from "svelte-highlight/languages/json";
</script>

<HighlightVirtual language={json} code={hugeLogDump} style="height: 480px" />

defineTheme, extendTheme, and TextMate import

Author palettes programmatically from semantic roles, extend an existing theme, or import a VS Code / TextMate theme JSON.

import { defineTheme, extendTheme } from "svelte-highlight/theme";
import { fromTextMate } from "svelte-highlight/theme/textmate";
import atomOneDark from "svelte-highlight/themes/atom-one-dark";

const midnight = defineTheme({
  name: "midnight",
  roles: {
    background: "#0b1021",
    foreground: "#d6deeb",
    keyword: "#c792ea",
  },
});

const branded = extendTheme(atomOneDark, {
  name: "branded",
  roles: { keyword: "#ff79c6" },
});

const palette = fromTextMate(nightOwlJson, { onWarn: console.warn });

Custom gdscript, heex, and sparql languages

These grammars are maintained by svelte-highlight. Import them from svelte-highlight/languages like any other language.

The gdscript grammar highlights Godot GDScript: func / class_name / extends, typed params, @export annotations, and $NodePath / %UniqueName lookups.

The heex grammar highlights Phoenix HEEx templates: embedded Elixir (<%= %>, { }), components (<.form>), and HTML markup.

The sparql grammar highlights SPARQL queries: PREFIX, SELECT / WHERE, graph patterns, and filters.

<script>
  import Highlight from "svelte-highlight";
  import gdscript from "svelte-highlight/languages/gdscript";
  import heex from "svelte-highlight/languages/heex";
  import sparql from "svelte-highlight/languages/sparql";

  const gdCode = `extends Node2D

@export var speed: float = 100.0

func _ready() -> void:
	$Label.text = "Hello"`;

  const heexCode = `<.form for={@changeset} phx-submit="save">
  <.input field={@changeset[:email]} type="email" />
  <button>Save</button>
</.form>`;

  const sparqlCode = `PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name
WHERE {
  ?person foaf:name ?name .
}`;
</script>

<Highlight language={gdscript} code={gdCode} />
<Highlight language={heex} code={heexCode} />
<Highlight language={sparql} code={sparqlCode} />