@sveltia/ui 0.77.2 → 0.78.0
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/dialog/dialog.svelte +7 -4
- package/dist/components/text-editor/constants.d.ts +5 -0
- package/dist/components/text-editor/constants.js +6 -0
- package/dist/components/text-editor/core.d.ts +6 -2
- package/dist/components/text-editor/core.js +316 -46
- package/dist/components/text-editor/lexical-root.svelte +62 -2
- package/dist/components/text-editor/lexical-root.svelte.d.ts +10 -0
- package/dist/components/text-editor/raw-markdown.d.ts +90 -0
- package/dist/components/text-editor/raw-markdown.js +471 -0
- package/dist/components/text-editor/shiki/facade.d.ts +4 -0
- package/dist/components/text-editor/shiki/facade.js +62 -0
- package/dist/components/text-editor/shiki/theme.d.ts +1 -0
- package/dist/components/text-editor/shiki/theme.js +31 -27
- 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 +39 -1
- package/dist/components/text-editor/text-editor.svelte +140 -2
- package/dist/components/text-editor/text-editor.svelte.d.ts +23 -5
- package/dist/components/text-editor/toolbar/code-language-switcher.svelte +14 -9
- package/dist/components/text-editor/toolbar/component-editor.svelte +96 -0
- package/dist/components/text-editor/toolbar/component-editor.svelte.d.ts +35 -0
- package/dist/components/text-editor/toolbar/format-text-button.svelte +69 -9
- package/dist/components/text-editor/toolbar/insert-component-dialog.svelte +92 -0
- package/dist/components/text-editor/toolbar/insert-component-dialog.svelte.d.ts +30 -0
- package/dist/components/text-editor/toolbar/insert-item-button.svelte +13 -2
- package/dist/components/text-editor/toolbar/insert-link-button.svelte +89 -10
- package/dist/components/text-editor/toolbar/insert-menu-button.svelte +21 -2
- package/dist/components/text-editor/toolbar/text-editor-toolbar.svelte +4 -4
- package/dist/components/text-editor/toolbar/toggle-block-menu-item.svelte +13 -0
- package/dist/components/text-field/text-area.svelte +119 -4
- package/dist/components/text-field/text-area.svelte.d.ts +17 -0
- package/dist/components/util/font-links.svelte +1 -1
- package/dist/components/util/fonts.js +1 -1
- package/dist/self-hosted/fonts/material-symbols-outlined-latin-wght-normal.woff2 +0 -0
- package/dist/services/group.svelte.d.ts +1 -1
- package/dist/services/group.svelte.js +14 -6
- package/dist/services/tree.svelte.d.ts +6 -1
- package/dist/services/tree.svelte.js +23 -7
- package/dist/typedefs.d.ts +49 -1
- package/dist/typedefs.js +22 -1
- package/package.json +2 -2
|
@@ -199,7 +199,7 @@ export class Group {
|
|
|
199
199
|
activated = false;
|
|
200
200
|
|
|
201
201
|
/**
|
|
202
|
-
* Whether {@link destroy} has run, so a pending {@link activate} must not
|
|
202
|
+
* Whether {@link destroy} has run, so a pending {@link activate} must not run.
|
|
203
203
|
* @type {boolean}
|
|
204
204
|
*/
|
|
205
205
|
#destroyed = false;
|
|
@@ -284,12 +284,14 @@ export class Group {
|
|
|
284
284
|
// eslint-disable-next-line jsdoc/require-description
|
|
285
285
|
/** @type {(event: MouseEvent) => void} */
|
|
286
286
|
this._onClick = (event) => {
|
|
287
|
+
this.activate();
|
|
287
288
|
this.onClick(event);
|
|
288
289
|
};
|
|
289
290
|
|
|
290
291
|
// eslint-disable-next-line jsdoc/require-description
|
|
291
292
|
/** @type {(event: KeyboardEvent) => void} */
|
|
292
293
|
this._onKeyDown = (event) => {
|
|
294
|
+
this.activate();
|
|
293
295
|
this.onKeyDown(event);
|
|
294
296
|
};
|
|
295
297
|
|
|
@@ -352,12 +354,16 @@ export class Group {
|
|
|
352
354
|
attributeFilter: ['aria-disabled', 'aria-hidden'],
|
|
353
355
|
});
|
|
354
356
|
|
|
357
|
+
// Listen right away: a click or a key press that comes before the activation below activates
|
|
358
|
+
// the members first, rather than being lost
|
|
359
|
+
parent.addEventListener('click', this._onClick);
|
|
360
|
+
parent.addEventListener('keydown', this._onKeyDown);
|
|
361
|
+
|
|
355
362
|
// Wait a bit before the relevant components, including the `aria-controls` target are mounted
|
|
356
363
|
(async () => {
|
|
357
364
|
await sleep(100);
|
|
358
365
|
|
|
359
|
-
// The widget may have been unmounted in the meantime
|
|
360
|
-
// would then never be removed
|
|
366
|
+
// The widget may have been unmounted in the meantime
|
|
361
367
|
if (!this.#destroyed) {
|
|
362
368
|
this.activate();
|
|
363
369
|
}
|
|
@@ -365,9 +371,13 @@ export class Group {
|
|
|
365
371
|
}
|
|
366
372
|
|
|
367
373
|
/**
|
|
368
|
-
* Activate the members.
|
|
374
|
+
* Activate the members, unless they already are.
|
|
369
375
|
*/
|
|
370
376
|
activate() {
|
|
377
|
+
if (this.activated) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
371
381
|
const { parent, allMembers, selected: defaultSelected } = this;
|
|
372
382
|
|
|
373
383
|
this.activated = true;
|
|
@@ -408,8 +418,6 @@ export class Group {
|
|
|
408
418
|
});
|
|
409
419
|
|
|
410
420
|
this.updateTabStop();
|
|
411
|
-
parent.addEventListener('click', this._onClick);
|
|
412
|
-
parent.addEventListener('keydown', this._onKeyDown);
|
|
413
421
|
parent.dispatchEvent(new CustomEvent('Initialized'));
|
|
414
422
|
}
|
|
415
423
|
|
|
@@ -45,6 +45,11 @@ export class Tree {
|
|
|
45
45
|
* @type {ReturnType<typeof globalThis.setTimeout> | undefined}
|
|
46
46
|
*/
|
|
47
47
|
typeAheadTimer: ReturnType<typeof globalThis.setTimeout> | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Whether {@link activate} has run.
|
|
50
|
+
* @type {boolean}
|
|
51
|
+
*/
|
|
52
|
+
activated: boolean;
|
|
48
53
|
/**
|
|
49
54
|
* Whether {@link destroy} has run, so a pending {@link activate} must not set anything up.
|
|
50
55
|
* @type {boolean}
|
|
@@ -58,7 +63,7 @@ export class Tree {
|
|
|
58
63
|
_onFocusIn: (event: FocusEvent) => void;
|
|
59
64
|
observer: MutationObserver;
|
|
60
65
|
/**
|
|
61
|
-
* Activate the items.
|
|
66
|
+
* Activate the items, unless they already are.
|
|
62
67
|
*/
|
|
63
68
|
activate(): void;
|
|
64
69
|
/**
|
|
@@ -67,6 +67,12 @@ export class Tree {
|
|
|
67
67
|
*/
|
|
68
68
|
this.typeAheadTimer = undefined;
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Whether {@link activate} has run.
|
|
72
|
+
* @type {boolean}
|
|
73
|
+
*/
|
|
74
|
+
this.activated = false;
|
|
75
|
+
|
|
70
76
|
/**
|
|
71
77
|
* Whether {@link destroy} has run, so a pending {@link activate} must not set anything up.
|
|
72
78
|
* @type {boolean}
|
|
@@ -76,18 +82,21 @@ export class Tree {
|
|
|
76
82
|
// eslint-disable-next-line jsdoc/require-description
|
|
77
83
|
/** @type {(event: MouseEvent) => void} */
|
|
78
84
|
this._onClick = (event) => {
|
|
85
|
+
this.activate();
|
|
79
86
|
this.onClick(event);
|
|
80
87
|
};
|
|
81
88
|
|
|
82
89
|
// eslint-disable-next-line jsdoc/require-description
|
|
83
90
|
/** @type {(event: KeyboardEvent) => void} */
|
|
84
91
|
this._onKeyDown = (event) => {
|
|
92
|
+
this.activate();
|
|
85
93
|
this.onKeyDown(event);
|
|
86
94
|
};
|
|
87
95
|
|
|
88
96
|
// eslint-disable-next-line jsdoc/require-description
|
|
89
97
|
/** @type {(event: FocusEvent) => void} */
|
|
90
98
|
this._onFocusIn = (event) => {
|
|
99
|
+
this.activate();
|
|
91
100
|
this.onFocusIn(event);
|
|
92
101
|
};
|
|
93
102
|
|
|
@@ -99,12 +108,18 @@ export class Tree {
|
|
|
99
108
|
// The widget root itself is never part of the tab order; one of the items always is
|
|
100
109
|
this.parent.tabIndex = -1;
|
|
101
110
|
|
|
111
|
+
// Listen right away: a click, a key press or a focus that comes before the activation below
|
|
112
|
+
// activates the items first, rather than being lost
|
|
113
|
+
parent.addEventListener('click', this._onClick);
|
|
114
|
+
parent.addEventListener('keydown', this._onKeyDown);
|
|
115
|
+
parent.addEventListener('focusin', this._onFocusIn);
|
|
116
|
+
|
|
102
117
|
// Wait a bit before the child components are mounted
|
|
103
118
|
(async () => {
|
|
104
119
|
await sleep(100);
|
|
105
120
|
|
|
106
|
-
// The widget may have been unmounted in the meantime, and the
|
|
107
|
-
//
|
|
121
|
+
// The widget may have been unmounted in the meantime, and the observer set up by
|
|
122
|
+
// `activate()` would then never be disconnected
|
|
108
123
|
if (!this.destroyed) {
|
|
109
124
|
this.activate();
|
|
110
125
|
}
|
|
@@ -112,16 +127,17 @@ export class Tree {
|
|
|
112
127
|
}
|
|
113
128
|
|
|
114
129
|
/**
|
|
115
|
-
* Activate the items.
|
|
130
|
+
* Activate the items, unless they already are.
|
|
116
131
|
*/
|
|
117
132
|
activate() {
|
|
133
|
+
if (this.activated) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
118
137
|
const { parent } = this;
|
|
119
138
|
|
|
139
|
+
this.activated = true;
|
|
120
140
|
this.update();
|
|
121
|
-
|
|
122
|
-
parent.addEventListener('click', this._onClick);
|
|
123
|
-
parent.addEventListener('keydown', this._onKeyDown);
|
|
124
|
-
parent.addEventListener('focusin', this._onFocusIn);
|
|
125
141
|
this.observer.observe(parent, { childList: true, subtree: true });
|
|
126
142
|
parent.dispatchEvent(new CustomEvent('Initialized'));
|
|
127
143
|
}
|
package/dist/typedefs.d.ts
CHANGED
|
@@ -273,7 +273,8 @@ export type DialogProps = {
|
|
|
273
273
|
/**
|
|
274
274
|
* Whether to automatically focus the first input field or primary
|
|
275
275
|
* action button. Default: `true`. If `false`, or if the dialog has neither, the `<dialog>` element
|
|
276
|
-
* gets focused instead, so the focus is always moved into the modal.
|
|
276
|
+
* gets focused instead, so the focus is always moved into the modal. The focus is left alone if it
|
|
277
|
+
* has already moved into the dialog content by then, like when the user has clicked an input field.
|
|
277
278
|
*/
|
|
278
279
|
focusInput?: boolean | undefined;
|
|
279
280
|
/**
|
|
@@ -862,6 +863,32 @@ export type CodeHighlighterLoaders = {
|
|
|
862
863
|
*/
|
|
863
864
|
loadTheme: (id: string) => Promise<any>;
|
|
864
865
|
};
|
|
866
|
+
/**
|
|
867
|
+
* Syntax-highlighted fragment of text, as painted behind a `<textarea>`.
|
|
868
|
+
*/
|
|
869
|
+
export type HighlightedToken = {
|
|
870
|
+
/**
|
|
871
|
+
* Text content.
|
|
872
|
+
*/
|
|
873
|
+
content: string;
|
|
874
|
+
/**
|
|
875
|
+
* CSS colour. The text’s default colour is used when omitted.
|
|
876
|
+
*/
|
|
877
|
+
color?: string | undefined;
|
|
878
|
+
/**
|
|
879
|
+
* Whether to embolden the text. It’s rendered with a stroke, so the text
|
|
880
|
+
* width doesn’t change.
|
|
881
|
+
*/
|
|
882
|
+
bold?: boolean | undefined;
|
|
883
|
+
/**
|
|
884
|
+
* Whether to underline the text.
|
|
885
|
+
*/
|
|
886
|
+
underline?: boolean | undefined;
|
|
887
|
+
/**
|
|
888
|
+
* Whether to strike through the text.
|
|
889
|
+
*/
|
|
890
|
+
strikethrough?: boolean | undefined;
|
|
891
|
+
};
|
|
865
892
|
/**
|
|
866
893
|
* Web font used by the components, published on Fontsource.
|
|
867
894
|
*/
|
|
@@ -990,6 +1017,16 @@ export type TextEditorStore = {
|
|
|
990
1017
|
* plain text editor.
|
|
991
1018
|
*/
|
|
992
1019
|
useRichText: boolean;
|
|
1020
|
+
/**
|
|
1021
|
+
* The `<textarea>` element of the plain text
|
|
1022
|
+
* mode.
|
|
1023
|
+
*/
|
|
1024
|
+
textArea: HTMLTextAreaElement | undefined;
|
|
1025
|
+
/**
|
|
1026
|
+
* ID of the editable element currently shown: the Lexical root in the
|
|
1027
|
+
* rich text mode, or the `<textarea>` in the plain text mode.
|
|
1028
|
+
*/
|
|
1029
|
+
controlId: string;
|
|
993
1030
|
/**
|
|
994
1031
|
* Whether there was an error while converting Markdown to
|
|
995
1032
|
* Lexical nodes.
|
|
@@ -999,10 +1036,21 @@ export type TextEditorStore = {
|
|
|
999
1036
|
* Whether to show a converter error in the UI.
|
|
1000
1037
|
*/
|
|
1001
1038
|
showConverterError: boolean;
|
|
1039
|
+
/**
|
|
1040
|
+
* Whether the user has changed the rich text content, and the editor
|
|
1041
|
+
* has yet to convert it to Markdown and update {@link TextEditorStore.inputValue}.
|
|
1042
|
+
*/
|
|
1043
|
+
pending: boolean;
|
|
1002
1044
|
/**
|
|
1003
1045
|
* Function to trigger the Lexical converter.
|
|
1004
1046
|
*/
|
|
1005
1047
|
convertMarkdown: () => Promise<void>;
|
|
1048
|
+
/**
|
|
1049
|
+
* Function to check if the given value,
|
|
1050
|
+
* exported by the editor, is only the {@link TextEditorStore.inputValue} last imported, written in
|
|
1051
|
+
* the editor’s own Markdown style, e.g. `_text_` for `*text*`, rather than a change.
|
|
1052
|
+
*/
|
|
1053
|
+
isRestyledImport: (value: string) => boolean;
|
|
1006
1054
|
};
|
|
1007
1055
|
export type SelectedItemDetail = {
|
|
1008
1056
|
/**
|
package/dist/typedefs.js
CHANGED
|
@@ -100,7 +100,8 @@
|
|
|
100
100
|
* @property {boolean} [cancelDisabled] Whether to disable the Cancel button.
|
|
101
101
|
* @property {boolean} [focusInput] Whether to automatically focus the first input field or primary
|
|
102
102
|
* action button. Default: `true`. If `false`, or if the dialog has neither, the `<dialog>` element
|
|
103
|
-
* gets focused instead, so the focus is always moved into the modal.
|
|
103
|
+
* gets focused instead, so the focus is always moved into the modal. The focus is left alone if it
|
|
104
|
+
* has already moved into the dialog content by then, like when the user has clicked an input field.
|
|
104
105
|
* @property {boolean} [lightDismiss] Whether to close the modal when the backdrop (outside of the
|
|
105
106
|
* modal) is clicked.
|
|
106
107
|
* @property {string} [value] Value entered on the textbox.
|
|
@@ -369,6 +370,17 @@
|
|
|
369
370
|
* @property {(id: string) => Promise<any>} loadTheme Load a theme by ID.
|
|
370
371
|
*/
|
|
371
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Syntax-highlighted fragment of text, as painted behind a `<textarea>`.
|
|
375
|
+
* @typedef {object} HighlightedToken
|
|
376
|
+
* @property {string} content Text content.
|
|
377
|
+
* @property {string} [color] CSS colour. The text’s default colour is used when omitted.
|
|
378
|
+
* @property {boolean} [bold] Whether to embolden the text. It’s rendered with a stroke, so the text
|
|
379
|
+
* width doesn’t change.
|
|
380
|
+
* @property {boolean} [underline] Whether to underline the text.
|
|
381
|
+
* @property {boolean} [strikethrough] Whether to strike through the text.
|
|
382
|
+
*/
|
|
383
|
+
|
|
372
384
|
/**
|
|
373
385
|
* Web font used by the components, published on Fontsource.
|
|
374
386
|
* @typedef {object} FontDefinition
|
|
@@ -423,10 +435,19 @@
|
|
|
423
435
|
* @property {TextEditorSelectionState} selection Current selection state.
|
|
424
436
|
* @property {boolean} useRichText Whether to use rich text mode. If `false`, the editor shows the
|
|
425
437
|
* plain text editor.
|
|
438
|
+
* @property {HTMLTextAreaElement | undefined} textArea The `<textarea>` element of the plain text
|
|
439
|
+
* mode.
|
|
440
|
+
* @property {string} controlId ID of the editable element currently shown: the Lexical root in the
|
|
441
|
+
* rich text mode, or the `<textarea>` in the plain text mode.
|
|
426
442
|
* @property {boolean} hasConverterError Whether there was an error while converting Markdown to
|
|
427
443
|
* Lexical nodes.
|
|
428
444
|
* @property {boolean} showConverterError Whether to show a converter error in the UI.
|
|
445
|
+
* @property {boolean} pending Whether the user has changed the rich text content, and the editor
|
|
446
|
+
* has yet to convert it to Markdown and update {@link TextEditorStore.inputValue}.
|
|
429
447
|
* @property {() => Promise<void>} convertMarkdown Function to trigger the Lexical converter.
|
|
448
|
+
* @property {(value: string) => boolean} isRestyledImport Function to check if the given value,
|
|
449
|
+
* exported by the editor, is only the {@link TextEditorStore.inputValue} last imported, written in
|
|
450
|
+
* the editor’s own Markdown style, e.g. `_text_` for `*text*`, rather than a change.
|
|
430
451
|
*/
|
|
431
452
|
|
|
432
453
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltia/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.78.0",
|
|
4
4
|
"description": "A collection of Svelte components and utilities for building user interfaces.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"lexical": "^0.51.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@fontsource-variable/material-symbols-outlined": "5.3.
|
|
64
|
+
"@fontsource-variable/material-symbols-outlined": "5.3.8",
|
|
65
65
|
"@fontsource-variable/source-sans-3": "5.3.0",
|
|
66
66
|
"@fontsource/noto-mono": "5.3.0",
|
|
67
67
|
"@rollup/plugin-yaml": "^5.0.0",
|