@hvniel/lexical-svelte
v0.1.1
Published
This package provides Lexical components and hooks for Svelte applications.
Maintainers
Readme
@hvniel/lexical-svelte
Svelte 5 components and utilities for building Lexical editors. The package ports the useful composition and plugin surface of @lexical/react into Svelte-native components, snippets, effects, and context.
Installation
npm install lexical @hvniel/lexical-sveltePreprocessor setup
Lexical deliberately prefixes update/read-scope functions with $, but Svelte reserves that prefix for runes and store subscriptions. The included preprocessor lets you use Lexical's canonical named imports without manual aliases or namespace imports.
Configure the component preprocessor in svelte.config.js:
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import { lexicalPreprocess } from '@hvniel/lexical-svelte/preprocess';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: [lexicalPreprocess(), vitePreprocess()]
};
export default config;Add the companion Vite hook for .svelte.js, .svelte.ts, and Svelte test modules in vite.config.ts:
import { sveltekit } from '@sveltejs/kit/vite';
import { lexicalImports } from '@hvniel/lexical-svelte/preprocess';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [lexicalImports(), sveltekit()]
});Both functions accept the same options:
const lexicalOptions = {
packages: ['lexical', '@lexical', '@hvniel/lexical-svelte', '@acme/editor', '$lib', '.', '..'],
markers: ['@lexical-scope', 'lex']
};
lexicalPreprocess(lexicalOptions);
lexicalImports(lexicalOptions);packagescontrols which named imports are processed. Entries match the package itself and its subpaths. The defaults arelexical,@lexical, and@hvniel/lexical-svelte.markersaccepts one string or an array. The default is@lexical-scope.- Named imports remain statically analyzable and tree-shakeable.
- Explicit aliases, type-only imports, unrelated packages, and shadowed bindings remain unchanged.
Local scope functions
Use an exact, adjacent marker when declaring a Lexical-scope function inside .svelte or .svelte.ts source:
<script lang="ts">
// @lexical-scope
function $readSelection() {
return $getSelection();
}
</script>Block comments work too:
/* @lexical-scope */
function $readSelection() {
return $getSelection();
}The marker must directly precede a function declaration. A blank line detaches it. Plain .ts and .js files do not need markers because they are not subject to Svelte's dollar-prefix restriction.
Basic editor
<script lang="ts">
import { $getRoot, $getSelection } from 'lexical';
import {
ContentEditable,
HistoryPlugin,
LexicalComposer,
LexicalErrorBoundary,
OnChangePlugin,
PlainTextPlugin
} from '@hvniel/lexical-svelte';
const theme = {};
function onError(error: Error) {
throw error;
}
const initialConfig = {
namespace: 'MyEditor',
theme,
onError
};
function onChange(editorState) {
editorState.read(() => {
const root = $getRoot();
const selection = $getSelection();
console.log(root, selection);
});
}
</script>
<LexicalComposer {initialConfig}>
<PlainTextPlugin errorBoundary={LexicalErrorBoundary}>
{#snippet contenteditable()}
<ContentEditable />
{/snippet}
</PlainTextPlugin>
<HistoryPlugin />
<OnChangePlugin {onChange} />
</LexicalComposer>Lexical Svelte plugins are ordinary Svelte components, so they compose naturally and can be loaded only where an editor needs them.
