@sveltia/ui 0.41.1 → 0.41.3
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/constants.d.ts +37 -1
- package/dist/components/text-editor/constants.js +152 -1
- package/dist/components/text-editor/core.d.ts +17 -5
- package/dist/components/text-editor/core.js +121 -143
- package/dist/components/text-editor/lexical-root.svelte +2 -1
- package/dist/components/text-editor/store.svelte.js +11 -2
- package/dist/components/text-editor/text-editor.svelte +2 -7
- package/dist/components/text-editor/text-editor.svelte.d.ts +3 -4
- package/dist/components/text-editor/toolbar/text-editor-toolbar.svelte +21 -18
- package/dist/typedefs.d.ts +6 -1
- package/dist/typedefs.js +6 -1
- package/package.json +6 -6
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @import {
|
|
2
|
+
* @import { EditorThemeClasses } from 'lexical';
|
|
3
|
+
* @import { Transformer } from '@lexical/markdown';
|
|
4
|
+
* @import {
|
|
5
|
+
* TextEditorBlockType,
|
|
6
|
+
* TextEditorFormatType,
|
|
7
|
+
* TextEditorInlineType,
|
|
8
|
+
* TextEditorNodeType,
|
|
9
|
+
* } from '../../typedefs';
|
|
3
10
|
*/
|
|
11
|
+
export const PRISM_BASE_URL: "https://unpkg.com/prismjs@1.30.0";
|
|
12
|
+
/**
|
|
13
|
+
* @type {EditorThemeClasses}
|
|
14
|
+
*/
|
|
15
|
+
export const EDITOR_THEME: EditorThemeClasses;
|
|
4
16
|
/**
|
|
5
17
|
* List of available buttons.
|
|
6
18
|
* @type {{ [key: string]: { labelKey: string, icon: string, inline: boolean } }}
|
|
@@ -28,6 +40,30 @@ export const BLOCK_BUTTON_TYPES: TextEditorBlockType[];
|
|
|
28
40
|
* Image related components IDs. `linked-image` is used in Sveltia CMS.
|
|
29
41
|
*/
|
|
30
42
|
export const IMAGE_COMPONENT_IDS: string[];
|
|
43
|
+
/**
|
|
44
|
+
* Map of Lexical nodes for each block type. The `paragraph` block type is excluded because it is
|
|
45
|
+
* the default block type.
|
|
46
|
+
* @type {Record<Exclude<TextEditorBlockType | 'link', 'paragraph'>, any[]>}
|
|
47
|
+
*/
|
|
48
|
+
export const NODE_MAP: Record<Exclude<TextEditorBlockType | "link", "paragraph">, any[]>;
|
|
49
|
+
/**
|
|
50
|
+
* Map of Lexical transformers for each block type. The `paragraph` block type is excluded because
|
|
51
|
+
* it is the default block type.
|
|
52
|
+
* @type {Record<Exclude<TextEditorNodeType, 'paragraph'>, Transformer[]>}
|
|
53
|
+
*/
|
|
54
|
+
export const TRANSFORMER_MAP: Record<Exclude<TextEditorNodeType, "paragraph">, Transformer[]>;
|
|
55
|
+
/**
|
|
56
|
+
* List of Markdown tags that should be disabled in the editor when converting Lexical nodes to
|
|
57
|
+
* Markdown (but not when converting Markdown to Lexical nodes because we don’t want to lose any
|
|
58
|
+
* formatting). Use underscore for italic text in Markdown instead of asterisks, and use double
|
|
59
|
+
* asterisks for bold text in Markdown instead of underscores. Also, disable triple asterisks and
|
|
60
|
+
* triple underscores for bold+italic text in Markdown, which can be confusing and is not commonly
|
|
61
|
+
* used. This is to ensure that the Markdown output is more readable and consistent.
|
|
62
|
+
*/
|
|
63
|
+
export const DISABLED_MARKDOWN_TAGS: string[];
|
|
64
|
+
import type { EditorThemeClasses } from 'lexical';
|
|
31
65
|
import type { TextEditorFormatType } from '../../typedefs';
|
|
32
66
|
import type { TextEditorInlineType } from '../../typedefs';
|
|
33
67
|
import type { TextEditorBlockType } from '../../typedefs';
|
|
68
|
+
import type { TextEditorNodeType } from '../../typedefs';
|
|
69
|
+
import type { Transformer } from '@lexical/markdown';
|
|
@@ -1,6 +1,89 @@
|
|
|
1
|
+
import { CodeHighlightNode, CodeNode } from '@lexical/code';
|
|
2
|
+
import { LinkNode } from '@lexical/link';
|
|
3
|
+
import { ListItemNode, ListNode } from '@lexical/list';
|
|
4
|
+
import {
|
|
5
|
+
BOLD_ITALIC_STAR,
|
|
6
|
+
BOLD_ITALIC_UNDERSCORE,
|
|
7
|
+
BOLD_STAR,
|
|
8
|
+
BOLD_UNDERSCORE,
|
|
9
|
+
CODE,
|
|
10
|
+
HEADING,
|
|
11
|
+
INLINE_CODE,
|
|
12
|
+
ITALIC_STAR,
|
|
13
|
+
ITALIC_UNDERSCORE,
|
|
14
|
+
LINK,
|
|
15
|
+
ORDERED_LIST,
|
|
16
|
+
QUOTE,
|
|
17
|
+
STRIKETHROUGH,
|
|
18
|
+
UNORDERED_LIST,
|
|
19
|
+
} from '@lexical/markdown';
|
|
20
|
+
import { HeadingNode, QuoteNode } from '@lexical/rich-text';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @import { EditorThemeClasses } from 'lexical';
|
|
24
|
+
* @import { Transformer } from '@lexical/markdown';
|
|
25
|
+
* @import {
|
|
26
|
+
* TextEditorBlockType,
|
|
27
|
+
* TextEditorFormatType,
|
|
28
|
+
* TextEditorInlineType,
|
|
29
|
+
* TextEditorNodeType,
|
|
30
|
+
* } from '../../typedefs';
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
export const PRISM_BASE_URL = `https://unpkg.com/prismjs@1.30.0`;
|
|
34
|
+
|
|
1
35
|
/**
|
|
2
|
-
* @
|
|
36
|
+
* @type {EditorThemeClasses}
|
|
3
37
|
*/
|
|
38
|
+
export const EDITOR_THEME = {
|
|
39
|
+
text: {
|
|
40
|
+
/**
|
|
41
|
+
* Enable bold+italic and strikethrough styling.
|
|
42
|
+
* @see https://github.com/facebook/lexical/discussions/4381
|
|
43
|
+
*/
|
|
44
|
+
italic: 'italic',
|
|
45
|
+
strikethrough: 'strikethrough',
|
|
46
|
+
},
|
|
47
|
+
list: {
|
|
48
|
+
nested: {
|
|
49
|
+
listitem: 'nested',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
code: 'code-block',
|
|
53
|
+
// https://github.com/facebook/lexical/blob/main/packages/lexical-website/docs/getting-started/theming.md
|
|
54
|
+
codeHighlight: {
|
|
55
|
+
atrule: 'token atrule',
|
|
56
|
+
attr: 'token attr',
|
|
57
|
+
boolean: 'token boolean',
|
|
58
|
+
builtin: 'token builtin',
|
|
59
|
+
cdata: 'token cdata',
|
|
60
|
+
char: 'token char',
|
|
61
|
+
class: 'token class',
|
|
62
|
+
'class-name': 'token class-name',
|
|
63
|
+
comment: 'token comment',
|
|
64
|
+
constant: 'token constant',
|
|
65
|
+
deleted: 'token deleted',
|
|
66
|
+
doctype: 'token doctype',
|
|
67
|
+
entity: 'token entity',
|
|
68
|
+
function: 'token function',
|
|
69
|
+
important: 'token important',
|
|
70
|
+
inserted: 'token inserted',
|
|
71
|
+
keyword: 'token keyword',
|
|
72
|
+
namespace: 'token namespace',
|
|
73
|
+
number: 'token number',
|
|
74
|
+
operator: 'token operator',
|
|
75
|
+
prolog: 'token prolog',
|
|
76
|
+
property: 'token property',
|
|
77
|
+
punctuation: 'token punctuation',
|
|
78
|
+
regex: 'token regex',
|
|
79
|
+
selector: 'token selector',
|
|
80
|
+
string: 'token string',
|
|
81
|
+
symbol: 'token symbol',
|
|
82
|
+
tag: 'token tag',
|
|
83
|
+
url: 'token url',
|
|
84
|
+
variable: 'token variable',
|
|
85
|
+
},
|
|
86
|
+
};
|
|
4
87
|
|
|
5
88
|
/**
|
|
6
89
|
* List of available buttons.
|
|
@@ -120,3 +203,71 @@ export const BLOCK_BUTTON_TYPES = [
|
|
|
120
203
|
* Image related components IDs. `linked-image` is used in Sveltia CMS.
|
|
121
204
|
*/
|
|
122
205
|
export const IMAGE_COMPONENT_IDS = ['image', 'linked-image'];
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Map of Lexical nodes for each block type. The `paragraph` block type is excluded because it is
|
|
209
|
+
* the default block type.
|
|
210
|
+
* @type {Record<Exclude<TextEditorBlockType | 'link', 'paragraph'>, any[]>}
|
|
211
|
+
*/
|
|
212
|
+
export const NODE_MAP = {
|
|
213
|
+
'heading-1': [HeadingNode],
|
|
214
|
+
'heading-2': [HeadingNode],
|
|
215
|
+
'heading-3': [HeadingNode],
|
|
216
|
+
'heading-4': [HeadingNode],
|
|
217
|
+
'heading-5': [HeadingNode],
|
|
218
|
+
'heading-6': [HeadingNode],
|
|
219
|
+
'bulleted-list': [ListNode, ListItemNode],
|
|
220
|
+
'numbered-list': [ListNode, ListItemNode],
|
|
221
|
+
blockquote: [QuoteNode],
|
|
222
|
+
'code-block': [CodeNode, CodeHighlightNode],
|
|
223
|
+
link: [LinkNode],
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Map of Lexical transformers for each block type. The `paragraph` block type is excluded because
|
|
228
|
+
* it is the default block type.
|
|
229
|
+
* @type {Record<Exclude<TextEditorNodeType, 'paragraph'>, Transformer[]>}
|
|
230
|
+
*/
|
|
231
|
+
export const TRANSFORMER_MAP = {
|
|
232
|
+
// ELEMENT_TRANSFORMERS
|
|
233
|
+
'heading-1': [HEADING],
|
|
234
|
+
'heading-2': [HEADING],
|
|
235
|
+
'heading-3': [HEADING],
|
|
236
|
+
'heading-4': [HEADING],
|
|
237
|
+
'heading-5': [HEADING],
|
|
238
|
+
'heading-6': [HEADING],
|
|
239
|
+
'bulleted-list': [UNORDERED_LIST],
|
|
240
|
+
'numbered-list': [ORDERED_LIST],
|
|
241
|
+
blockquote: [QUOTE],
|
|
242
|
+
// MULTILINE_ELEMENT_TRANSFORMERS
|
|
243
|
+
'code-block': [CODE],
|
|
244
|
+
// TEXT_FORMAT_TRANSFORMERS
|
|
245
|
+
code: [INLINE_CODE],
|
|
246
|
+
bold: [
|
|
247
|
+
BOLD_STAR,
|
|
248
|
+
// Disabled for Markdown output in `DISABLED_MARKDOWN_TAGS` below
|
|
249
|
+
BOLD_UNDERSCORE,
|
|
250
|
+
BOLD_ITALIC_STAR,
|
|
251
|
+
BOLD_ITALIC_UNDERSCORE,
|
|
252
|
+
],
|
|
253
|
+
italic: [
|
|
254
|
+
ITALIC_UNDERSCORE,
|
|
255
|
+
// Disabled for Markdown output in `DISABLED_MARKDOWN_TAGS` below
|
|
256
|
+
ITALIC_STAR,
|
|
257
|
+
BOLD_ITALIC_STAR,
|
|
258
|
+
BOLD_ITALIC_UNDERSCORE,
|
|
259
|
+
],
|
|
260
|
+
strikethrough: [STRIKETHROUGH],
|
|
261
|
+
// TEXT_MATCH_TRANSFORMERS
|
|
262
|
+
link: [LINK],
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* List of Markdown tags that should be disabled in the editor when converting Lexical nodes to
|
|
267
|
+
* Markdown (but not when converting Markdown to Lexical nodes because we don’t want to lose any
|
|
268
|
+
* formatting). Use underscore for italic text in Markdown instead of asterisks, and use double
|
|
269
|
+
* asterisks for bold text in Markdown instead of underscores. Also, disable triple asterisks and
|
|
270
|
+
* triple underscores for bold+italic text in Markdown, which can be confusing and is not commonly
|
|
271
|
+
* used. This is to ensure that the Markdown output is more readable and consistent.
|
|
272
|
+
*/
|
|
273
|
+
export const DISABLED_MARKDOWN_TAGS = ['*', '__', '***', '___'];
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
export function getSelectionTypes(): TextEditorSelectionState;
|
|
2
|
-
export function onEditorUpdate(editor: LexicalEditor): void;
|
|
3
|
-
export function initEditor({ components, useMarkdownShortcuts, isCodeEditor, defaultLanguage, }: TextEditorConfig):
|
|
2
|
+
export function onEditorUpdate(editor: LexicalEditor, enabledTransformers: Transformer[]): void;
|
|
3
|
+
export function initEditor({ enabledButtons, components, useMarkdownShortcuts, isCodeEditor, defaultLanguage, }: TextEditorConfig): InitEditorResult;
|
|
4
|
+
export function loadCodeHighlighter(lang: string): Promise<void>;
|
|
5
|
+
export function convertMarkdownToLexical(editor: LexicalEditor, value: string, enabledTransformers: Transformer[]): Promise<void>;
|
|
6
|
+
export function focusEditor(editor: LexicalEditor): Promise<void>;
|
|
7
|
+
export type InitEditorResult = {
|
|
8
|
+
/**
|
|
9
|
+
* Editor instance.
|
|
10
|
+
*/
|
|
4
11
|
editor: LexicalEditor;
|
|
12
|
+
/**
|
|
13
|
+
* List of enabled Markdown transformers.
|
|
14
|
+
*/
|
|
15
|
+
enabledTransformers: Transformer[];
|
|
16
|
+
/**
|
|
17
|
+
* Remove all registered Lexical listeners.
|
|
18
|
+
*/
|
|
5
19
|
dispose: () => void;
|
|
6
20
|
};
|
|
7
|
-
export function loadCodeHighlighter(lang: string): Promise<void>;
|
|
8
|
-
export function convertMarkdownToLexical(editor: LexicalEditor, value: string): Promise<void>;
|
|
9
|
-
export function focusEditor(editor: LexicalEditor): Promise<void>;
|
|
10
21
|
import type { TextEditorSelectionState } from '../../typedefs';
|
|
11
22
|
import type { LexicalEditor } from 'lexical';
|
|
23
|
+
import type { Transformer } from '@lexical/markdown';
|
|
12
24
|
import type { TextEditorConfig } from '../../typedefs';
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
import 'prismjs';
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
-
CodeHighlightNode,
|
|
7
|
-
CodeNode,
|
|
8
6
|
$createCodeNode as createCodeNode,
|
|
9
7
|
$isCodeHighlightNode as isCodeHighlightNode,
|
|
10
8
|
$isCodeNode as isCodeNode,
|
|
@@ -15,7 +13,6 @@ import { HorizontalRuleNode } from '@lexical/extension';
|
|
|
15
13
|
import { createEmptyHistoryState, registerHistory } from '@lexical/history';
|
|
16
14
|
import {
|
|
17
15
|
$isLinkNode as isLinkNode,
|
|
18
|
-
LinkNode,
|
|
19
16
|
TOGGLE_LINK_COMMAND,
|
|
20
17
|
$toggleLink as toggleLink,
|
|
21
18
|
} from '@lexical/link';
|
|
@@ -26,20 +23,16 @@ import {
|
|
|
26
23
|
$insertList as insertList,
|
|
27
24
|
$isListItemNode as isListItemNode,
|
|
28
25
|
$isListNode as isListNode,
|
|
29
|
-
ListItemNode,
|
|
30
26
|
ListNode,
|
|
31
27
|
} from '@lexical/list';
|
|
32
28
|
import {
|
|
33
29
|
$convertFromMarkdownString as convertFromMarkdownString,
|
|
34
30
|
$convertToMarkdownString as convertToMarkdownString,
|
|
35
31
|
registerMarkdownShortcuts,
|
|
36
|
-
TRANSFORMERS,
|
|
37
32
|
} from '@lexical/markdown';
|
|
38
33
|
import {
|
|
39
|
-
HeadingNode,
|
|
40
34
|
$isHeadingNode as isHeadingNode,
|
|
41
35
|
$isQuoteNode as isQuoteNode,
|
|
42
|
-
QuoteNode,
|
|
43
36
|
registerRichText,
|
|
44
37
|
} from '@lexical/rich-text';
|
|
45
38
|
import { TableCellNode, TableNode, TableRowNode } from '@lexical/table';
|
|
@@ -57,93 +50,37 @@ import {
|
|
|
57
50
|
OUTDENT_CONTENT_COMMAND,
|
|
58
51
|
} from 'lexical';
|
|
59
52
|
import prismComponents from 'prismjs/components';
|
|
60
|
-
import {
|
|
53
|
+
import {
|
|
54
|
+
BLOCK_BUTTON_TYPES,
|
|
55
|
+
DISABLED_MARKDOWN_TAGS,
|
|
56
|
+
EDITOR_THEME,
|
|
57
|
+
NODE_MAP,
|
|
58
|
+
PRISM_BASE_URL,
|
|
59
|
+
TEXT_FORMAT_BUTTON_TYPES,
|
|
60
|
+
TRANSFORMER_MAP,
|
|
61
|
+
} from './constants.js';
|
|
61
62
|
import { increaseListIndentation, splitMultilineFormatting } from './markdown.js';
|
|
62
63
|
import { HR } from './transformers/hr.js';
|
|
63
64
|
import { TABLE } from './transformers/table.js';
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
67
|
* @import { CreateEditorArgs, LexicalEditor } from 'lexical';
|
|
68
|
+
* @import { Transformer } from '@lexical/markdown';
|
|
67
69
|
* @import {
|
|
68
70
|
* TextEditorBlockType,
|
|
69
71
|
* TextEditorConfig,
|
|
70
72
|
* TextEditorInlineType,
|
|
73
|
+
* TextEditorNodeType,
|
|
71
74
|
* TextEditorSelectionState,
|
|
72
75
|
* } from '../../typedefs';
|
|
73
76
|
*/
|
|
74
77
|
|
|
75
|
-
const allTransformers = [...TRANSFORMERS, HR, TABLE];
|
|
76
|
-
const prismBaseURL = `https://unpkg.com/prismjs@1.30.0`;
|
|
77
|
-
|
|
78
78
|
/**
|
|
79
|
-
*
|
|
80
|
-
* @
|
|
79
|
+
* @typedef {object} InitEditorResult
|
|
80
|
+
* @property {LexicalEditor} editor Editor instance.
|
|
81
|
+
* @property {Transformer[]} enabledTransformers List of enabled Markdown transformers.
|
|
82
|
+
* @property {() => void} dispose Remove all registered Lexical listeners.
|
|
81
83
|
*/
|
|
82
|
-
const editorConfig = {
|
|
83
|
-
namespace: 'editor',
|
|
84
|
-
nodes: [
|
|
85
|
-
HeadingNode,
|
|
86
|
-
QuoteNode,
|
|
87
|
-
LinkNode,
|
|
88
|
-
ListNode,
|
|
89
|
-
ListItemNode,
|
|
90
|
-
CodeNode,
|
|
91
|
-
CodeHighlightNode,
|
|
92
|
-
HorizontalRuleNode,
|
|
93
|
-
TableNode,
|
|
94
|
-
TableCellNode,
|
|
95
|
-
TableRowNode,
|
|
96
|
-
],
|
|
97
|
-
theme: {
|
|
98
|
-
text: {
|
|
99
|
-
/**
|
|
100
|
-
* Enable bold+italic and strikethrough styling.
|
|
101
|
-
* @see https://github.com/facebook/lexical/discussions/4381
|
|
102
|
-
*/
|
|
103
|
-
italic: 'italic',
|
|
104
|
-
strikethrough: 'strikethrough',
|
|
105
|
-
},
|
|
106
|
-
list: {
|
|
107
|
-
nested: {
|
|
108
|
-
listitem: 'nested',
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
code: 'code-block',
|
|
112
|
-
// https://github.com/facebook/lexical/blob/main/packages/lexical-website/docs/getting-started/theming.md
|
|
113
|
-
codeHighlight: {
|
|
114
|
-
atrule: 'token atrule',
|
|
115
|
-
attr: 'token attr',
|
|
116
|
-
boolean: 'token boolean',
|
|
117
|
-
builtin: 'token builtin',
|
|
118
|
-
cdata: 'token cdata',
|
|
119
|
-
char: 'token char',
|
|
120
|
-
class: 'token class',
|
|
121
|
-
'class-name': 'token class-name',
|
|
122
|
-
comment: 'token comment',
|
|
123
|
-
constant: 'token constant',
|
|
124
|
-
deleted: 'token deleted',
|
|
125
|
-
doctype: 'token doctype',
|
|
126
|
-
entity: 'token entity',
|
|
127
|
-
function: 'token function',
|
|
128
|
-
important: 'token important',
|
|
129
|
-
inserted: 'token inserted',
|
|
130
|
-
keyword: 'token keyword',
|
|
131
|
-
namespace: 'token namespace',
|
|
132
|
-
number: 'token number',
|
|
133
|
-
operator: 'token operator',
|
|
134
|
-
prolog: 'token prolog',
|
|
135
|
-
property: 'token property',
|
|
136
|
-
punctuation: 'token punctuation',
|
|
137
|
-
regex: 'token regex',
|
|
138
|
-
selector: 'token selector',
|
|
139
|
-
string: 'token string',
|
|
140
|
-
symbol: 'token symbol',
|
|
141
|
-
tag: 'token tag',
|
|
142
|
-
url: 'token url',
|
|
143
|
-
variable: 'token variable',
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
};
|
|
147
84
|
|
|
148
85
|
/**
|
|
149
86
|
* Get the current selection’s block node key as well as block and inline level types.
|
|
@@ -223,15 +160,18 @@ export const getSelectionTypes = () => {
|
|
|
223
160
|
* Listen to changes made on the editor and trigger the Update event.
|
|
224
161
|
* @internal
|
|
225
162
|
* @param {LexicalEditor} editor Editor instance.
|
|
163
|
+
* @param {Transformer[]} enabledTransformers Enabled Markdown transformers.
|
|
226
164
|
*/
|
|
227
|
-
export const onEditorUpdate = (editor) => {
|
|
165
|
+
export const onEditorUpdate = (editor, enabledTransformers) => {
|
|
166
|
+
const transformers = enabledTransformers.filter(
|
|
167
|
+
(/** @type {any} */ { tag }) => !DISABLED_MARKDOWN_TAGS.includes(tag),
|
|
168
|
+
);
|
|
169
|
+
|
|
228
170
|
editor.getRootElement()?.dispatchEvent(
|
|
229
171
|
new CustomEvent('Update', {
|
|
230
172
|
detail: {
|
|
231
|
-
value: convertToMarkdownString(
|
|
232
|
-
//
|
|
233
|
-
allTransformers.filter((/** @type {any} */ { tag }) => tag !== '*'),
|
|
234
|
-
) // Remove unnecessary backslash for underscore and backslash characters
|
|
173
|
+
value: convertToMarkdownString(transformers)
|
|
174
|
+
// Remove unnecessary backslash for underscore and backslash characters
|
|
235
175
|
// @see https://github.com/sveltia/sveltia-cms/issues/430
|
|
236
176
|
// @see https://github.com/sveltia/sveltia-cms/issues/512
|
|
237
177
|
.replace(/\\([_\\])/g, '$1')
|
|
@@ -249,18 +189,44 @@ export const onEditorUpdate = (editor) => {
|
|
|
249
189
|
/**
|
|
250
190
|
* Initialize the Lexical editor.
|
|
251
191
|
* @param {TextEditorConfig} config Editor configuration.
|
|
252
|
-
* @returns {
|
|
192
|
+
* @returns {InitEditorResult} Editor instance and cleanup.
|
|
253
193
|
*/
|
|
254
194
|
export const initEditor = ({
|
|
195
|
+
enabledButtons = [],
|
|
255
196
|
components = [],
|
|
256
197
|
useMarkdownShortcuts,
|
|
257
198
|
isCodeEditor = false,
|
|
258
199
|
defaultLanguage = 'plain',
|
|
259
200
|
}) => {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
201
|
+
/** @type {CreateEditorArgs} */
|
|
202
|
+
const editorConfig = {
|
|
203
|
+
namespace: 'editor',
|
|
204
|
+
nodes: [
|
|
205
|
+
...components.map(({ node }) => node),
|
|
206
|
+
...new Set(
|
|
207
|
+
Object.entries(NODE_MAP)
|
|
208
|
+
.filter(([button]) => enabledButtons.includes(/** @type {TextEditorNodeType} */ (button)))
|
|
209
|
+
.flatMap(([, nodes]) => nodes),
|
|
210
|
+
),
|
|
211
|
+
HorizontalRuleNode,
|
|
212
|
+
TableNode,
|
|
213
|
+
TableCellNode,
|
|
214
|
+
TableRowNode,
|
|
215
|
+
],
|
|
216
|
+
theme: EDITOR_THEME,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/** @type {Transformer[]} */
|
|
220
|
+
const enabledTransformers = [
|
|
221
|
+
...components.map(({ transformer }) => transformer),
|
|
222
|
+
...new Set(
|
|
223
|
+
Object.entries(TRANSFORMER_MAP)
|
|
224
|
+
.filter(([button]) => enabledButtons.includes(/** @type {TextEditorNodeType} */ (button)))
|
|
225
|
+
.flatMap(([, transformers]) => transformers),
|
|
226
|
+
),
|
|
227
|
+
HR,
|
|
228
|
+
TABLE,
|
|
229
|
+
];
|
|
264
230
|
|
|
265
231
|
const editor = createEditor(editorConfig);
|
|
266
232
|
/** @type {Array<() => void>} */
|
|
@@ -282,63 +248,73 @@ export const initEditor = ({
|
|
|
282
248
|
addUnregister(registerHistory(editor, createEmptyHistoryState(), 1000));
|
|
283
249
|
|
|
284
250
|
if (useMarkdownShortcuts) {
|
|
285
|
-
addUnregister(registerMarkdownShortcuts(editor,
|
|
251
|
+
addUnregister(registerMarkdownShortcuts(editor, enabledTransformers));
|
|
286
252
|
}
|
|
287
253
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
editor.registerCommand(
|
|
300
|
-
TOGGLE_LINK_COMMAND,
|
|
301
|
-
(payload) => {
|
|
302
|
-
toggleLink(typeof payload === 'string' ? payload : null);
|
|
303
|
-
|
|
304
|
-
return true;
|
|
305
|
-
},
|
|
306
|
-
COMMAND_PRIORITY_NORMAL,
|
|
307
|
-
),
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
addUnregister(
|
|
311
|
-
editor.registerCommand(
|
|
312
|
-
INSERT_UNORDERED_LIST_COMMAND,
|
|
313
|
-
() => {
|
|
314
|
-
insertList('bullet');
|
|
254
|
+
if (enabledButtons.includes('code-block') || isCodeEditor) {
|
|
255
|
+
addUnregister(
|
|
256
|
+
registerCodeHighlighting(editor, {
|
|
257
|
+
defaultLanguage,
|
|
258
|
+
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
259
|
+
tokenize: (code, lang = 'plain') =>
|
|
260
|
+
window.Prism.tokenize(code, window.Prism.languages[lang] ?? window.Prism.languages.plain),
|
|
261
|
+
$tokenize: PrismTokenizer.$tokenize,
|
|
262
|
+
}),
|
|
263
|
+
);
|
|
264
|
+
}
|
|
315
265
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
266
|
+
if (enabledButtons.includes('link')) {
|
|
267
|
+
addUnregister(
|
|
268
|
+
editor.registerCommand(
|
|
269
|
+
TOGGLE_LINK_COMMAND,
|
|
270
|
+
(payload) => {
|
|
271
|
+
toggleLink(typeof payload === 'string' ? payload : null);
|
|
272
|
+
|
|
273
|
+
return true;
|
|
274
|
+
},
|
|
275
|
+
COMMAND_PRIORITY_NORMAL,
|
|
276
|
+
),
|
|
277
|
+
);
|
|
278
|
+
}
|
|
321
279
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
280
|
+
if (enabledButtons.includes('bulleted-list')) {
|
|
281
|
+
addUnregister(
|
|
282
|
+
editor.registerCommand(
|
|
283
|
+
INSERT_UNORDERED_LIST_COMMAND,
|
|
284
|
+
() => {
|
|
285
|
+
insertList('bullet');
|
|
286
|
+
|
|
287
|
+
return true;
|
|
288
|
+
},
|
|
289
|
+
COMMAND_PRIORITY_NORMAL,
|
|
290
|
+
),
|
|
291
|
+
);
|
|
292
|
+
}
|
|
327
293
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
294
|
+
if (enabledButtons.includes('numbered-list')) {
|
|
295
|
+
addUnregister(
|
|
296
|
+
editor.registerCommand(
|
|
297
|
+
INSERT_ORDERED_LIST_COMMAND,
|
|
298
|
+
() => {
|
|
299
|
+
insertList('number');
|
|
300
|
+
|
|
301
|
+
return true;
|
|
302
|
+
},
|
|
303
|
+
COMMAND_PRIORITY_NORMAL,
|
|
304
|
+
),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
333
307
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
308
|
+
if (enabledButtons.includes('bulleted-list') || enabledButtons.includes('numbered-list')) {
|
|
309
|
+
// https://github.com/facebook/lexical/blob/main/packages/lexical-react/src/shared/useList.ts
|
|
310
|
+
addUnregister(
|
|
311
|
+
editor.registerCommand(
|
|
312
|
+
INSERT_PARAGRAPH_COMMAND,
|
|
313
|
+
() => handleListInsertParagraph(),
|
|
314
|
+
COMMAND_PRIORITY_NORMAL,
|
|
315
|
+
),
|
|
316
|
+
);
|
|
317
|
+
}
|
|
342
318
|
|
|
343
319
|
addUnregister(
|
|
344
320
|
editor.registerUpdateListener(() => {
|
|
@@ -369,7 +345,7 @@ export const initEditor = ({
|
|
|
369
345
|
}
|
|
370
346
|
}
|
|
371
347
|
|
|
372
|
-
onEditorUpdate(editor);
|
|
348
|
+
onEditorUpdate(editor, enabledTransformers);
|
|
373
349
|
});
|
|
374
350
|
})();
|
|
375
351
|
}),
|
|
@@ -424,6 +400,7 @@ export const initEditor = ({
|
|
|
424
400
|
|
|
425
401
|
return {
|
|
426
402
|
editor,
|
|
403
|
+
enabledTransformers,
|
|
427
404
|
/**
|
|
428
405
|
* Remove all registered Lexical listeners.
|
|
429
406
|
*/
|
|
@@ -455,7 +432,7 @@ export const loadCodeHighlighter = async (lang) => {
|
|
|
455
432
|
|
|
456
433
|
try {
|
|
457
434
|
// eslint-disable-next-line jsdoc/no-bad-blocks
|
|
458
|
-
await import(/* @vite-ignore */ `${
|
|
435
|
+
await import(/* @vite-ignore */ `${PRISM_BASE_URL}/components/prism-${canonicalLang}.min.js`);
|
|
459
436
|
} catch {
|
|
460
437
|
//
|
|
461
438
|
}
|
|
@@ -465,10 +442,11 @@ export const loadCodeHighlighter = async (lang) => {
|
|
|
465
442
|
* Convert Markdown to Lexical nodes.
|
|
466
443
|
* @param {LexicalEditor} editor Editor instance.
|
|
467
444
|
* @param {string} value Current Markdown value.
|
|
445
|
+
* @param {Transformer[]} enabledTransformers List of enabled Markdown transformers.
|
|
468
446
|
* @returns {Promise<void>} Nothing.
|
|
469
447
|
* @throws {Error} Failed to convert the value to Lexical nodes.
|
|
470
448
|
*/
|
|
471
|
-
export const convertMarkdownToLexical = async (editor, value) => {
|
|
449
|
+
export const convertMarkdownToLexical = async (editor, value, enabledTransformers) => {
|
|
472
450
|
// Load Prism language support on demand; the `loadLanguages` Prism utility method cannot be used
|
|
473
451
|
await Promise.all(
|
|
474
452
|
[...value.matchAll(/^```(?<lang>.+?)\n/gm)].map(async ({ groups: { lang = 'plain' } = {} }) =>
|
|
@@ -485,7 +463,7 @@ export const convertMarkdownToLexical = async (editor, value) => {
|
|
|
485
463
|
return new Promise((resolve, reject) => {
|
|
486
464
|
editor.update(() => {
|
|
487
465
|
try {
|
|
488
|
-
convertFromMarkdownString(value,
|
|
466
|
+
convertFromMarkdownString(value, enabledTransformers);
|
|
489
467
|
resolve(undefined);
|
|
490
468
|
} catch (ex) {
|
|
491
469
|
reject(new Error('Failed to convert Markdown', { cause: ex }));
|
|
@@ -88,9 +88,10 @@
|
|
|
88
88
|
};
|
|
89
89
|
|
|
90
90
|
onMount(() => {
|
|
91
|
-
const { editor, dispose } = initEditor(editorStore.config);
|
|
91
|
+
const { editor, enabledTransformers, dispose } = initEditor(editorStore.config);
|
|
92
92
|
|
|
93
93
|
editorStore.editor = editor;
|
|
94
|
+
editorStore.enabledTransformers = enabledTransformers;
|
|
94
95
|
|
|
95
96
|
lexicalRoot?.addEventListener('Update', onUpdate);
|
|
96
97
|
lexicalRoot?.addEventListener('click', onClick);
|
|
@@ -2,8 +2,9 @@ import { generateElementId } from '@sveltia/utils/element';
|
|
|
2
2
|
import { convertMarkdownToLexical } from './core.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* @import { TextEditorConfig, TextEditorSelectionState, TextEditorStore } from '../../typedefs';
|
|
6
5
|
* @import { LexicalEditor } from 'lexical';
|
|
6
|
+
* @import { Transformer } from '@lexical/markdown';
|
|
7
|
+
* @import { TextEditorConfig, TextEditorSelectionState, TextEditorStore } from '../../typedefs';
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -17,6 +18,8 @@ export const createEditorStore = () => {
|
|
|
17
18
|
let initialized = $state(false);
|
|
18
19
|
/** @type {LexicalEditor | undefined} */
|
|
19
20
|
let editor = $state();
|
|
21
|
+
/** @type {Transformer[]} */
|
|
22
|
+
let enabledTransformers = $state([]);
|
|
20
23
|
|
|
21
24
|
/** @type {TextEditorConfig} */
|
|
22
25
|
let config = $state({
|
|
@@ -53,7 +56,7 @@ export const createEditorStore = () => {
|
|
|
53
56
|
// We should avoid an empty editor; there should be at least one `<p>`, so give it an empty
|
|
54
57
|
// string if the `value` is `undefined`
|
|
55
58
|
// @see https://github.com/facebook/lexical/issues/2308
|
|
56
|
-
await convertMarkdownToLexical(editor, inputValue || '');
|
|
59
|
+
await convertMarkdownToLexical(editor, inputValue || '', enabledTransformers);
|
|
57
60
|
} catch (ex) {
|
|
58
61
|
hasConverterError = true;
|
|
59
62
|
inputValue = originalValue;
|
|
@@ -70,6 +73,12 @@ export const createEditorStore = () => {
|
|
|
70
73
|
set editor(newValue) {
|
|
71
74
|
editor = newValue;
|
|
72
75
|
},
|
|
76
|
+
set enabledTransformers(newValue) {
|
|
77
|
+
enabledTransformers = newValue;
|
|
78
|
+
},
|
|
79
|
+
get enabledTransformers() {
|
|
80
|
+
return enabledTransformers;
|
|
81
|
+
},
|
|
73
82
|
get initialized() {
|
|
74
83
|
return initialized;
|
|
75
84
|
},
|
|
@@ -15,12 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* @import { Snippet } from 'svelte';
|
|
18
|
-
* @import {
|
|
19
|
-
* TextEditorBlockType,
|
|
20
|
-
* TextEditorComponent,
|
|
21
|
-
* TextEditorInlineType,
|
|
22
|
-
* TextEditorMode,
|
|
23
|
-
* } from '../../typedefs';
|
|
18
|
+
* @import { TextEditorComponent, TextEditorMode, TextEditorNodeType } from '../../typedefs';
|
|
24
19
|
*/
|
|
25
20
|
|
|
26
21
|
/**
|
|
@@ -29,7 +24,7 @@
|
|
|
29
24
|
* @property {boolean} [flex] Make the text input container flexible.
|
|
30
25
|
* @property {'ltr' | 'rtl' | 'auto'} [dir] The `dir` attribute on the `<textarea>` element.
|
|
31
26
|
* @property {TextEditorMode[]} [modes] Enabled modes.
|
|
32
|
-
* @property {
|
|
27
|
+
* @property {TextEditorNodeType[]} [buttons] Enabled buttons.
|
|
33
28
|
* @property {TextEditorComponent[]} [components] Editor components.
|
|
34
29
|
* @property {boolean} [useMarkdownShortcuts] Whether to enable Markdown keyboard shortcuts in the
|
|
35
30
|
* rich text editor.
|
|
@@ -24,7 +24,7 @@ declare const TextEditor: import("svelte").Component<{
|
|
|
24
24
|
/**
|
|
25
25
|
* Enabled buttons.
|
|
26
26
|
*/
|
|
27
|
-
buttons?:
|
|
27
|
+
buttons?: TextEditorNodeType[] | undefined;
|
|
28
28
|
/**
|
|
29
29
|
* Editor components.
|
|
30
30
|
*/
|
|
@@ -87,7 +87,7 @@ type Props = {
|
|
|
87
87
|
/**
|
|
88
88
|
* Enabled buttons.
|
|
89
89
|
*/
|
|
90
|
-
buttons?:
|
|
90
|
+
buttons?: TextEditorNodeType[] | undefined;
|
|
91
91
|
/**
|
|
92
92
|
* Editor components.
|
|
93
93
|
*/
|
|
@@ -131,7 +131,6 @@ type Props = {
|
|
|
131
131
|
children?: Snippet<[]> | undefined;
|
|
132
132
|
};
|
|
133
133
|
import type { TextEditorMode } from '../../typedefs';
|
|
134
|
-
import type {
|
|
135
|
-
import type { TextEditorInlineType } from '../../typedefs';
|
|
134
|
+
import type { TextEditorNodeType } from '../../typedefs';
|
|
136
135
|
import type { TextEditorComponent } from '../../typedefs';
|
|
137
136
|
import type { Snippet } from 'svelte';
|
|
@@ -82,24 +82,27 @@
|
|
|
82
82
|
</script>
|
|
83
83
|
|
|
84
84
|
<ToolbarWrapper disabled={disabled || readonly} aria-label={_('_sui.text_editor.text_editor')}>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
85
|
+
{#if blockLevelButtons.length > 1}
|
|
86
|
+
<MenuButton
|
|
87
|
+
disabled={!editorStore.useRichText}
|
|
88
|
+
aria-label={_('_sui.text_editor.show_text_style_options')}
|
|
89
|
+
aria-controls="{editorStore.editorId}-lexical-root"
|
|
90
|
+
>
|
|
91
|
+
{#snippet startIcon()}
|
|
92
|
+
<Icon
|
|
93
|
+
name={AVAILABLE_BUTTONS[editorStore.selection.blockType ?? '']?.icon ??
|
|
94
|
+
'format_paragraph'}
|
|
95
|
+
/>
|
|
96
|
+
{/snippet}
|
|
97
|
+
{#snippet popup()}
|
|
98
|
+
<Menu aria-label={_('_sui.text_editor.text_style_options')}>
|
|
99
|
+
{#each blockLevelButtons as type (type)}
|
|
100
|
+
<ToggleBlockMenuItem {type} />
|
|
101
|
+
{/each}
|
|
102
|
+
</Menu>
|
|
103
|
+
{/snippet}
|
|
104
|
+
</MenuButton>
|
|
105
|
+
{/if}
|
|
103
106
|
{#if editorStore.selection.blockType === 'code-block'}
|
|
104
107
|
<Divider orientation="vertical" />
|
|
105
108
|
<CodeLanguageSwitcher disabled={!editorStore.useRichText} />
|
package/dist/typedefs.d.ts
CHANGED
|
@@ -664,6 +664,7 @@ export type ToastPosition = "auto" | "top-left" | "top-center" | "top-right" | "
|
|
|
664
664
|
export type TextEditorBlockType = "paragraph" | "heading-1" | "heading-2" | "heading-3" | "heading-4" | "heading-5" | "heading-6" | "bulleted-list" | "numbered-list" | "blockquote" | "code-block";
|
|
665
665
|
export type TextEditorFormatType = "bold" | "italic" | "strikethrough" | "code";
|
|
666
666
|
export type TextEditorInlineType = TextEditorFormatType | "link";
|
|
667
|
+
export type TextEditorNodeType = TextEditorBlockType | TextEditorInlineType;
|
|
667
668
|
export type TextEditorMode = "rich-text" | "plain-text";
|
|
668
669
|
export type TextEditorComponent = {
|
|
669
670
|
/**
|
|
@@ -701,7 +702,7 @@ export type TextEditorConfig = {
|
|
|
701
702
|
* Enabled buttons for the
|
|
702
703
|
* editor.
|
|
703
704
|
*/
|
|
704
|
-
enabledButtons:
|
|
705
|
+
enabledButtons: TextEditorNodeType[];
|
|
705
706
|
/**
|
|
706
707
|
* Editor components.
|
|
707
708
|
*/
|
|
@@ -739,6 +740,10 @@ export type TextEditorStore = {
|
|
|
739
740
|
* Lexical editor instance.
|
|
740
741
|
*/
|
|
741
742
|
editor: LexicalEditor | undefined;
|
|
743
|
+
/**
|
|
744
|
+
* Enabled Lexical transformers.
|
|
745
|
+
*/
|
|
746
|
+
enabledTransformers: Transformer[];
|
|
742
747
|
/**
|
|
743
748
|
* Whether the Lexical editor is initialized.
|
|
744
749
|
*/
|
package/dist/typedefs.js
CHANGED
|
@@ -270,6 +270,10 @@
|
|
|
270
270
|
* @typedef {TextEditorFormatType | 'link'} TextEditorInlineType
|
|
271
271
|
*/
|
|
272
272
|
|
|
273
|
+
/**
|
|
274
|
+
* @typedef {TextEditorBlockType | TextEditorInlineType} TextEditorNodeType
|
|
275
|
+
*/
|
|
276
|
+
|
|
273
277
|
/**
|
|
274
278
|
* @typedef {'rich-text' | 'plain-text'} TextEditorMode
|
|
275
279
|
*/
|
|
@@ -288,7 +292,7 @@
|
|
|
288
292
|
/**
|
|
289
293
|
* @typedef {object} TextEditorConfig
|
|
290
294
|
* @property {TextEditorMode[]} modes Enabled modes.
|
|
291
|
-
* @property {
|
|
295
|
+
* @property {TextEditorNodeType[]} enabledButtons Enabled buttons for the
|
|
292
296
|
* editor.
|
|
293
297
|
* @property {TextEditorComponent[]} components Editor components.
|
|
294
298
|
* @property {boolean} useMarkdownShortcuts Whether to enable Markdown keyboard shortcuts in the
|
|
@@ -307,6 +311,7 @@
|
|
|
307
311
|
/**
|
|
308
312
|
* @typedef {object} TextEditorStore
|
|
309
313
|
* @property {LexicalEditor | undefined} editor Lexical editor instance.
|
|
314
|
+
* @property {Transformer[]} enabledTransformers Enabled Lexical transformers.
|
|
310
315
|
* @property {boolean} initialized Whether the Lexical editor is initialized.
|
|
311
316
|
* @property {string} editorId Random ID assigned to the editor.
|
|
312
317
|
* @property {TextEditorConfig} config Editor configuration.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltia/ui",
|
|
3
|
-
"version": "0.41.
|
|
3
|
+
"version": "0.41.3",
|
|
4
4
|
"description": "A collection of Svelte components and utilities for building user interfaces.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -55,19 +55,19 @@
|
|
|
55
55
|
"@sveltejs/adapter-auto": "^7.0.1",
|
|
56
56
|
"@sveltejs/kit": "^2.69.1",
|
|
57
57
|
"@sveltejs/package": "^2.5.8",
|
|
58
|
-
"@sveltejs/vite-plugin-svelte": "^7.1.
|
|
59
|
-
"@vitest/coverage-v8": "^4.1.
|
|
58
|
+
"@sveltejs/vite-plugin-svelte": "^7.1.4",
|
|
59
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
60
60
|
"cspell": "^10.0.1",
|
|
61
61
|
"eslint": "^9.39.4",
|
|
62
62
|
"eslint-config-airbnb-extended": "^3.1.0",
|
|
63
63
|
"eslint-config-prettier": "^10.1.8",
|
|
64
64
|
"eslint-plugin-import": "^2.32.0",
|
|
65
|
-
"eslint-plugin-jsdoc": "^63.0.
|
|
65
|
+
"eslint-plugin-jsdoc": "^63.0.12",
|
|
66
66
|
"eslint-plugin-package-json": "^1.5.0",
|
|
67
67
|
"eslint-plugin-svelte": "^3.20.0",
|
|
68
68
|
"globals": "^17.7.0",
|
|
69
69
|
"happy-dom": "^20.10.6",
|
|
70
|
-
"oxlint": "^1.
|
|
70
|
+
"oxlint": "^1.73.0",
|
|
71
71
|
"postcss": "^8.5.16",
|
|
72
72
|
"postcss-html": "^1.8.1",
|
|
73
73
|
"prettier": "^3.9.4",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"svelte-preprocess": "^6.0.5",
|
|
82
82
|
"tslib": "^2.8.1",
|
|
83
83
|
"vite": "^8.1.3",
|
|
84
|
-
"vitest": "^4.1.
|
|
84
|
+
"vitest": "^4.1.10"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"svelte": "^5.0.0"
|