Skip to content

Commit

Permalink
feat: support svelte v5 (#96)
Browse files Browse the repository at this point in the history
* feat: support svelte v5

* Revert prettier-plugin-svelte

* chore: update cypress

* Call flushSync after mounting

* make sure flushSync won't be imported in v4

* refactor variable name

* fix build
  • Loading branch information
ocavue authored Oct 22, 2024
1 parent 42c3be4 commit d04cd34
Show file tree
Hide file tree
Showing 15 changed files with 651 additions and 2,195 deletions.
5 changes: 5 additions & 0 deletions .changeset/witty-zebras-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@prosemirror-adapter/svelte": minor
---

Support Svelte v5.
6 changes: 3 additions & 3 deletions e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
"@prosemirror-adapter/solid": "workspace:*",
"@prosemirror-adapter/svelte": "workspace:*",
"@prosemirror-adapter/vue": "workspace:*",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"@types/react": "^18.0.30",
"@types/react-dom": "^18.0.11",
"@vitejs/plugin-react": "^4.0.0",
"@vitejs/plugin-vue": "^5.0.0",
"cypress": "^13.2.0",
"cypress": "^13.15.0",
"lit": "^3.0.0",
"prosemirror-example-setup": "^1.2.1",
"prosemirror-menu": "^1.2.1",
Expand All @@ -33,7 +33,7 @@
"react-dom": "^18.2.0",
"solid-js": "^1.8.11",
"start-server-and-test": "^2.0.0",
"svelte": "^4.0.0",
"svelte": "^5.0.2",
"vite-plugin-solid": "^2.8.2",
"vue": "3.5.12"
}
Expand Down
4 changes: 1 addition & 3 deletions e2e/src/svelte/components/Editor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
} from "@prosemirror-adapter/svelte";
import { Plugin } from 'prosemirror-state'
import {DecorationSet, EditorView} from "prosemirror-view";
import {onDestroy, SvelteComponent} from "svelte";
import {onDestroy} from "svelte";
import {createEditorView} from "../../createEditorView";
import Hashes from "./Hashes.svelte";
import Paragraph from "./Paragraph.svelte";
import Heading from "./Heading.svelte";
import Size from "./Size.svelte";
let components: SvelteComponent[]
const nodeViewFactory = useNodeViewFactory()
const pluginViewFactory = usePluginViewFactory()
const widgetViewFactory = useWidgetViewFactory()
Expand Down
3 changes: 2 additions & 1 deletion e2e/src/svelte/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mount } from 'svelte'
import App from './App.svelte'

const app = new App({
const app = mount(App, {
target: document.getElementById('app')!,
})

Expand Down
10 changes: 5 additions & 5 deletions examples/svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
"prosemirror-view": "^1.30.2"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.14.0",
"@sveltejs/adapter-auto": "^3.2.5",
"@sveltejs/kit": "^2.7.2",
"prettier": "^2.8.7",
"prettier-plugin-svelte": "^2.10.0",
"svelte": "^3.57.0",
"svelte-check": "^3.1.4",
"svelte": "^5.0.2",
"svelte-check": "^4.0.5",
"tslib": "^2.5.0",
"typescript": "^5.0.2",
"vite": "^4.2.1"
"vite": "^5.4.9"
}
}
4 changes: 1 addition & 3 deletions examples/svelte/src/components/Editor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
} from "@prosemirror-adapter/svelte";
import { Plugin } from 'prosemirror-state'
import { DecorationSet, EditorView } from "prosemirror-view";
import { onDestroy, SvelteComponent } from "svelte";
import { onDestroy } from "svelte";
import { createEditorView } from "../libs/createEditorView";
import Hashes from "./Hashes.svelte";
import Paragraph from "./Paragraph.svelte";
import Heading from "./Heading.svelte";
import Size from "./Size.svelte";
let components: SvelteComponent[]
const nodeViewFactory = useNodeViewFactory()
const pluginViewFactory = usePluginViewFactory()
const widgetViewFactory = useWidgetViewFactory()
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@prosemirror-adapter/monorepo",
"private": true,
"packageManager": "pnpm@9.12.1",
"packageManager": "pnpm@9.12.2",
"license": "MIT",
"engines": {
"node": ">=20"
Expand Down
6 changes: 3 additions & 3 deletions packages/svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@
"build": "tsc --emitDeclarationOnly && vite build"
},
"peerDependencies": {
"svelte": "^4.0.0"
"svelte": "^4.0.0 || ^5.0.0"
},
"dependencies": {
"@prosemirror-adapter/core": "workspace:*",
"nanoid": "^5.0.0",
"tslib": "^2.5.0"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"svelte": "^4.0.0"
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"svelte": "^5.0.2"
}
}
14 changes: 6 additions & 8 deletions packages/svelte/src/SvelteRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { SvelteComponent } from 'svelte'
import type { Writable } from 'svelte/store'
import { writable } from 'svelte/store'

Expand All @@ -7,36 +6,35 @@ export interface SvelteRenderer<Context> {

context: Context

render: () => SvelteComponent
render: () => VoidFunction

updateContext: () => void
}

export interface SvelteRendererResult {
readonly portals: Writable<Record<string, SvelteComponent>>
readonly renderSvelteRenderer: (renderer: SvelteRenderer<unknown>) => void
readonly removeSvelteRenderer: (renderer: SvelteRenderer<unknown>) => void
}

export function useSvelteRenderer(): SvelteRendererResult {
const portals: Writable<Record<string, SvelteComponent>> = writable({})
const unmounts: Writable<Record<string, VoidFunction>> = writable({})

const renderSvelteRenderer = (renderer: SvelteRenderer<unknown>) => {
portals.update(records => ({
unmounts.update(records => ({
...records,
[renderer.key]: renderer.render(),
}))
}

const removeSvelteRenderer = (renderer: SvelteRenderer<unknown>) => {
portals.update((records) => {
const { [renderer.key]: _, ...rest } = records
unmounts.update((records) => {
const { [renderer.key]: unmount, ...rest } = records
unmount?.()
return rest
})
}

return {
portals,
renderSvelteRenderer,
removeSvelteRenderer,
} as const
Expand Down
35 changes: 35 additions & 0 deletions packages/svelte/src/mount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as svelte from 'svelte'
import type {
SvelteClassComponentConstructor,
SvelteComponentConstructor,
} from './types'

const isSvelte5 = !!svelte.mount && !!svelte.flushSync

interface MountOptions {
target: HTMLElement
context: Map<string, unknown>
}

function mountFunctionComponent(UserComponent: SvelteComponentConstructor, options: MountOptions): VoidFunction {
// Using Svelte v5, where components are functions
const component = svelte.mount(UserComponent, { ...options }) as svelte.SvelteComponent
// Unlike `new UserComponent()` in Svelte v4, `mount()` in Svelte v5 doesn't
// call `onMount()` and action functions automatically. So we need to call
// `flushSync()` to ensure they run.
svelte.flushSync()
return () => svelte.unmount(component)
}

function mountClassComponent(UserComponent: SvelteComponentConstructor, options: MountOptions): VoidFunction {
// Using Svelte v4, where components are classes
const component = new (UserComponent as SvelteClassComponentConstructor)(options)
return () => component.$destroy()
}

/**
* Mounts a Svelte component to a DOM element.
*
* Returns a function that unmounts the component.
*/
export const mount = isSvelte5 ? mountFunctionComponent : mountClassComponent
3 changes: 2 additions & 1 deletion packages/svelte/src/nodeView/SvelteNodeView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Writable } from 'svelte/store'
import { writable } from 'svelte/store'

import type { SvelteRenderer } from '../SvelteRenderer'
import { mount } from '../mount'
import type { NodeViewContext, NodeViewContextMap } from './nodeViewContext'
import type { SvelteNodeViewComponent } from './SvelteNodeViewOptions'

Expand Down Expand Up @@ -50,7 +51,7 @@ export class SvelteNodeView extends CoreNodeView<SvelteNodeViewComponent> implem
render = () => {
const UserComponent = this.component

return new UserComponent({
return mount(UserComponent, {
target: this.dom,
context: this.context,
})
Expand Down
3 changes: 2 additions & 1 deletion packages/svelte/src/pluginView/SveltePluginView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { nanoid } from 'nanoid'
import type { Writable } from 'svelte/store'
import { writable } from 'svelte/store'
import type { SvelteRenderer } from '../SvelteRenderer'
import { mount } from '../mount'
import type { PluginViewContext, PluginViewContextMap } from './pluginViewContext'
import type { SveltePluginViewComponent } from './SveltePluginViewOptions'

Expand Down Expand Up @@ -31,7 +32,7 @@ export class SveltePluginView extends CorePluginView<SveltePluginViewComponent>
render = () => {
const UserComponent = this.component

return new UserComponent({
return mount(UserComponent, {
target: this.root,
context: this.context,
})
Expand Down
5 changes: 3 additions & 2 deletions packages/svelte/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ComponentConstructorOptions, SvelteComponent } from 'svelte'
import type { Component, ComponentConstructorOptions, SvelteComponent } from 'svelte'

export type AnyRecord = Record<string, any>
export type SvelteComponentConstructor<T extends AnyRecord = AnyRecord> = new (options: ComponentConstructorOptions<T>) => SvelteComponent
export type SvelteClassComponentConstructor<T extends AnyRecord = AnyRecord> = new (options: ComponentConstructorOptions<T>) => SvelteComponent
export type SvelteComponentConstructor<T extends AnyRecord = AnyRecord> = SvelteClassComponentConstructor<T> | Component<T>

export type Obj2Map<T extends AnyRecord> = Map<keyof T, T[keyof T]>
3 changes: 2 additions & 1 deletion packages/svelte/src/widgetView/SvelteWidgetView.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CoreWidgetView } from '@prosemirror-adapter/core'
import { nanoid } from 'nanoid'
import type { SvelteRenderer } from '../SvelteRenderer'
import { mount } from '../mount'
import type { SvelteWidgetViewComponent } from './SvelteWidgetViewOptions'
import type { WidgetViewContext, WidgetViewContextMap } from './widgetViewContext'

Expand Down Expand Up @@ -29,7 +30,7 @@ export class SvelteWidgetView extends CoreWidgetView<SvelteWidgetViewComponent>
render = () => {
const UserComponent = this.component

return new UserComponent({
return mount(UserComponent, {
target: this.dom,
context: this.context,
})
Expand Down
Loading

0 comments on commit d04cd34

Please sign in to comment.