@sveltia/ui 0.79.3 → 0.79.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/text-editor/shiki/version.d.ts +1 -1
- package/dist/components/text-editor/shiki/version.js +1 -1
- package/dist/components/text-editor/store.svelte.js +27 -1
- package/dist/components/text-editor/toolbar/code-language-switcher.svelte +42 -23
- package/dist/typedefs.d.ts +8 -1
- package/dist/typedefs.js +5 -1
- package/package.json +3 -3
|
@@ -45,6 +45,11 @@ export const createEditorStore = () => {
|
|
|
45
45
|
let showConverterError = $state(false);
|
|
46
46
|
/** @type {boolean} */
|
|
47
47
|
let pending = $state(false);
|
|
48
|
+
/**
|
|
49
|
+
* Number of editor operations started by the user that have yet to update the editor.
|
|
50
|
+
* @type {number}
|
|
51
|
+
*/
|
|
52
|
+
let runningOperations = $state(0);
|
|
48
53
|
/**
|
|
49
54
|
* Value last imported to the Lexical editor, and the Markdown the editor exports for it.
|
|
50
55
|
* @type {{ source: string, exported: string } | undefined}
|
|
@@ -195,7 +200,7 @@ export const createEditorStore = () => {
|
|
|
195
200
|
showConverterError = newValue;
|
|
196
201
|
},
|
|
197
202
|
get pending() {
|
|
198
|
-
return pending;
|
|
203
|
+
return pending || runningOperations > 0;
|
|
199
204
|
},
|
|
200
205
|
set pending(newValue) {
|
|
201
206
|
pending = newValue;
|
|
@@ -205,6 +210,27 @@ export const createEditorStore = () => {
|
|
|
205
210
|
},
|
|
206
211
|
editorId,
|
|
207
212
|
convertMarkdown,
|
|
213
|
+
/**
|
|
214
|
+
* Mark an operation the user started as running, which makes the content count as
|
|
215
|
+
* {@link TextEditorStore.pending} until it’s done. Use it for an operation that only reaches
|
|
216
|
+
* the editor after an `await`, such as a language change waiting for the highlighter to load:
|
|
217
|
+
* the flag the editor sets for itself is cleared by every update it makes in the meantime,
|
|
218
|
+
* including the one the focus move fires, so it can’t cover the wait.
|
|
219
|
+
* @returns {() => void} Function to call once the operation has updated the editor. Calling it
|
|
220
|
+
* more than once has no further effect.
|
|
221
|
+
*/
|
|
222
|
+
startOperation: () => {
|
|
223
|
+
runningOperations += 1;
|
|
224
|
+
|
|
225
|
+
let done = false;
|
|
226
|
+
|
|
227
|
+
return () => {
|
|
228
|
+
if (!done) {
|
|
229
|
+
done = true;
|
|
230
|
+
runningOperations -= 1;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
},
|
|
208
234
|
/**
|
|
209
235
|
* Get the value last imported if the given value, exported by the editor, is only that value
|
|
210
236
|
* written in the editor’s own Markdown style.
|
|
@@ -66,6 +66,46 @@
|
|
|
66
66
|
return isCodeNode(node) ? node : null;
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Give the code block the given language, once the highlighter for it has loaded.
|
|
71
|
+
* @param {string} lang Language ID.
|
|
72
|
+
*/
|
|
73
|
+
const changeLanguage = async (lang) => {
|
|
74
|
+
const { editor } = editorStore;
|
|
75
|
+
|
|
76
|
+
if (!editor || selectedKey === lang) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// The change only reaches the editor, and anything bound to it, once the highlighter has
|
|
81
|
+
// loaded, so report the content as pending until then: the flag the editor sets for itself is
|
|
82
|
+
// cleared by the update the focus move below fires
|
|
83
|
+
const endOperation = editorStore.startOperation();
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
await focusEditor(editor);
|
|
87
|
+
await loadCodeHighlighter(lang);
|
|
88
|
+
|
|
89
|
+
// The user may have moved on to another field while the highlighter was loading
|
|
90
|
+
editor.update(
|
|
91
|
+
() => {
|
|
92
|
+
// https://github.com/facebook/lexical/blob/main/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx#L713
|
|
93
|
+
const node = getCodeNode();
|
|
94
|
+
|
|
95
|
+
if (node) {
|
|
96
|
+
node.setLanguage(lang);
|
|
97
|
+
selectedLanguage = lang;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{ tag: getBackgroundUpdateTags(editor) },
|
|
101
|
+
);
|
|
102
|
+
} finally {
|
|
103
|
+
// The editor has flagged the export that follows as pending by now, so the hand-off leaves
|
|
104
|
+
// no gap
|
|
105
|
+
endOperation();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
69
109
|
$effect(() => {
|
|
70
110
|
void editorStore.selection.blockNodeKey;
|
|
71
111
|
|
|
@@ -86,29 +126,8 @@
|
|
|
86
126
|
{disabled}
|
|
87
127
|
ariaLabel={_('_sui.text_editor.language')}
|
|
88
128
|
value={selectedKey}
|
|
89
|
-
onChange={
|
|
90
|
-
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const { editor } = editorStore;
|
|
95
|
-
|
|
96
|
-
await focusEditor(editor);
|
|
97
|
-
await loadCodeHighlighter(lang);
|
|
98
|
-
|
|
99
|
-
// The user may have moved on to another field while the highlighter was loading
|
|
100
|
-
editor.update(
|
|
101
|
-
() => {
|
|
102
|
-
// https://github.com/facebook/lexical/blob/main/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx#L713
|
|
103
|
-
const node = getCodeNode();
|
|
104
|
-
|
|
105
|
-
if (node) {
|
|
106
|
-
node.setLanguage(lang);
|
|
107
|
-
selectedLanguage = lang;
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
{ tag: getBackgroundUpdateTags(editor) },
|
|
111
|
-
);
|
|
129
|
+
onChange={({ detail: { value: lang } }) => {
|
|
130
|
+
changeLanguage(lang);
|
|
112
131
|
}}
|
|
113
132
|
>
|
|
114
133
|
<Option label={_('_sui.text_editor.plain_text')} value="plain" dir="ltr" />
|
package/dist/typedefs.d.ts
CHANGED
|
@@ -1045,7 +1045,8 @@ export type TextEditorStore = {
|
|
|
1045
1045
|
showConverterError: boolean;
|
|
1046
1046
|
/**
|
|
1047
1047
|
* Whether the user has changed the rich text content, and the editor
|
|
1048
|
-
* has yet to convert it to Markdown and update {@link TextEditorStore.inputValue}.
|
|
1048
|
+
* has yet to convert it to Markdown and update {@link TextEditorStore.inputValue}. It’s also set
|
|
1049
|
+
* while an operation started with {@link TextEditorStore.startOperation} is running.
|
|
1049
1050
|
*/
|
|
1050
1051
|
pending: boolean;
|
|
1051
1052
|
/**
|
|
@@ -1057,6 +1058,12 @@ export type TextEditorStore = {
|
|
|
1057
1058
|
* Function to trigger the Lexical converter.
|
|
1058
1059
|
*/
|
|
1059
1060
|
convertMarkdown: () => Promise<void>;
|
|
1061
|
+
/**
|
|
1062
|
+
* Function marking an operation the user started, which
|
|
1063
|
+
* only updates the editor after an `await`, as running. It returns a function to call once the
|
|
1064
|
+
* operation is done. The content counts as {@link TextEditorStore.pending} meanwhile.
|
|
1065
|
+
*/
|
|
1066
|
+
startOperation: () => () => void;
|
|
1060
1067
|
/**
|
|
1061
1068
|
* Function to get the
|
|
1062
1069
|
* {@link TextEditorStore.inputValue} last imported if the given value, exported by the editor, is
|
package/dist/typedefs.js
CHANGED
|
@@ -447,10 +447,14 @@
|
|
|
447
447
|
* Lexical nodes.
|
|
448
448
|
* @property {boolean} showConverterError Whether to show a converter error in the UI.
|
|
449
449
|
* @property {boolean} pending Whether the user has changed the rich text content, and the editor
|
|
450
|
-
* has yet to convert it to Markdown and update {@link TextEditorStore.inputValue}.
|
|
450
|
+
* has yet to convert it to Markdown and update {@link TextEditorStore.inputValue}. It’s also set
|
|
451
|
+
* while an operation started with {@link TextEditorStore.startOperation} is running.
|
|
451
452
|
* @property {boolean} importing Whether the latest {@link TextEditorStore.inputValue} is still
|
|
452
453
|
* being imported to the Lexical editor.
|
|
453
454
|
* @property {() => Promise<void>} convertMarkdown Function to trigger the Lexical converter.
|
|
455
|
+
* @property {() => () => void} startOperation Function marking an operation the user started, which
|
|
456
|
+
* only updates the editor after an `await`, as running. It returns a function to call once the
|
|
457
|
+
* operation is done. The content counts as {@link TextEditorStore.pending} meanwhile.
|
|
454
458
|
* @property {(value: string) => string | undefined} getImportedValue Function to get the
|
|
455
459
|
* {@link TextEditorStore.inputValue} last imported if the given value, exported by the editor, is
|
|
456
460
|
* only that value written in the editor’s own Markdown style, e.g. `_text_` for `*text*`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltia/ui",
|
|
3
|
-
"version": "0.79.
|
|
3
|
+
"version": "0.79.4",
|
|
4
4
|
"description": "A collection of Svelte components and utilities for building user interfaces.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -85,9 +85,9 @@
|
|
|
85
85
|
"eslint-plugin-svelte": "^3.23.0",
|
|
86
86
|
"globals": "^17.13.0",
|
|
87
87
|
"happy-dom": "^20.14.5",
|
|
88
|
-
"oxlint": "^1.
|
|
88
|
+
"oxlint": "^1.87.0",
|
|
89
89
|
"playwright": "^1.63.0",
|
|
90
|
-
"postcss": "^8.5.
|
|
90
|
+
"postcss": "^8.5.29",
|
|
91
91
|
"postcss-html": "^2.0.0",
|
|
92
92
|
"prettier": "^3.9.9",
|
|
93
93
|
"prettier-plugin-svelte": "^4.1.1",
|