⬆️ Update Svelte to 5

This commit is contained in:
frostime 2025-08-16 17:03:37 +08:00
parent 3972fc1e46
commit ba404a6648
9 changed files with 172 additions and 103 deletions

View file

@ -16,7 +16,7 @@
"make-install": "vite build && node --no-warnings ./scripts/make_install.js"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.0",
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"@tsconfig/svelte": "^4.0.1",
"@types/node": "^20.3.0",
"cross-env": "^7.0.3",
@ -27,10 +27,10 @@
"rollup-plugin-livereload": "^2.0.5",
"sass": "^1.63.3",
"siyuan": "1.1.2",
"svelte": "^4.2.20",
"svelte": "^5.0.0",
"ts-node": "^10.9.1",
"typescript": "^5.1.3",
"vite": "^5.2.9",
"typescript": "^5.5.0",
"vite": "^5.4.4",
"vite-plugin-static-copy": "^1.0.2",
"vite-plugin-zip-pack": "^1.0.5"
}

View file

@ -11,13 +11,19 @@
// import { version } from "@/api";
import { showMessage, fetchPost, Protyle } from "siyuan";
export let app;
export let blockID: string;
interface Props {
app: any;
blockID: string;
}
let time: string = "";
let { app, blockID }: Props = $props();
let divProtyle: HTMLDivElement;
let time: string = $state("");
// let ver: string = "";
let divProtyle: HTMLDivElement = $state();
let protyle: any;
// let blockID: string = $state('');
onMount(async () => {
// ver = await version();
@ -50,14 +56,14 @@
<div class="fn__hr"></div>
<div class="fn__hr"></div>
<div>API demo:</div>
<div class="fn__hr" />
<div class="fn__hr"></div>
<div class="plugin-sample__time">
System current time: <span id="time">{time}</span>
</div>
<div class="fn__hr" />
<div class="fn__hr" />
<div class="fn__hr"></div>
<div class="fn__hr"></div>
<div>Protyle demo: id = {blockID}</div>
<div class="fn__hr" />
<div id="protyle" style="height: 360px;" bind:this={divProtyle}/>
<div class="fn__hr"></div>
<div id="protyle" style="height: 360px;" bind:this={divProtyle}></div>
</div>

View file

@ -23,9 +23,9 @@ import {
getModelByDockType,
getAllEditor,
Files,
platformUtils,
// platformUtils,
openSetting,
openAttributePanel,
openAttributePanel,
saveLayout
} from "siyuan";
import "./index.scss";
@ -36,6 +36,7 @@ import SettingExample from "@/setting-example.svelte";
import { SettingUtils } from "./libs/setting-utils";
import { svelteDialog } from "./libs/dialog";
import { mount, unmount } from "svelte";
const STORAGE_NAME = "menu-config";
const TAB_TYPE = "custom_tab";
@ -84,7 +85,7 @@ export default class PluginSample extends Plugin {
this.custom = this.addTab({
type: TAB_TYPE,
init() {
app = new HelloExample({
app = mount(HelloExample, {
target: tabDiv,
props: {
app: this.app,
@ -98,7 +99,8 @@ export default class PluginSample extends Plugin {
console.log("before destroy tab:", TAB_TYPE);
},
destroy() {
app?.$destroy();
// app?.$destroy();
app && unmount(app);
console.log("destroy tab:", TAB_TYPE);
}
});
@ -415,19 +417,28 @@ export default class PluginSample extends Plugin {
* A custom setting pannel provided by svelte
*/
openSetting(): void {
let dialog = new Dialog({
// let dialog = new Dialog({
// title: "SettingPannel",
// content: `<div id="SettingPanel" style="height: 100%;"></div>`,
// width: "800px",
// destroyCallback: (options) => {
// console.log("destroyCallback", options);
// //You'd better destroy the component when the dialog is closed
// unmount(pannel);
// }
// });
// let pannel = mount(SettingExample, {
// target: dialog.element.querySelector("#SettingPanel"),
// });
svelteDialog({
title: "SettingPannel",
content: `<div id="SettingPanel" style="height: 100%;"></div>`,
width: "800px",
destroyCallback: (options) => {
console.log("destroyCallback", options);
//You'd better destroy the component when the dialog is closed
pannel.$destroy();
height: "35rem",
component: SettingExample,
props: {
app: this.app,
}
});
let pannel = new SettingExample({
target: dialog.element.querySelector("#SettingPanel"),
});
}
private eventBusPaste(event: any) {
@ -471,14 +482,10 @@ export default class PluginSample extends Plugin {
svelteDialog({
title: `SiYuan ${Constants.SIYUAN_VERSION}`,
width: this.isMobile ? "92vw" : "720px",
constructor: (container: HTMLElement) => {
return new HelloExample({
target: container,
props: {
app: this.app,
blockID: docId
}
});
component: HelloExample,
props: {
app: this.app,
blockID: docId
}
});
}

View file

@ -1,33 +1,47 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
export let type: string; // Setting Type
export let key: string;
export let value: any;
// Optional parameters
export let placeholder: string = "";
export let options: { [key: string | number]: string } = {};
export let slider: {
interface Props {
type: string;
key: string;
value: any;
placeholder?: string;
options?: { [key: string | number]: string };
slider?: {
min: number;
max: number;
step: number;
} = { min: 0, max: 100, step: 1 };
export let button: {
};
button?: {
label: string;
callback?: () => void;
} = { label: value, callback: () => {} };
export let fnSize: boolean = true; // If the form input is used within setting panel context, it is usually given a fixed width by a class named "fn__size200".
export let style: string = ""; // Custom style
const dispatch = createEventDispatcher();
function click() {
button?.callback();
dispatch("click", { key: key });
};
fnSize?: boolean;
style?: string;
onclick?: (detail: {key: string}) => void;
onchanged?: (detail: {key: string, value: any}) => void;
}
function changed() {
dispatch("changed", { key: key, value: value });
let {
type,
key,
value = $bindable(),
placeholder = "",
options = {},
slider = { min: 0, max: 100, step: 1 },
button = { label: value, callback: () => {} },
fnSize = true,
style = "",
onclick,
onchanged
}: Props = $props();
function handleClick() {
button?.callback();
onclick?.({ key: key });
}
function handleChanged() {
onchanged?.({ key: key, value: value });
}
</script>
@ -38,7 +52,7 @@
id={key}
type="checkbox"
bind:checked={value}
on:change={changed}
onchange={handleChanged}
style={style}
/>
{:else if type === "textinput"}
@ -50,7 +64,7 @@
id={key}
{placeholder}
bind:value={value}
on:change={changed}
onchange={handleChanged}
style={style}
/>
{:else if type === "textarea"}
@ -58,8 +72,8 @@
class="b3-text-field fn__block"
style={`resize: vertical; height: 10em; white-space: nowrap; ${style}`}
bind:value={value}
on:change={changed}
/>
onchange={handleChanged}
></textarea>
{:else if type === "number"}
<input
class:b3-text-field={true}
@ -68,7 +82,7 @@
id={key}
type="number"
bind:value={value}
on:change={changed}
onchange={handleChanged}
style={style}
/>
{:else if type === "button"}
@ -79,7 +93,7 @@
class:fn__flex-center={true}
class:fn__size200={fnSize}
id={key}
on:click={click}
onclick={handleClick}
style={style}
>
{button.label}
@ -92,7 +106,7 @@
class:fn__size200={fnSize}
id="iconPosition"
bind:value={value}
on:change={changed}
onchange={handleChanged}
style={style}
>
{#each Object.entries(options) as [value, text]}
@ -111,7 +125,7 @@
step={slider.step}
type="range"
bind:value={value}
on:change={changed}
onchange={handleChanged}
style={style}
/>
</div>

View file

@ -7,9 +7,19 @@
Description : The setting item container
-->
<script lang="ts">
export let title: string; // Displayint Setting Title
export let description: string; // Displaying Setting Text
export let direction: 'row' | 'column' = 'column';
interface Props {
title: string;
description: string;
direction?: 'row' | 'column';
children?: import('svelte').Snippet;
}
let {
title,
description,
direction = 'column',
children
}: Props = $props();
</script>
{#if direction === "row"}
@ -19,7 +29,7 @@
<div class="b3-label__text">{@html description}</div>
<div class="fn__hr"></div>
<div style="display: flex; flex-direction: column; gap: 5px; position: relative;">
<slot />
{@render children?.()}
</div>
</div>
</div>
@ -31,8 +41,8 @@
{@html description}
</div>
</div>
<span class="fn__space" />
<slot />
<span class="fn__space"></span>
{@render children?.()}
</div>
{/if}

View file

@ -1,3 +1,8 @@
<script>
/** @type {{children?: import('svelte').Snippet}} */
let { children } = $props();
</script>
<div class="item__readme b3-typography">
<slot/>
{@render children?.()}
</div>

View file

@ -7,28 +7,42 @@
Description :
-->
<script lang="ts">
import { createEventDispatcher } from "svelte";
import Form from './Form';
export let group: string;
export let settingItems: ISettingItem[];
export let display: boolean = true;
const dispatch = createEventDispatcher();
function onClick( {detail}) {
dispatch("click", { key: detail.key });
}
function onChanged( {detail}) {
dispatch("changed", {group: group, ...detail});
interface Props {
group: string;
settingItems: ISettingItem[];
display?: boolean;
children?: import('svelte').Snippet;
onclick?: (detail: {key: string}) => void;
onchanged?: (detail: {group: string, key: string, value: any}) => void;
}
$: fn__none = display ? "" : "fn__none";
let {
group,
settingItems: _settingItems,
display = true,
children,
onclick,
onchanged
}: Props = $props();
// 使用 $state 让 settingItems 变成响应式
let settingItems = $state(_settingItems);
function handleClick(detail: {key: string}) {
onclick?.(detail);
}
function handleChanged(detail: {key: string, value: any}) {
onchanged?.({group: group, key: detail.key, value: detail.value});
}
let fn__none = $derived(display ? "" : "fn__none");
</script>
<div class="config__tab-container {fn__none}" data-name={group}>
<slot />
{@render children?.()}
{#each settingItems as item (item.key)}
<Form.Wrap
title={item.title}
@ -43,8 +57,8 @@
options={item?.options}
slider={item?.slider}
button={item?.button}
on:click={onClick}
on:changed={onChanged}
onclick={handleClick}
onchanged={handleChanged}
/>
</Form.Wrap>
{/each}

View file

@ -3,11 +3,11 @@
* @Author : frostime
* @Date : 2024-03-23 21:37:33
* @FilePath : /src/libs/dialog.ts
* @LastEditTime : 2024-10-16 14:31:04
* @LastEditTime : 2025-08-16 15:39:48
* @Description : Kits about dialogs
*/
import { Dialog } from "siyuan";
import { type SvelteComponent } from "svelte";
import { Component, mount, unmount } from "svelte";
export const inputDialog = (args: {
title: string, placeholder?: string, defaultText?: string,
@ -143,21 +143,34 @@ export const simpleDialog = (args: {
export const svelteDialog = (args: {
title: string, constructor: (container: HTMLElement) => SvelteComponent,
width?: string, height?: string,
title: string,
component: Component<any>, // Svelte 5 component constructor
props?: Record<string, any>,
width?: string,
height?: string,
callback?: () => void;
}) => {
let container = document.createElement('div')
container.style.display = 'contents';
let component = args.constructor(container);
// 内部处理 mount
let componentInstance = mount(args.component, {
target: container,
props: args.props || {}
});
const { dialog, close } = simpleDialog({
...args, ele: container, callback: () => {
component.$destroy();
...args,
ele: container,
callback: () => {
// 内部处理 unmount
unmount(componentInstance);
if (args.callback) args.callback();
}
});
return {
component,
component: componentInstance,
dialog,
close
}

View file

@ -3,7 +3,7 @@
import SettingPanel from "./libs/components/setting-panel.svelte";
let groups: string[] = ["🌈 Group 1", "✨ Group 2"];
let focusGroup = groups[0];
let focusGroup = $state(groups[0]);
const group1Items: ISettingItem[] = [
{
@ -79,7 +79,7 @@
value: any;
}
const onChanged = ({ detail }: CustomEvent<ChangeEvent>) => {
const onChanged = (detail: ChangeEvent) => {
if (detail.group === groups[0]) {
// setting.set(detail.key, detail.value);
//Please add your code here
@ -91,15 +91,15 @@
<div class="fn__flex-1 fn__flex config__panel">
<ul class="b3-tab-bar b3-list b3-list--background">
{#each groups as group}
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<li
data-name="editor"
class:b3-list-item--focus={group === focusGroup}
class="b3-list-item"
on:click={() => {
onclick={() => {
focusGroup = group;
}}
on:keydown={() => {}}
onkeydown={() => {}}
>
<span class="b3-list-item__text">{group}</span>
</li>
@ -110,8 +110,8 @@
group={groups[0]}
settingItems={group1Items}
display={focusGroup === groups[0]}
on:changed={onChanged}
on:click={({ detail }) => { console.debug("Click:", detail.key); }}
onchanged={onChanged}
onclick={(detail) => { console.debug("Click:", detail.key); }}
>
<div class="fn__flex b3-label">
💡 This is our default settings.
@ -121,8 +121,8 @@
group={groups[1]}
settingItems={group2Items}
display={focusGroup === groups[1]}
on:changed={onChanged}
on:click={({ detail }) => { console.debug("Click:", detail.key); }}
onchanged={onChanged}
onclick={(detail) => { console.debug("Click:", detail.key); }}
>
</SettingPanel>
</div>