@nldd/design-system 0.8.86 → 0.8.87
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/custom-elements.json +660 -142
- package/dist/components/actions/icon-button/icon-button.d.ts +2 -2
- package/dist/components/actions/icon-button/icon-button.d.ts.map +1 -1
- package/dist/components/actions/icon-button/icon-button.js +3 -3
- package/dist/components/actions/icon-button/icon-button.js.map +1 -1
- package/dist/components/components.js +1140 -243
- package/dist/components/content/avatar/avatar.d.ts +6 -6
- package/dist/components/content/avatar/avatar.d.ts.map +1 -1
- package/dist/components/content/avatar/avatar.js +9 -9
- package/dist/components/content/avatar/avatar.js.map +1 -1
- package/dist/components/content/icon/icon-aliases.d.ts.map +1 -1
- package/dist/components/content/icon/icon-aliases.js +4 -0
- package/dist/components/content/icon/icon-aliases.js.map +1 -1
- package/dist/components/content/icon/icon-gallery-status.d.ts.map +1 -1
- package/dist/components/content/icon/icon-gallery-status.js +3 -26
- package/dist/components/content/icon/icon-gallery-status.js.map +1 -1
- package/dist/components/content/icon/icon-registry.d.ts.map +1 -1
- package/dist/components/content/icon/icon-registry.js +2 -0
- package/dist/components/content/icon/icon-registry.js.map +1 -1
- package/dist/components/content/icon/icon.d.ts +2 -2
- package/dist/components/content/icon/icon.d.ts.map +1 -1
- package/dist/components/content/icon/icon.js +3 -3
- package/dist/components/content/icon/icon.js.map +1 -1
- package/dist/components/content/icon/icon.styles.d.ts.map +1 -1
- package/dist/components/content/icon/icon.styles.js +8 -2
- package/dist/components/content/icon/icon.styles.js.map +1 -1
- package/dist/components/content/rich-text/rich-text.d.ts +7 -6
- package/dist/components/content/rich-text/rich-text.d.ts.map +1 -1
- package/dist/components/content/rich-text/rich-text.js +8 -7
- package/dist/components/content/rich-text/rich-text.js.map +1 -1
- package/dist/components/content/text/text.d.ts +2 -2
- package/dist/components/content/text/text.js +3 -3
- package/dist/components/content/title/title.d.ts +5 -5
- package/dist/components/content/title/title.d.ts.map +1 -1
- package/dist/components/content/title/title.js +6 -6
- package/dist/components/content/title/title.js.map +1 -1
- package/dist/components/content/tooltip/tooltip.d.ts +2 -2
- package/dist/components/content/tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/content/tooltip/tooltip.js +4 -4
- package/dist/components/content/tooltip/tooltip.js.map +1 -1
- package/dist/components/{dist-C09E9-dJ.js → dist-B_Mnmrj4.js} +1 -1
- package/dist/components/{dist-CjaG8dOI.js → dist-ByH8hQze.js} +2 -2
- package/dist/components/{dist-BB7TxeMK.js → dist-CRwuSgMM.js} +2 -2
- package/dist/components/{dist-la_b3ZSq.js → dist-CSrO_mYe.js} +1 -1
- package/dist/components/{dist-762GHPyH.js → dist-CX3DK4i7.js} +3 -3
- package/dist/components/{dist-DZoFKUO-.js → dist-CbCO0WCd.js} +1 -1
- package/dist/components/{dist-B_3OW7pC.js → dist-CgDuh26K.js} +1 -1
- package/dist/components/{dist-DaavuU6W.js → dist-DXZ-cFAl.js} +2 -2
- package/dist/components/{dist-CRsR6ckU.js → dist-LX8LuMac.js} +1 -1
- package/dist/components/{dist-BJI4-6iQ.js → dist-eVFegyjM.js} +1 -1
- package/dist/components/{dist-C6gnorjP.js → dist-fIxe0l7k.js} +9 -1
- package/dist/components/{icon-Cd4BloIM.js → icon-C_zwJZ_g.js} +14 -4
- package/dist/components/{icon-button-CXN0yaVx.js → icon-button-CEz4MB9H.js} +10 -10
- package/dist/components/inputs/code-editor/code-editor.styles.js +2 -2
- package/dist/components/inputs/text-editor/text-editor.annotation-sentinels.d.ts +3 -5
- package/dist/components/inputs/text-editor/text-editor.annotation-sentinels.d.ts.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.annotation-sentinels.js +30 -44
- package/dist/components/inputs/text-editor/text-editor.annotation-sentinels.js.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.annotations.d.ts.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.annotations.js +31 -5
- package/dist/components/inputs/text-editor/text-editor.annotations.js.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.commands.d.ts +14 -2
- package/dist/components/inputs/text-editor/text-editor.commands.d.ts.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.commands.js +115 -36
- package/dist/components/inputs/text-editor/text-editor.commands.js.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.cursor.d.ts +7 -0
- package/dist/components/inputs/text-editor/text-editor.cursor.d.ts.map +1 -0
- package/dist/components/inputs/text-editor/text-editor.cursor.js +207 -0
- package/dist/components/inputs/text-editor/text-editor.cursor.js.map +1 -0
- package/dist/components/inputs/text-editor/text-editor.d.ts +65 -13
- package/dist/components/inputs/text-editor/text-editor.d.ts.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.emphasis.d.ts +32 -0
- package/dist/components/inputs/text-editor/text-editor.emphasis.d.ts.map +1 -0
- package/dist/components/inputs/text-editor/text-editor.emphasis.js +229 -0
- package/dist/components/inputs/text-editor/text-editor.emphasis.js.map +1 -0
- package/dist/components/inputs/text-editor/text-editor.js +177 -18
- package/dist/components/inputs/text-editor/text-editor.js.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.links.d.ts +8 -0
- package/dist/components/inputs/text-editor/text-editor.links.d.ts.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.links.js +30 -4
- package/dist/components/inputs/text-editor/text-editor.links.js.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.markdown.d.ts.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.markdown.js +52 -18
- package/dist/components/inputs/text-editor/text-editor.markdown.js.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.mentions.d.ts +78 -11
- package/dist/components/inputs/text-editor/text-editor.mentions.d.ts.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.mentions.js +190 -41
- package/dist/components/inputs/text-editor/text-editor.mentions.js.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.ordered-list.d.ts +0 -2
- package/dist/components/inputs/text-editor/text-editor.ordered-list.d.ts.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.ordered-list.js +21 -1
- package/dist/components/inputs/text-editor/text-editor.ordered-list.js.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.styles.d.ts.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.styles.js +11 -10
- package/dist/components/inputs/text-editor/text-editor.styles.js.map +1 -1
- package/dist/components/inputs/text-editor/text-editor.syntax.d.ts +9 -0
- package/dist/components/inputs/text-editor/text-editor.syntax.d.ts.map +1 -0
- package/dist/components/inputs/text-editor/text-editor.syntax.js +20 -0
- package/dist/components/inputs/text-editor/text-editor.syntax.js.map +1 -0
- package/dist/components/layout/page-sections/page-section-controls.d.ts +0 -70
- package/dist/components/layout/page-sections/page-section-controls.d.ts.map +1 -1
- package/dist/components/layout/page-sections/page-section-controls.js +0 -3
- package/dist/components/layout/page-sections/page-section-controls.js.map +1 -1
- package/dist/components/layout/sheet/sheet.d.ts +3 -7
- package/dist/components/layout/sheet/sheet.d.ts.map +1 -1
- package/dist/components/layout/sheet/sheet.js +4 -18
- package/dist/components/layout/sheet/sheet.js.map +1 -1
- package/dist/components/layout/sheet/sheet.styles.d.ts.map +1 -1
- package/dist/components/layout/sheet/sheet.styles.js +0 -4
- package/dist/components/layout/sheet/sheet.styles.js.map +1 -1
- package/dist/components/layout/sheet/sheet.template.js +2 -2
- package/dist/components/layout/sheet/sheet.template.js.map +1 -1
- package/dist/components/layout/window/window.d.ts +2 -4
- package/dist/components/layout/window/window.d.ts.map +1 -1
- package/dist/components/layout/window/window.js +4 -14
- package/dist/components/layout/window/window.js.map +1 -1
- package/dist/components/layout/window/window.template.d.ts.map +1 -1
- package/dist/components/layout/window/window.template.js +2 -2
- package/dist/components/layout/window/window.template.js.map +1 -1
- package/dist/components/lists-and-tables/cells/icon-cell/icon-cell.d.ts +2 -2
- package/dist/components/lists-and-tables/cells/icon-cell/icon-cell.js +3 -3
- package/dist/components/lists-and-tables/cells/text-cell/text-cell.d.ts +2 -2
- package/dist/components/lists-and-tables/cells/text-cell/text-cell.js +3 -3
- package/dist/components/lists-and-tables/cells/title-cell/title-cell.d.ts +2 -2
- package/dist/components/lists-and-tables/cells/title-cell/title-cell.js +3 -3
- package/dist/components/lists-and-tables/list/list.d.ts +4 -2
- package/dist/components/lists-and-tables/list/list.d.ts.map +1 -1
- package/dist/components/lists-and-tables/list/list.js +23 -5
- package/dist/components/lists-and-tables/list/list.js.map +1 -1
- package/dist/components/navigation/document-tab-bar/document-tab-bar.template.js +1 -1
- package/dist/components/navigation/document-tab-bar/document-tab-bar.template.js.map +1 -1
- package/dist/components/navigation/link/link.d.ts +2 -2
- package/dist/components/navigation/link/link.d.ts.map +1 -1
- package/dist/components/navigation/link/link.js +3 -2
- package/dist/components/navigation/link/link.js.map +1 -1
- package/dist/components/status-and-feedback/activity-indicator/activity-indicator.d.ts +3 -3
- package/dist/components/status-and-feedback/activity-indicator/activity-indicator.d.ts.map +1 -1
- package/dist/components/status-and-feedback/activity-indicator/activity-indicator.js +4 -4
- package/dist/components/status-and-feedback/activity-indicator/activity-indicator.js.map +1 -1
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.d.ts +8 -0
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.d.ts.map +1 -1
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.js +14 -0
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.js.map +1 -1
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.styles.d.ts.map +1 -1
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.styles.js +22 -1
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.styles.js.map +1 -1
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.template.d.ts.map +1 -1
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.template.js +6 -2
- package/dist/components/status-and-feedback/inline-dialog/inline-dialog.template.js.map +1 -1
- package/dist/components/status-and-feedback/modal-dialog/modal-dialog.d.ts +3 -1
- package/dist/components/status-and-feedback/modal-dialog/modal-dialog.d.ts.map +1 -1
- package/dist/components/status-and-feedback/modal-dialog/modal-dialog.js +5 -0
- package/dist/components/status-and-feedback/modal-dialog/modal-dialog.js.map +1 -1
- package/dist/components/status-and-feedback/modal-dialog/modal-dialog.template.d.ts.map +1 -1
- package/dist/components/status-and-feedback/modal-dialog/modal-dialog.template.js +1 -0
- package/dist/components/status-and-feedback/modal-dialog/modal-dialog.template.js.map +1 -1
- package/dist/favicon.svg +8 -2
- package/dist/nldd.min.js +525 -496
- package/dist/types/vue.d.ts +31 -23
- package/package.json +1 -1
|
@@ -3,14 +3,14 @@ import { n as slottedReset, t as inheritedTextReset } from "./shadow-resets-aG-r
|
|
|
3
3
|
import { t as __decorate } from "./decorate-lwt_OrAG.js";
|
|
4
4
|
import { t as withTranslations } from "./with-translations-CqUV9S5g.js";
|
|
5
5
|
import { t as reflectNonDefault } from "./reflect-non-default-OLaK60rT.js";
|
|
6
|
-
import { i as PopupAnchorController, n as NLDDTooltip, r as NLDDActivityIndicator, t as NLDDIconButton } from "./icon-button-
|
|
7
|
-
import { t as NLDDIcon } from "./icon-
|
|
6
|
+
import { i as PopupAnchorController, n as NLDDTooltip, r as NLDDActivityIndicator, t as NLDDIconButton } from "./icon-button-CEz4MB9H.js";
|
|
7
|
+
import { t as NLDDIcon } from "./icon-C_zwJZ_g.js";
|
|
8
8
|
import { n as isPointerMode, r as isTouchMode, t as isKeyboardMode } from "./input-modality-DhTeUxKi.js";
|
|
9
9
|
import { t as breakpoints } from "./breakpoints-CkxsiRgH.js";
|
|
10
10
|
import { t as VisibilityMixin } from "./visibility-mixin-BU1vIMW7.js";
|
|
11
|
-
import { $ as
|
|
12
|
-
import { i as completionStatus, n as autocompletion, s as startCompletion, t as CompletionContext } from "./dist-
|
|
13
|
-
import { n as html$2, r as htmlCompletionSource } from "./dist-
|
|
11
|
+
import { $ as layer, A as syntaxTree, B as Tree, C as indentNodeProp, Ct as findClusterBreak, D as matchBrackets, E as languageDataProp, F as NodeProp, G as RectangleMarker, H as Decoration, I as NodeSet, J as drawSelection, K as ViewPlugin, L as NodeType, M as styleTags, N as tags, Q as keymap, S as getIndentation, St as countColumn, T as indentUnit, U as Direction, V as parseMixed, W as EditorView, X as getDrawSelectionConfig, Y as dropCursor, _t as Text, a as HighlightStyle, at as ChangeDesc, b as foldService, c as Language, ct as EditorSelection, d as ParseContext, et as lineNumbers, f as StreamLanguage, ft as Prec, gt as StateField, h as defineLanguageFacet, ht as StateEffect, it as Annotation, j as Tag, k as syntaxHighlighting, l as LanguageDescription, lt as EditorState, nt as placeholder, o as IndentContext, ot as ChangeSet, pt as RangeSetBuilder, q as WidgetType, st as Compartment, u as LanguageSupport, ut as Facet, vt as Transaction, w as indentString, x as getIndentUnit, xt as combineConfig, y as foldNodeProp, z as Parser } from "./dist-fIxe0l7k.js";
|
|
12
|
+
import { i as completionStatus, n as autocompletion, s as startCompletion, t as CompletionContext } from "./dist-CgDuh26K.js";
|
|
13
|
+
import { n as html$2, r as htmlCompletionSource } from "./dist-CX3DK4i7.js";
|
|
14
14
|
import { LitElement, css, html, nothing, svg, unsafeCSS } from "lit";
|
|
15
15
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
16
16
|
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
@@ -1956,7 +1956,7 @@ function template$21() {
|
|
|
1956
1956
|
* @element nldd-icon-cell
|
|
1957
1957
|
* @attr {string} vertical-alignment - Vertical alignment: 'top' | 'center' | 'bottom' (default: 'center')
|
|
1958
1958
|
* @attr {string} size - Size: '16' | '20' | '24' | '32' (default: '24')
|
|
1959
|
-
* @attr {'
|
|
1959
|
+
* @attr {'content' | 'secondary' | 'accent' | 'success' | 'warning' | 'critical'} color - Color variant of the icon (default: 'content')
|
|
1960
1960
|
* @attr {string} icon - Icon name (renders `<nldd-icon>`). Takes precedence over the default slot.
|
|
1961
1961
|
*
|
|
1962
1962
|
* @slot - Fallback for custom icon content when `icon` is not set.
|
|
@@ -1968,7 +1968,7 @@ var NLDDIconCell = (_NLDDIconCell = class NLDDIconCell extends VisibilityMixin(L
|
|
|
1968
1968
|
super(..._args);
|
|
1969
1969
|
this.verticalAlignment = "center";
|
|
1970
1970
|
this.size = "24";
|
|
1971
|
-
this.color = "
|
|
1971
|
+
this.color = "content";
|
|
1972
1972
|
this.icon = "";
|
|
1973
1973
|
}
|
|
1974
1974
|
render() {
|
|
@@ -1986,7 +1986,7 @@ __decorate([property({
|
|
|
1986
1986
|
})], NLDDIconCell.prototype, "size", void 0);
|
|
1987
1987
|
__decorate([property({
|
|
1988
1988
|
reflect: true,
|
|
1989
|
-
converter: reflectNonDefault("
|
|
1989
|
+
converter: reflectNonDefault("content")
|
|
1990
1990
|
})], NLDDIconCell.prototype, "color", void 0);
|
|
1991
1991
|
__decorate([property({
|
|
1992
1992
|
type: String,
|
|
@@ -2364,7 +2364,7 @@ function template$20() {
|
|
|
2364
2364
|
*
|
|
2365
2365
|
* @element nldd-text-cell
|
|
2366
2366
|
* @attr {string} size - Cell size: 'sm' | 'md' (default: 'md')
|
|
2367
|
-
* @attr {string} color - Text color variant: '
|
|
2367
|
+
* @attr {string} color - Text color variant: 'content' (the default) | 'secondary' | 'accent' | 'success' | 'warning' | 'critical'. All variants other than those two apply to all three text fields so the cell reads as a coherent state.
|
|
2368
2368
|
* @attr {string} width - 'full' | 'fit-content' | CSS length (e.g. '200px', '20rem'). Default: 'full'
|
|
2369
2369
|
* @attr {string} min-width - Minimum width as CSS length (e.g. '80px', '5rem')
|
|
2370
2370
|
* @attr {string} max-width - Maximum width as CSS length (e.g. '200px', '20rem')
|
|
@@ -2401,7 +2401,7 @@ var NLDDTextCell = (_NLDDTextCell = class NLDDTextCell extends VisibilityMixin(L
|
|
|
2401
2401
|
constructor(..._args) {
|
|
2402
2402
|
super(..._args);
|
|
2403
2403
|
this.size = "md";
|
|
2404
|
-
this.color = "
|
|
2404
|
+
this.color = "content";
|
|
2405
2405
|
this.width = "full";
|
|
2406
2406
|
this.horizontalAlignment = "left";
|
|
2407
2407
|
this.verticalAlignment = "center";
|
|
@@ -2458,7 +2458,7 @@ __decorate([property({
|
|
|
2458
2458
|
})], NLDDTextCell.prototype, "size", void 0);
|
|
2459
2459
|
__decorate([property({
|
|
2460
2460
|
reflect: true,
|
|
2461
|
-
converter: reflectNonDefault("
|
|
2461
|
+
converter: reflectNonDefault("content")
|
|
2462
2462
|
})], NLDDTextCell.prototype, "color", void 0);
|
|
2463
2463
|
__decorate([property({
|
|
2464
2464
|
reflect: true,
|
|
@@ -2878,7 +2878,7 @@ var inlineDialogStyles = css`
|
|
|
2878
2878
|
|
|
2879
2879
|
/* # Elements */
|
|
2880
2880
|
|
|
2881
|
-
.inline-
|
|
2881
|
+
.inline-dialog {
|
|
2882
2882
|
box-sizing: border-box;
|
|
2883
2883
|
display: flex;
|
|
2884
2884
|
max-width: var(--primitives-area-480);
|
|
@@ -2887,6 +2887,10 @@ var inlineDialogStyles = css`
|
|
|
2887
2887
|
align-items: center;
|
|
2888
2888
|
}
|
|
2889
2889
|
|
|
2890
|
+
.inline-dialog--left-aligned {
|
|
2891
|
+
align-items: stretch;
|
|
2892
|
+
}
|
|
2893
|
+
|
|
2890
2894
|
.inline-dialog__main {
|
|
2891
2895
|
display: flex;
|
|
2892
2896
|
width: 100%;
|
|
@@ -2895,6 +2899,10 @@ var inlineDialogStyles = css`
|
|
|
2895
2899
|
gap: var(--primitives-space-2);
|
|
2896
2900
|
}
|
|
2897
2901
|
|
|
2902
|
+
.inline-dialog--left-aligned .inline-dialog__main {
|
|
2903
|
+
align-items: stretch;
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2898
2906
|
.inline-dialog__icon {
|
|
2899
2907
|
display: flex;
|
|
2900
2908
|
width: var(--_icon-size);
|
|
@@ -2926,8 +2934,21 @@ var inlineDialogStyles = css`
|
|
|
2926
2934
|
text-wrap: pretty;
|
|
2927
2935
|
}
|
|
2928
2936
|
|
|
2937
|
+
.inline-dialog--left-aligned .inline-dialog__text,
|
|
2938
|
+
.inline-dialog--left-aligned .inline-dialog__supporting-text {
|
|
2939
|
+
text-align: left;
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2929
2942
|
.inline-dialog__content {
|
|
2943
|
+
display: flex;
|
|
2930
2944
|
width: 100%;
|
|
2945
|
+
flex-direction: column;
|
|
2946
|
+
align-items: center;
|
|
2947
|
+
padding-top: var(--primitives-space-16);
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
.inline-dialog--left-aligned .inline-dialog__content {
|
|
2951
|
+
align-items: stretch;
|
|
2931
2952
|
}
|
|
2932
2953
|
|
|
2933
2954
|
.inline-dialog__content[hidden] {
|
|
@@ -2946,8 +2967,10 @@ var inlineDialogStyles = css`
|
|
|
2946
2967
|
//#endregion
|
|
2947
2968
|
//#region src/components/status-and-feedback/inline-dialog/inline-dialog.template.ts
|
|
2948
2969
|
function inlineDialogTemplate(component) {
|
|
2970
|
+
const alignment = component._resolvedHorizontalAlignment;
|
|
2971
|
+
const blockClass = ["inline-dialog", alignment === "left" ? "inline-dialog--left-aligned" : ""].filter(Boolean).join(" ");
|
|
2949
2972
|
return html`
|
|
2950
|
-
<div class
|
|
2973
|
+
<div class=${blockClass}>
|
|
2951
2974
|
<div class="inline-dialog__main">
|
|
2952
2975
|
${component.variant === "loading" ? html`
|
|
2953
2976
|
<div class="inline-dialog__icon">
|
|
@@ -2976,7 +2999,7 @@ function inlineDialogTemplate(component) {
|
|
|
2976
2999
|
<div class="inline-dialog__footer"
|
|
2977
3000
|
?hidden=${!component._hasActions}
|
|
2978
3001
|
>
|
|
2979
|
-
<nldd-button-group orientation
|
|
3002
|
+
<nldd-button-group orientation=${alignment === "left" ? "horizontal" : "vertical"}>
|
|
2980
3003
|
<slot name="actions"></slot>
|
|
2981
3004
|
</nldd-button-group>
|
|
2982
3005
|
</div>
|
|
@@ -3110,6 +3133,7 @@ NLDDButtonGroup = __decorate([customElement("nldd-button-group")], NLDDButtonGro
|
|
|
3110
3133
|
* @attr {string} text - Main text (heading or paragraph, depending on heading-level)
|
|
3111
3134
|
* @attr {string} supporting-text - Supporting text below the heading
|
|
3112
3135
|
* @attr {1|2|3|4|5|6} heading-level - Renders text as h1–h6; absent renders a p
|
|
3136
|
+
* @attr {'left'|'center'} horizontal-alignment - Overrides the alignment of text, icon and actions. Unset (the default) derives it: content in the default slot means a task, which aligns left; a bare message stays centered. Left alignment also lays the actions out in a row instead of stacked full-width.
|
|
3113
3137
|
*
|
|
3114
3138
|
* @slot - Optional custom content between text and actions
|
|
3115
3139
|
* @slot actions - nldd-button elements, wrapped in nldd-button-group (max 3)
|
|
@@ -3125,6 +3149,7 @@ var NLDDInlineDialog = (_NLDDInlineDialog = class NLDDInlineDialog extends LitEl
|
|
|
3125
3149
|
this.text = "";
|
|
3126
3150
|
this.supportingText = "";
|
|
3127
3151
|
this.headingLevel = null;
|
|
3152
|
+
this.horizontalAlignment = "";
|
|
3128
3153
|
this._hasContent = false;
|
|
3129
3154
|
this._hasActions = false;
|
|
3130
3155
|
}
|
|
@@ -3134,6 +3159,14 @@ var NLDDInlineDialog = (_NLDDInlineDialog = class NLDDInlineDialog extends LitEl
|
|
|
3134
3159
|
if (this.icon) return this.icon;
|
|
3135
3160
|
return "";
|
|
3136
3161
|
}
|
|
3162
|
+
/** Anything in the default slot is a task (a form, a list) rather than a
|
|
3163
|
+
* message, and a task reads left-aligned. Derived rather than defaulted so
|
|
3164
|
+
* the empty state — the other half of this component — stays centered
|
|
3165
|
+
* without every consumer setting an attribute. */
|
|
3166
|
+
get _resolvedHorizontalAlignment() {
|
|
3167
|
+
if (this.horizontalAlignment) return this.horizontalAlignment;
|
|
3168
|
+
return this._hasContent ? "left" : "center";
|
|
3169
|
+
}
|
|
3137
3170
|
firstUpdated() {
|
|
3138
3171
|
const contentSlot = this.shadowRoot?.querySelector("slot:not([name])");
|
|
3139
3172
|
const actionsSlot = this.shadowRoot?.querySelector("slot[name=\"actions\"]");
|
|
@@ -3188,6 +3221,11 @@ __decorate([property({
|
|
|
3188
3221
|
reflect: true,
|
|
3189
3222
|
attribute: "heading-level"
|
|
3190
3223
|
})], NLDDInlineDialog.prototype, "headingLevel", void 0);
|
|
3224
|
+
__decorate([property({
|
|
3225
|
+
reflect: true,
|
|
3226
|
+
attribute: "horizontal-alignment",
|
|
3227
|
+
converter: reflectNonDefault("")
|
|
3228
|
+
})], NLDDInlineDialog.prototype, "horizontalAlignment", void 0);
|
|
3191
3229
|
__decorate([state()], NLDDInlineDialog.prototype, "_hasContent", void 0);
|
|
3192
3230
|
__decorate([state()], NLDDInlineDialog.prototype, "_hasActions", void 0);
|
|
3193
3231
|
NLDDInlineDialog = __decorate([customElement("nldd-inline-dialog")], NLDDInlineDialog);
|
|
@@ -6379,8 +6417,8 @@ function avatarTemplate(component) {
|
|
|
6379
6417
|
* @element nldd-avatar
|
|
6380
6418
|
*
|
|
6381
6419
|
* @attr {string} type - `person` (circle, person icon) or `organization` (rounded, building icon); default `person`
|
|
6382
|
-
* @attr {string} size - `full` (default) scales with the container, like nldd-icon; or a fixed size in px (spacer-aligned: 16, 20, 24, 28, 32, 40, 44, 48, 56, 64, 80, 96).
|
|
6383
|
-
* @attr {string} color - `
|
|
6420
|
+
* @attr {string} size - `full` (the default) scales with the container, like nldd-icon; or a fixed size in px (spacer-aligned: 16, 20, 24, 28, 32, 40, 44, 48, 56, 64, 80, 96). The initials and the icon scale along
|
|
6421
|
+
* @attr {string} color - `neutral` (the default, a neutral fill) or `inherit` (fill in the content color: the `--context-content-color` channel, or `currentColor` when that is unset; text in the contrast color, so the avatar can replace an icon in a button for instance)
|
|
6384
6422
|
* @attr {boolean} icon-aligned - Shrinks the visible shape to 5/6 of the host, centered, so the avatar aligns optically with an icon on the same grid (an icon glyph has built-in margin)
|
|
6385
6423
|
* @attr {string} name - Name of the person or organization; supplies the derived initials and the accessible label
|
|
6386
6424
|
* @attr {string} initials - Explicit initials, at most 3 characters (overrides what is derived from `name`; also for organization acronyms)
|
|
@@ -6389,7 +6427,7 @@ function avatarTemplate(component) {
|
|
|
6389
6427
|
* @attr {string} icon - Overrides the type-dependent fallback icon
|
|
6390
6428
|
* @attr {string} accessible-label - Name of the link or button; without it `name` is used
|
|
6391
6429
|
* @attr {boolean} decorative - Hides the avatar from assistive software (use when the name already stands beside it as text)
|
|
6392
|
-
* @attr {string} tooltip-timing - When the name appears as a tooltip on hover or focus: `
|
|
6430
|
+
* @attr {string} tooltip-timing - When the name appears as a tooltip on hover or focus: `delay` (the default, after 700ms), `instant`, or `never`. An avatar shows no text, so without a tooltip the name is readable by assistive software only. A `decorative` avatar shows none regardless: there the name already stands beside it as text
|
|
6393
6431
|
* @attr {string} href - Makes the avatar a link to this URL; the shape itself becomes the link, so the hit area and the focus ring follow it
|
|
6394
6432
|
* @attr {boolean} no-tab - Takes the control out of the tab order (tabindex="-1"), for an avatar that is a link or a button inside a roving container (a row of an nldd-list). Does nothing on a decorative avatar.
|
|
6395
6433
|
* @attr {boolean} button - Makes the avatar a button; ignored when `href` is set
|
|
@@ -6416,8 +6454,8 @@ var NLDDAvatar = (_NLDDAvatar = class NLDDAvatar extends withTranslations(LitEle
|
|
|
6416
6454
|
constructor(..._args) {
|
|
6417
6455
|
super(..._args);
|
|
6418
6456
|
this.type = "person";
|
|
6419
|
-
this.size = "";
|
|
6420
|
-
this.color = "
|
|
6457
|
+
this.size = "full";
|
|
6458
|
+
this.color = "neutral";
|
|
6421
6459
|
this.iconAligned = false;
|
|
6422
6460
|
this.name = "";
|
|
6423
6461
|
this.initials = "";
|
|
@@ -6426,7 +6464,7 @@ var NLDDAvatar = (_NLDDAvatar = class NLDDAvatar extends withTranslations(LitEle
|
|
|
6426
6464
|
this.icon = "";
|
|
6427
6465
|
this.accessibleLabel = "";
|
|
6428
6466
|
this.decorative = false;
|
|
6429
|
-
this.tooltipTiming = "
|
|
6467
|
+
this.tooltipTiming = "delay";
|
|
6430
6468
|
this.href = "";
|
|
6431
6469
|
this.noTab = false;
|
|
6432
6470
|
this.button = false;
|
|
@@ -6527,11 +6565,11 @@ __decorate([property({
|
|
|
6527
6565
|
})], NLDDAvatar.prototype, "type", void 0);
|
|
6528
6566
|
__decorate([property({
|
|
6529
6567
|
reflect: true,
|
|
6530
|
-
converter: reflectNonDefault("")
|
|
6568
|
+
converter: reflectNonDefault("full")
|
|
6531
6569
|
})], NLDDAvatar.prototype, "size", void 0);
|
|
6532
6570
|
__decorate([property({
|
|
6533
6571
|
reflect: true,
|
|
6534
|
-
converter: reflectNonDefault("
|
|
6572
|
+
converter: reflectNonDefault("neutral")
|
|
6535
6573
|
})], NLDDAvatar.prototype, "color", void 0);
|
|
6536
6574
|
__decorate([property({
|
|
6537
6575
|
type: Boolean,
|
|
@@ -6554,7 +6592,7 @@ __decorate([property({
|
|
|
6554
6592
|
__decorate([property({
|
|
6555
6593
|
reflect: true,
|
|
6556
6594
|
attribute: "tooltip-timing",
|
|
6557
|
-
converter: reflectNonDefault("
|
|
6595
|
+
converter: reflectNonDefault("delay")
|
|
6558
6596
|
})], NLDDAvatar.prototype, "tooltipTiming", void 0);
|
|
6559
6597
|
__decorate([property({
|
|
6560
6598
|
type: String,
|
|
@@ -9085,7 +9123,7 @@ var NLDDList = (_NLDDList2 = class NLDDList extends LitElement {
|
|
|
9085
9123
|
});
|
|
9086
9124
|
}
|
|
9087
9125
|
_updateEmpty() {
|
|
9088
|
-
const items = this._getItems();
|
|
9126
|
+
const items = this.hasUpdated ? this._getItems() : Array.from(this.querySelectorAll(":scope > nldd-list-item"));
|
|
9089
9127
|
this._isEmpty = items.length === 0 || items.every((item) => item.hasAttribute("hidden"));
|
|
9090
9128
|
this._hasItems = items.length > 0;
|
|
9091
9129
|
this._hasEmptyState = !!this.querySelector(":scope > [slot=\"empty\"]");
|
|
@@ -9100,8 +9138,10 @@ var NLDDList = (_NLDDList2 = class NLDDList extends LitElement {
|
|
|
9100
9138
|
* the app's to write and a house sentence was wrong more often than right.
|
|
9101
9139
|
* That leaves a real risk of a blank area with nothing in the accessibility
|
|
9102
9140
|
* tree either, so the list asks the person building it rather than
|
|
9103
|
-
* answering for them.
|
|
9104
|
-
*
|
|
9141
|
+
* answering for them. It asks about the state it is actually in: rows that
|
|
9142
|
+
* are all hidden are covered by [slot="no-results"] as well as by the
|
|
9143
|
+
* [slot="empty"] it falls back to. A listbox before you have typed is left
|
|
9144
|
+
* alone: an empty search is not an empty list.
|
|
9105
9145
|
*/
|
|
9106
9146
|
_warnSilentEmpty() {}
|
|
9107
9147
|
/** Every option needs a stable id for aria-activedescendant. Assign one to
|
|
@@ -11540,16 +11580,16 @@ var nlddCodeMirrorTheme = [baseTheme, syntaxHighlighting(highlightStyle)];
|
|
|
11540
11580
|
//#endregion
|
|
11541
11581
|
//#region src/utilities/codemirror/languages.ts
|
|
11542
11582
|
var loaders = {
|
|
11543
|
-
json: async () => (await import("./dist-
|
|
11544
|
-
yaml: async () => (await import("./dist-
|
|
11545
|
-
javascript: async () => (await import("./dist-
|
|
11546
|
-
typescript: async () => (await import("./dist-
|
|
11547
|
-
css: async () => (await import("./dist-
|
|
11548
|
-
html: async () => (await import("./dist-
|
|
11549
|
-
xml: async () => (await import("./dist-
|
|
11550
|
-
python: async () => (await import("./dist-
|
|
11551
|
-
rust: async () => (await import("./dist-
|
|
11552
|
-
sql: async () => (await import("./dist-
|
|
11583
|
+
json: async () => (await import("./dist-LX8LuMac.js")).json(),
|
|
11584
|
+
yaml: async () => (await import("./dist-CSrO_mYe.js")).yaml(),
|
|
11585
|
+
javascript: async () => (await import("./dist-ByH8hQze.js").then((n) => n.t)).javascript(),
|
|
11586
|
+
typescript: async () => (await import("./dist-ByH8hQze.js").then((n) => n.t)).javascript({ typescript: true }),
|
|
11587
|
+
css: async () => (await import("./dist-B_Mnmrj4.js").then((n) => n.r)).css(),
|
|
11588
|
+
html: async () => (await import("./dist-CX3DK4i7.js").then((n) => n.t)).html(),
|
|
11589
|
+
xml: async () => (await import("./dist-eVFegyjM.js")).xml(),
|
|
11590
|
+
python: async () => (await import("./dist-CRwuSgMM.js")).python(),
|
|
11591
|
+
rust: async () => (await import("./dist-CbCO0WCd.js")).rust(),
|
|
11592
|
+
sql: async () => (await import("./dist-DXZ-cFAl.js")).sql(),
|
|
11553
11593
|
markdown: async () => (await Promise.resolve().then(() => dist_exports)).markdown(),
|
|
11554
11594
|
bash: async () => new LanguageSupport(StreamLanguage.define((await import("./shell-C61GCsJA.js")).shell)),
|
|
11555
11595
|
toml: async () => new LanguageSupport(StreamLanguage.define((await import("./toml-C2HBbPgG.js")).toml)),
|
|
@@ -12834,11 +12874,12 @@ var nlddRichTextTranslations = { "components.rich-text.table-scroll-label": "Scr
|
|
|
12834
12874
|
* `overflow-wrap: break-word` safety net on p/li is always on, independent of
|
|
12835
12875
|
* this attribute, so long URLs and compounds break neatly instead of
|
|
12836
12876
|
* overflowing even without a dictionary.
|
|
12837
|
-
* @attr {string} color - '
|
|
12838
|
-
*
|
|
12839
|
-
*
|
|
12840
|
-
*
|
|
12841
|
-
*
|
|
12877
|
+
* @attr {string} color - 'content' (the default) takes the system's own content
|
|
12878
|
+
* colors, each element its own. 'inherit' lets all text follow the color of
|
|
12879
|
+
* the surface instead (for colored areas such as the filled categories).
|
|
12880
|
+
* Links stay underlined as an affordance; secondary text (figcaption) gets
|
|
12881
|
+
* the same color at a lowered opacity. Known v1 gaps: inline code, mark,
|
|
12882
|
+
* tables and hr keep their own surfaces.
|
|
12842
12883
|
* @attr {object} translations - Override translation keys; unset keys fall back to Dutch
|
|
12843
12884
|
*/
|
|
12844
12885
|
var MANAGED_LABEL_ATTR = "data-nldd-managed-label";
|
|
@@ -12848,7 +12889,7 @@ var NLDDRichText = class NLDDRichText extends LitElement {
|
|
|
12848
12889
|
this.spacing = "snug";
|
|
12849
12890
|
this.centered = false;
|
|
12850
12891
|
this.hyphens = false;
|
|
12851
|
-
this.color = "";
|
|
12892
|
+
this.color = "content";
|
|
12852
12893
|
this.translations = {};
|
|
12853
12894
|
}
|
|
12854
12895
|
_t(key) {
|
|
@@ -12907,7 +12948,7 @@ __decorate([property({
|
|
|
12907
12948
|
})], NLDDRichText.prototype, "hyphens", void 0);
|
|
12908
12949
|
__decorate([property({
|
|
12909
12950
|
reflect: true,
|
|
12910
|
-
converter: reflectNonDefault("")
|
|
12951
|
+
converter: reflectNonDefault("content")
|
|
12911
12952
|
})], NLDDRichText.prototype, "color", void 0);
|
|
12912
12953
|
__decorate([property({ type: Object })], NLDDRichText.prototype, "translations", void 0);
|
|
12913
12954
|
NLDDRichText = __decorate([customElement("nldd-rich-text")], NLDDRichText);
|
|
@@ -13420,7 +13461,7 @@ function template$10() {
|
|
|
13420
13461
|
* @attr {string} size - Text size on the body scale: 'xxs' | 'xs' | 'sm' | 'md' | 'lg' (default: 'md')
|
|
13421
13462
|
* @attr {string} weight - Font weight: 'regular' | 'medium' | 'bold' (default: 'regular'). With 'bold' a slotted `<strong>` no longer stands out: there is nothing bolder in the scale.
|
|
13422
13463
|
* @attr {string} line-height - Line height: 'flat' | 'tight' | 'snug' | 'loose' (default: 'snug')
|
|
13423
|
-
* @attr {string} color - Text color: '
|
|
13464
|
+
* @attr {string} color - Text color: 'content' (the default) | 'secondary' | 'accent' | 'success' | 'warning' | 'critical' | 'inherit'. 'content' and 'secondary' follow the surrounding content channel; 'inherit' takes the color it inherits, for text on a painted surface.
|
|
13424
13465
|
* @attr {string} horizontal-alignment - Alignment of the text within the block: 'left' | 'center' | 'right' (default: 'left'). Aligns the words; `horizontal-alignment` on nldd-container moves the box.
|
|
13425
13466
|
*
|
|
13426
13467
|
* @slot - The text. Inline elements work as they are: `<strong>` and `<b>` take the bold weight from the scale, `<a>`, `<em>` and components such as `nldd-tag` are left alone.
|
|
@@ -13432,7 +13473,7 @@ var NLDDText = (_NLDDText = class NLDDText extends LitElement {
|
|
|
13432
13473
|
this.size = "md";
|
|
13433
13474
|
this.weight = "regular";
|
|
13434
13475
|
this.lineHeight = "snug";
|
|
13435
|
-
this.color = "
|
|
13476
|
+
this.color = "content";
|
|
13436
13477
|
this.horizontalAlignment = "left";
|
|
13437
13478
|
}
|
|
13438
13479
|
render() {
|
|
@@ -13454,7 +13495,7 @@ __decorate([property({
|
|
|
13454
13495
|
})], NLDDText.prototype, "lineHeight", void 0);
|
|
13455
13496
|
__decorate([property({
|
|
13456
13497
|
reflect: true,
|
|
13457
|
-
converter: reflectNonDefault("
|
|
13498
|
+
converter: reflectNonDefault("content")
|
|
13458
13499
|
})], NLDDText.prototype, "color", void 0);
|
|
13459
13500
|
__decorate([property({
|
|
13460
13501
|
reflect: true,
|
|
@@ -13743,10 +13784,10 @@ function titleTemplate() {
|
|
|
13743
13784
|
* @element nldd-title
|
|
13744
13785
|
*
|
|
13745
13786
|
* @attr {number} size - Visual size of the title: 1–6 (default: 3)
|
|
13746
|
-
* @attr {string} color - '
|
|
13747
|
-
*
|
|
13748
|
-
*
|
|
13749
|
-
*
|
|
13787
|
+
* @attr {string} color - 'content' (the default) takes the system's own content
|
|
13788
|
+
* colors. 'inherit' lets the title follow the text color of the surface
|
|
13789
|
+
* instead (for colored areas such as the filled categories); overline and
|
|
13790
|
+
* subtitle get the same color at a lowered opacity.
|
|
13750
13791
|
*
|
|
13751
13792
|
* @slot overline - Optional overline above the title
|
|
13752
13793
|
* @slot - Title text (use h1–h6 for semantics)
|
|
@@ -13758,7 +13799,7 @@ var NLDDTitle = (_NLDDTitle = class NLDDTitle extends LitElement {
|
|
|
13758
13799
|
constructor(..._args) {
|
|
13759
13800
|
super(..._args);
|
|
13760
13801
|
this.size = 3;
|
|
13761
|
-
this.color = "";
|
|
13802
|
+
this.color = "content";
|
|
13762
13803
|
}
|
|
13763
13804
|
render() {
|
|
13764
13805
|
return titleTemplate();
|
|
@@ -13770,7 +13811,7 @@ __decorate([property({
|
|
|
13770
13811
|
})], NLDDTitle.prototype, "size", void 0);
|
|
13771
13812
|
__decorate([property({
|
|
13772
13813
|
reflect: true,
|
|
13773
|
-
converter: reflectNonDefault("")
|
|
13814
|
+
converter: reflectNonDefault("content")
|
|
13774
13815
|
})], NLDDTitle.prototype, "color", void 0);
|
|
13775
13816
|
NLDDTitle = __decorate([customElement("nldd-title")], NLDDTitle);
|
|
13776
13817
|
//#endregion
|
|
@@ -17834,7 +17875,7 @@ var codeEditorStyles = css`
|
|
|
17834
17875
|
/* # Host */
|
|
17835
17876
|
|
|
17836
17877
|
:host {
|
|
17837
|
-
--
|
|
17878
|
+
--_caret-width: var(--primitives-border-width-regular);
|
|
17838
17879
|
--_corner-radius: 0;
|
|
17839
17880
|
--_background-color: transparent;
|
|
17840
17881
|
--_border-color: transparent;
|
|
@@ -17936,7 +17977,7 @@ var codeEditorStyles = css`
|
|
|
17936
17977
|
CodeMirror's theme cursor color without depending on an attribute. */
|
|
17937
17978
|
:host .cm-cursor.cm-cursor {
|
|
17938
17979
|
border-left-color: var(--primitives-color-accent-600);
|
|
17939
|
-
border-left-width: var(--
|
|
17980
|
+
border-left-width: var(--_caret-width);
|
|
17940
17981
|
}
|
|
17941
17982
|
|
|
17942
17983
|
/* Resize model — rows is the floor in every mode:
|
|
@@ -28668,8 +28709,65 @@ var pasteURLAsLink = /*@__PURE__*/ EditorView.domEventHandlers({ paste: (event,
|
|
|
28668
28709
|
return true;
|
|
28669
28710
|
} });
|
|
28670
28711
|
//#endregion
|
|
28712
|
+
//#region src/components/inputs/text-editor/text-editor.syntax.ts
|
|
28713
|
+
/** The innermost node at `pos` that `match` accepts, looking outward from there.
|
|
28714
|
+
* `side` decides which node a position between two of them belongs to: -1 the
|
|
28715
|
+
* one that ends there, 1 the one that starts there. Null when none matches. */
|
|
28716
|
+
function enclosingNode(state, pos, side, match) {
|
|
28717
|
+
for (let node = syntaxTree(state).resolveInner(pos, side); node; node = node.parent) if (match(node)) return node;
|
|
28718
|
+
return null;
|
|
28719
|
+
}
|
|
28720
|
+
/** `enclosingNode` for the common case: a node that goes by one of these names. */
|
|
28721
|
+
function enclosingNamed(state, pos, side, names) {
|
|
28722
|
+
return enclosingNode(state, pos, side, typeof names === "string" ? (node) => node.name === names : (node) => names.has(node.name));
|
|
28723
|
+
}
|
|
28724
|
+
//#endregion
|
|
28671
28725
|
//#region src/components/inputs/text-editor/text-editor.mentions.ts
|
|
28672
|
-
|
|
28726
|
+
/** The query being typed: a trigger at the start of the line or after
|
|
28727
|
+
* whitespace, followed by name characters, up to the caret. Anchored that way
|
|
28728
|
+
* so a trigger inside a word (an e-mail address, `piet@sam`) stays a plain
|
|
28729
|
+
* character. The name class is ASCII for now; widening it changes what a
|
|
28730
|
+
* source receives and is its own change. */
|
|
28731
|
+
var queryPatterns = /* @__PURE__ */ new Map();
|
|
28732
|
+
function queryPattern(triggers) {
|
|
28733
|
+
const chars = Array.from(new Set(triggers.filter((t) => t.length === 1 && !/[\s\w]/.test(t)))).sort().join("");
|
|
28734
|
+
if (!chars) return null;
|
|
28735
|
+
let pattern = queryPatterns.get(chars);
|
|
28736
|
+
if (!pattern) {
|
|
28737
|
+
pattern = new RegExp(`(^|\\s)([${chars.replace(/[\\\]^-]/g, "\\$&")}])([\\w.-]*)$`);
|
|
28738
|
+
queryPatterns.set(chars, pattern);
|
|
28739
|
+
}
|
|
28740
|
+
return pattern;
|
|
28741
|
+
}
|
|
28742
|
+
/** Code is quoted verbatim, so a trigger in a fenced block, an indented block
|
|
28743
|
+
* or a backtick span is not a typeahead and must not open the list. */
|
|
28744
|
+
var CODE_NODES = /* @__PURE__ */ new Set([
|
|
28745
|
+
"FencedCode",
|
|
28746
|
+
"CodeBlock",
|
|
28747
|
+
"InlineCode"
|
|
28748
|
+
]);
|
|
28749
|
+
function inCode(state, pos) {
|
|
28750
|
+
return enclosingNamed(state, pos, 1, CODE_NODES) !== null;
|
|
28751
|
+
}
|
|
28752
|
+
/** The typeahead query at `pos` for one of `triggers`, or null when the text
|
|
28753
|
+
* before the caret is not one. `from` is the trigger, `query` the typed text
|
|
28754
|
+
* without it. Both the completion source and the reopen-on-delete path go
|
|
28755
|
+
* through this, so they cannot disagree about what counts as a query. */
|
|
28756
|
+
function typeaheadQueryAt(state, pos, triggers) {
|
|
28757
|
+
const pattern = queryPattern(triggers);
|
|
28758
|
+
if (!pattern) return null;
|
|
28759
|
+
const line = state.doc.lineAt(pos);
|
|
28760
|
+
const match = pattern.exec(state.sliceDoc(line.from, pos));
|
|
28761
|
+
if (!match) return null;
|
|
28762
|
+
const from = line.from + match.index + match[1].length;
|
|
28763
|
+
if (inCode(state, from)) return null;
|
|
28764
|
+
return {
|
|
28765
|
+
from,
|
|
28766
|
+
to: pos,
|
|
28767
|
+
query: match[3],
|
|
28768
|
+
trigger: match[2]
|
|
28769
|
+
};
|
|
28770
|
+
}
|
|
28673
28771
|
/** Href prefix that marks a markdown link as a mention. */
|
|
28674
28772
|
var MENTION_HREF_PREFIX = "user:";
|
|
28675
28773
|
/** The markdown-compatible token stored for a mention (degrades to a plain link).
|
|
@@ -28679,7 +28777,11 @@ var MENTION_HREF_PREFIX = "user:";
|
|
|
28679
28777
|
* `]` or `)` would otherwise start a second, attacker-shaped link. The render
|
|
28680
28778
|
* layer reverses both via `unescapeMentionLabel` / `decodeMentionId`. */
|
|
28681
28779
|
function mentionToken(candidate) {
|
|
28682
|
-
return `[@${candidate.
|
|
28780
|
+
return `[@${candidate.text.replace(/[[\]\\]/g, (c) => "\\" + c)}](${MENTION_HREF_PREFIX}${encodeURIComponent(candidate.id).replace(/[()<>]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase())})`;
|
|
28781
|
+
}
|
|
28782
|
+
/** What the built-in mention writes: the token and a space to go on typing. */
|
|
28783
|
+
function mentionInsert(candidate) {
|
|
28784
|
+
return `${mentionToken(candidate)} `;
|
|
28683
28785
|
}
|
|
28684
28786
|
/** Reverse `mentionToken`'s label escaping for display. */
|
|
28685
28787
|
function unescapeMentionLabel(label) {
|
|
@@ -28694,38 +28796,86 @@ function decodeMentionId(id) {
|
|
|
28694
28796
|
return id;
|
|
28695
28797
|
}
|
|
28696
28798
|
}
|
|
28697
|
-
function
|
|
28799
|
+
function defaultInsert(trigger) {
|
|
28800
|
+
return (candidate) => `${trigger}${candidate.text} `;
|
|
28801
|
+
}
|
|
28802
|
+
/** The avatar, icon or symbol in front of a row, or nothing. A decorative
|
|
28803
|
+
* avatar: the name stands beside it as the row's text. The icon is the size of
|
|
28804
|
+
* a menu item's, and the symbol takes the same box, so a list that mixes them
|
|
28805
|
+
* lines up. */
|
|
28806
|
+
function renderLead(completion) {
|
|
28807
|
+
const { candidate } = completion;
|
|
28808
|
+
if (candidate.avatar) {
|
|
28809
|
+
const avatar = document.createElement("nldd-avatar");
|
|
28810
|
+
avatar.setAttribute("name", candidate.text);
|
|
28811
|
+
avatar.setAttribute("size", "32");
|
|
28812
|
+
avatar.setAttribute("decorative", "");
|
|
28813
|
+
if (candidate.avatar.src) avatar.setAttribute("src", candidate.avatar.src);
|
|
28814
|
+
if (candidate.avatar.type) avatar.setAttribute("type", candidate.avatar.type);
|
|
28815
|
+
return avatar;
|
|
28816
|
+
}
|
|
28817
|
+
if (candidate.icon) {
|
|
28818
|
+
const icon = document.createElement("nldd-icon");
|
|
28819
|
+
icon.setAttribute("name", candidate.icon);
|
|
28820
|
+
icon.setAttribute("size", "20");
|
|
28821
|
+
icon.setAttribute("aria-hidden", "true");
|
|
28822
|
+
return icon;
|
|
28823
|
+
}
|
|
28824
|
+
if (candidate.symbol) {
|
|
28825
|
+
const symbol = document.createElement("span");
|
|
28826
|
+
symbol.className = "cm-nldd-symbol";
|
|
28827
|
+
symbol.textContent = candidate.symbol;
|
|
28828
|
+
symbol.setAttribute("aria-hidden", "true");
|
|
28829
|
+
return symbol;
|
|
28830
|
+
}
|
|
28831
|
+
return null;
|
|
28832
|
+
}
|
|
28833
|
+
/** A row with an avatar takes two lines: the text above, the supporting text
|
|
28834
|
+
* under it, like a title cell. */
|
|
28835
|
+
function rowClass(completion) {
|
|
28836
|
+
return completion.candidate.avatar ? "cm-nldd-row-avatar" : "";
|
|
28837
|
+
}
|
|
28838
|
+
function completionSource(getTypeaheads, onChoose) {
|
|
28698
28839
|
return async (context) => {
|
|
28699
|
-
const
|
|
28700
|
-
|
|
28701
|
-
|
|
28702
|
-
|
|
28703
|
-
const
|
|
28704
|
-
|
|
28705
|
-
|
|
28706
|
-
|
|
28707
|
-
|
|
28708
|
-
|
|
28709
|
-
label:
|
|
28710
|
-
detail: candidate.
|
|
28840
|
+
const lists = getTypeaheads();
|
|
28841
|
+
const match = typeaheadQueryAt(context.state, context.pos, lists.map((t) => t.trigger));
|
|
28842
|
+
if (!match) return null;
|
|
28843
|
+
const onTrigger = lists.filter((t) => t.trigger === match.trigger);
|
|
28844
|
+
const results = await Promise.all(onTrigger.map((t) => t.source(match.query)));
|
|
28845
|
+
const options = [];
|
|
28846
|
+
results.forEach((candidates, index) => {
|
|
28847
|
+
const typeahead = onTrigger[index];
|
|
28848
|
+
const insert = typeahead.insert ?? defaultInsert(match.trigger);
|
|
28849
|
+
for (const candidate of candidates ?? []) options.push({
|
|
28850
|
+
label: `${match.trigger}${candidate.text}`,
|
|
28851
|
+
detail: candidate.supportingText,
|
|
28852
|
+
candidate,
|
|
28711
28853
|
apply: (view, _completion, from, to) => {
|
|
28712
|
-
const
|
|
28854
|
+
const text = insert(candidate);
|
|
28713
28855
|
view.dispatch({
|
|
28714
28856
|
changes: {
|
|
28715
28857
|
from,
|
|
28716
28858
|
to,
|
|
28717
|
-
insert:
|
|
28859
|
+
insert: text
|
|
28718
28860
|
},
|
|
28719
|
-
selection: { anchor: from +
|
|
28861
|
+
selection: { anchor: from + text.length },
|
|
28862
|
+
userEvent: "input.complete"
|
|
28720
28863
|
});
|
|
28721
|
-
|
|
28722
|
-
|
|
28723
|
-
|
|
28864
|
+
onChoose({
|
|
28865
|
+
typeahead,
|
|
28866
|
+
trigger: match.trigger,
|
|
28867
|
+
candidate,
|
|
28724
28868
|
from,
|
|
28725
|
-
to: from +
|
|
28869
|
+
to: from + text.length
|
|
28726
28870
|
});
|
|
28727
28871
|
}
|
|
28728
|
-
})
|
|
28872
|
+
});
|
|
28873
|
+
});
|
|
28874
|
+
if (!options.length) return null;
|
|
28875
|
+
return {
|
|
28876
|
+
from: match.from,
|
|
28877
|
+
filter: false,
|
|
28878
|
+
options
|
|
28729
28879
|
};
|
|
28730
28880
|
};
|
|
28731
28881
|
}
|
|
@@ -28739,6 +28889,8 @@ var popupTheme = EditorView.theme({
|
|
|
28739
28889
|
".cm-tooltip.cm-tooltip-autocomplete > ul": {
|
|
28740
28890
|
fontFamily: "var(--primitives-font-family-body)",
|
|
28741
28891
|
fontSize: "var(--primitives-font-size-100)",
|
|
28892
|
+
minWidth: "var(--primitives-area-280)",
|
|
28893
|
+
boxSizing: "border-box",
|
|
28742
28894
|
maxHeight: "14em",
|
|
28743
28895
|
margin: "0",
|
|
28744
28896
|
padding: "var(--primitives-space-8)"
|
|
@@ -28754,6 +28906,32 @@ var popupTheme = EditorView.theme({
|
|
|
28754
28906
|
color: "var(--semantics-content-color)",
|
|
28755
28907
|
cursor: "default"
|
|
28756
28908
|
},
|
|
28909
|
+
".cm-tooltip.cm-tooltip-autocomplete > ul > li > :is(nldd-avatar, nldd-icon, .cm-nldd-symbol)": { flex: "none" },
|
|
28910
|
+
".cm-nldd-symbol": {
|
|
28911
|
+
display: "inline-flex",
|
|
28912
|
+
justifyContent: "center",
|
|
28913
|
+
inlineSize: "20px"
|
|
28914
|
+
},
|
|
28915
|
+
".cm-tooltip.cm-tooltip-autocomplete > ul > li.cm-nldd-row-avatar": {
|
|
28916
|
+
display: "grid",
|
|
28917
|
+
gridTemplateColumns: "auto minmax(0, 1fr)",
|
|
28918
|
+
alignContent: "center",
|
|
28919
|
+
rowGap: "0",
|
|
28920
|
+
minHeight: "var(--semantics-controls-md-min-size)"
|
|
28921
|
+
},
|
|
28922
|
+
".cm-tooltip.cm-tooltip-autocomplete > ul > li.cm-nldd-row-avatar > nldd-avatar": {
|
|
28923
|
+
gridRow: "span 2",
|
|
28924
|
+
alignSelf: "center"
|
|
28925
|
+
},
|
|
28926
|
+
".cm-tooltip.cm-tooltip-autocomplete > ul > li.cm-nldd-row-avatar > .cm-completionLabel": {
|
|
28927
|
+
gridColumn: "2",
|
|
28928
|
+
font: "var(--primitives-font-body-md-regular-tight)"
|
|
28929
|
+
},
|
|
28930
|
+
".cm-tooltip.cm-tooltip-autocomplete > ul > li.cm-nldd-row-avatar > .cm-completionDetail": {
|
|
28931
|
+
gridColumn: "2",
|
|
28932
|
+
marginLeft: "0",
|
|
28933
|
+
font: "var(--primitives-font-body-sm-regular-tight)"
|
|
28934
|
+
},
|
|
28757
28935
|
".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {
|
|
28758
28936
|
backgroundColor: "var(--components-menu-item-is-highlighted-background-color)",
|
|
28759
28937
|
color: "var(--components-menu-item-is-highlighted-content-color)"
|
|
@@ -28771,22 +28949,26 @@ var popupTheme = EditorView.theme({
|
|
|
28771
28949
|
"@media (pointer: coarse)": { ".cm-tooltip.cm-tooltip-autocomplete > ul > li": { minHeight: "var(--semantics-controls-md-min-size)" } }
|
|
28772
28950
|
});
|
|
28773
28951
|
/**
|
|
28774
|
-
*
|
|
28775
|
-
*
|
|
28776
|
-
* `
|
|
28952
|
+
* The typeaheads. `getTypeaheads` is read on every keystroke, so the editor can
|
|
28953
|
+
* hand over its current lists; choosing a candidate writes what the list's
|
|
28954
|
+
* `insert` says and calls `onChoose`. Without lists it is inert.
|
|
28777
28955
|
*/
|
|
28778
|
-
|
|
28779
|
-
|
|
28780
|
-
|
|
28781
|
-
|
|
28782
|
-
|
|
28783
|
-
|
|
28784
|
-
});
|
|
28785
|
-
function mentions(getSource, onInsert) {
|
|
28956
|
+
function typeaheads(getTypeaheads, onChoose) {
|
|
28957
|
+
const reopenOnDelete = EditorView.updateListener.of((update) => {
|
|
28958
|
+
if (!update.docChanged || completionStatus(update.state) !== null) return;
|
|
28959
|
+
if (!update.transactions.some((tr) => tr.isUserEvent("delete"))) return;
|
|
28960
|
+
const triggers = getTypeaheads().map((t) => t.trigger);
|
|
28961
|
+
if (typeaheadQueryAt(update.state, update.state.selection.main.head, triggers)) startCompletion(update.view);
|
|
28962
|
+
});
|
|
28786
28963
|
return [
|
|
28787
28964
|
autocompletion({
|
|
28788
|
-
override: [completionSource(
|
|
28789
|
-
icons: false
|
|
28965
|
+
override: [completionSource(getTypeaheads, onChoose)],
|
|
28966
|
+
icons: false,
|
|
28967
|
+
addToOptions: [{
|
|
28968
|
+
position: 20,
|
|
28969
|
+
render: renderLead
|
|
28970
|
+
}],
|
|
28971
|
+
optionClass: rowClass
|
|
28790
28972
|
}),
|
|
28791
28973
|
reopenOnDelete,
|
|
28792
28974
|
popupTheme
|
|
@@ -28845,15 +29027,22 @@ var LinkOpenWidget = class extends WidgetType {
|
|
|
28845
29027
|
ignoreEvent() {
|
|
28846
29028
|
return true;
|
|
28847
29029
|
}
|
|
28848
|
-
/**
|
|
28849
|
-
*
|
|
28850
|
-
|
|
29030
|
+
/** The caret at the link's end has two places to be, and `side` says which: on
|
|
29031
|
+
* the link's side of the badge, or after the badge. Both at text height, not
|
|
29032
|
+
* the badge's own box (taller, and it would flip with the arrival direction).
|
|
29033
|
+
* The cursor layer treats the badge as a character with a stop on either
|
|
29034
|
+
* side, whether the link is a bare URL (text typed on the link's side extends
|
|
29035
|
+
* it) or a `[text](url)` link (text typed there lands after the link, and
|
|
29036
|
+
* so after its badge). Ignoring `side` drew both after the badge, so deleting
|
|
29037
|
+
* the last character of a URL looked like editing outside it. */
|
|
29038
|
+
coordsAt(dom, _pos, side) {
|
|
28851
29039
|
const badge = dom.getBoundingClientRect();
|
|
28852
29040
|
const box = textCaretBox(dom) ?? {
|
|
28853
29041
|
top: badge.top,
|
|
28854
29042
|
bottom: badge.bottom
|
|
28855
29043
|
};
|
|
28856
|
-
const
|
|
29044
|
+
const cs = getComputedStyle(dom);
|
|
29045
|
+
const x = side < 0 ? badge.left - parseFloat(cs.marginLeft) : badge.right + parseFloat(cs.marginRight);
|
|
28857
29046
|
return {
|
|
28858
29047
|
left: x,
|
|
28859
29048
|
right: x,
|
|
@@ -28973,6 +29162,243 @@ function linkOpenBadge(label) {
|
|
|
28973
29162
|
}
|
|
28974
29163
|
}, { decorations: (plugin) => plugin.decorations });
|
|
28975
29164
|
}
|
|
29165
|
+
/** Whether a link with a badge ends at `pos`: a `[text](url)` link or a bare
|
|
29166
|
+
* URL, with a destination the badge accepts. The same tests as `buildBadges`,
|
|
29167
|
+
* so a mention (a link too, but without a badge) is not one. */
|
|
29168
|
+
function linkEndsAt(state, pos) {
|
|
29169
|
+
let refs = null;
|
|
29170
|
+
return enclosingNode(state, pos, -1, (node) => {
|
|
29171
|
+
if (node.to !== pos) return false;
|
|
29172
|
+
if (node.name === "Link") return hrefOf(state, node, refs ?? (refs = referenceDefs(state))) !== null;
|
|
29173
|
+
return node.name === "URL" && !inLinkContext(node) && bareHref(state, node) !== null;
|
|
29174
|
+
}) !== null;
|
|
29175
|
+
}
|
|
29176
|
+
/** Whether a bare URL with a badge ends at `pos`: the link that text typed at
|
|
29177
|
+
* its end extends, unlike a `[text](url)` link, which ends at its `)`. */
|
|
29178
|
+
function bareUrlEndsAt(state, pos) {
|
|
29179
|
+
return enclosingNode(state, pos, -1, (node) => node.name === "URL" && node.to === pos && !inLinkContext(node) && bareHref(state, node) !== null) !== null;
|
|
29180
|
+
}
|
|
29181
|
+
//#endregion
|
|
29182
|
+
//#region src/components/inputs/text-editor/text-editor.emphasis.ts
|
|
29183
|
+
/** The emphasis nodes that live by the flanking rules, with the marker the
|
|
29184
|
+
* editor writes for them. Inline code is not among them: a code span keeps its
|
|
29185
|
+
* whitespace and never fails to close. */
|
|
29186
|
+
var EMPHASIS_MARKERS = /* @__PURE__ */ new Map([
|
|
29187
|
+
["StrongEmphasis", "**"],
|
|
29188
|
+
["Emphasis", "*"],
|
|
29189
|
+
["Strikethrough", "~~"]
|
|
29190
|
+
]);
|
|
29191
|
+
/** The blocks that hold inline content. A held emphasis must stay within one:
|
|
29192
|
+
* a paragraph break inside it (Enter twice) ends the run for good. */
|
|
29193
|
+
var INLINE_BLOCKS = /* @__PURE__ */ new Set([
|
|
29194
|
+
"Paragraph",
|
|
29195
|
+
"ATXHeading1",
|
|
29196
|
+
"ATXHeading2",
|
|
29197
|
+
"ATXHeading3",
|
|
29198
|
+
"ATXHeading4",
|
|
29199
|
+
"ATXHeading5",
|
|
29200
|
+
"ATXHeading6",
|
|
29201
|
+
"SetextHeading1",
|
|
29202
|
+
"SetextHeading2",
|
|
29203
|
+
"TableCell"
|
|
29204
|
+
]);
|
|
29205
|
+
/** What may sit between the end of a run's text and its closing marker for the
|
|
29206
|
+
* marker to be moved back to the text: whitespace, and after a line break the
|
|
29207
|
+
* scaffolding Enter writes for the next list item, task or quote line. Text
|
|
29208
|
+
* there means the break fell inside the run, and that is left alone. */
|
|
29209
|
+
var TRAIL_RE = /^\s*(?:\n\s*(?:(?:[-*+]|\d+[.)]|>|\[[ xX]\])\s*)*)*$/;
|
|
29210
|
+
/** Starts a hold on markers just written around an empty selection: `****`
|
|
29211
|
+
* parses as nothing, so there is no node to remember, but what is typed
|
|
29212
|
+
* between them is meant to be bold. */
|
|
29213
|
+
var holdEmphasis = StateEffect.define({ map: (value, mapping) => ({
|
|
29214
|
+
...value,
|
|
29215
|
+
from: mapping.mapPos(value.from, 1),
|
|
29216
|
+
to: mapping.mapPos(value.to, -1)
|
|
29217
|
+
}) });
|
|
29218
|
+
function emphasisAround(state, pos, side) {
|
|
29219
|
+
return enclosingNode(state, pos, side, (node) => EMPHASIS_MARKERS.has(node.name));
|
|
29220
|
+
}
|
|
29221
|
+
function inlineBlockAt(state, pos) {
|
|
29222
|
+
return enclosingNamed(state, pos, 1, INLINE_BLOCKS);
|
|
29223
|
+
}
|
|
29224
|
+
/** The innermost emphasis the main selection is inside of on both of its sides,
|
|
29225
|
+
* as the tree parses it now. Just before the opening marker or just after the
|
|
29226
|
+
* closing one is outside: text typed there lands outside the emphasis. */
|
|
29227
|
+
function liveEmphasis(state) {
|
|
29228
|
+
const { from, to } = state.selection.main;
|
|
29229
|
+
const left = emphasisAround(state, from, -1);
|
|
29230
|
+
const right = left && emphasisAround(state, to, 1);
|
|
29231
|
+
if (!left || !right || left.from !== right.from || left.to !== right.to) return null;
|
|
29232
|
+
const len = EMPHASIS_MARKERS.get(left.name).length;
|
|
29233
|
+
return {
|
|
29234
|
+
from: left.from,
|
|
29235
|
+
to: left.to,
|
|
29236
|
+
name: left.name,
|
|
29237
|
+
marker: state.sliceDoc(left.from, left.from + len),
|
|
29238
|
+
live: true
|
|
29239
|
+
};
|
|
29240
|
+
}
|
|
29241
|
+
/** Whether a remembered emphasis is still worth holding: the selection is between
|
|
29242
|
+
* its markers, both markers are still there, no paragraph break cut it, and
|
|
29243
|
+
* the parser has not made something else of its start. (Typing `**` inside
|
|
29244
|
+
* bold splits it, and then the tree's own reading should show.) */
|
|
29245
|
+
function holds(state, held) {
|
|
29246
|
+
const len = held.marker.length;
|
|
29247
|
+
const { from, to } = state.selection.main;
|
|
29248
|
+
if (from < held.from + len || to > held.to - len) return false;
|
|
29249
|
+
const text = state.sliceDoc(held.from, held.to);
|
|
29250
|
+
if (text.length < 2 * len || !text.startsWith(held.marker) || !text.endsWith(held.marker)) return false;
|
|
29251
|
+
const block = inlineBlockAt(state, held.from);
|
|
29252
|
+
if (!block || block.to < held.to) return false;
|
|
29253
|
+
const parsed = emphasisAround(state, held.from, 1);
|
|
29254
|
+
return !(parsed && parsed.name === held.name && parsed.from === held.from);
|
|
29255
|
+
}
|
|
29256
|
+
function mapHeld(held, through) {
|
|
29257
|
+
return {
|
|
29258
|
+
...held,
|
|
29259
|
+
from: through.changes.mapPos(held.from, 1),
|
|
29260
|
+
to: through.changes.mapPos(held.to, -1)
|
|
29261
|
+
};
|
|
29262
|
+
}
|
|
29263
|
+
/** The emphasis the caret is in: the tree's own while it parses, and the held
|
|
29264
|
+
* one, mapped along through edits, once it does not. Null outside any. */
|
|
29265
|
+
var heldEmphasisField = StateField.define({
|
|
29266
|
+
create: (state) => liveEmphasis(state),
|
|
29267
|
+
update(prev, tr) {
|
|
29268
|
+
if (prev) {
|
|
29269
|
+
const held = mapHeld({
|
|
29270
|
+
...prev,
|
|
29271
|
+
live: false
|
|
29272
|
+
}, tr);
|
|
29273
|
+
if (holds(tr.state, held)) return held;
|
|
29274
|
+
}
|
|
29275
|
+
const live = liveEmphasis(tr.state);
|
|
29276
|
+
if (live) return live;
|
|
29277
|
+
const seed = tr.effects.find((effect) => effect.is(holdEmphasis));
|
|
29278
|
+
return seed ? {
|
|
29279
|
+
...seed.value,
|
|
29280
|
+
live: false
|
|
29281
|
+
} : null;
|
|
29282
|
+
}
|
|
29283
|
+
});
|
|
29284
|
+
/** The whitespace at the inside edges of `held`, or null when there is nothing
|
|
29285
|
+
* to move: no whitespace at the edges, nothing but whitespace inside, or the
|
|
29286
|
+
* markers are gone. The text ends where the opening block's text does: past
|
|
29287
|
+
* a paragraph break the rest of the run can never be inside the emphasis, so
|
|
29288
|
+
* it counts as trail, provided it is scaffolding and not text. */
|
|
29289
|
+
function repairFor(state, held) {
|
|
29290
|
+
const len = held.marker.length;
|
|
29291
|
+
const text = state.sliceDoc(held.from, held.to);
|
|
29292
|
+
if (text.length < 2 * len || !text.startsWith(held.marker) || !text.endsWith(held.marker)) return null;
|
|
29293
|
+
const inner = text.slice(len, text.length - len);
|
|
29294
|
+
const lead = /^\s*/.exec(inner)[0].length;
|
|
29295
|
+
const block = inlineBlockAt(state, held.from);
|
|
29296
|
+
const inBlock = state.sliceDoc(held.from + len, Math.min(held.to - len, block ? block.to : held.to - len));
|
|
29297
|
+
const contentEnd = held.from + len + inBlock.replace(/\s+$/, "").length;
|
|
29298
|
+
if (contentEnd <= held.from + len + lead) return null;
|
|
29299
|
+
const trail = held.to - len - contentEnd;
|
|
29300
|
+
if (!lead && !trail) return null;
|
|
29301
|
+
if (!TRAIL_RE.test(state.sliceDoc(contentEnd, held.to - len))) return null;
|
|
29302
|
+
return {
|
|
29303
|
+
from: held.from,
|
|
29304
|
+
to: held.to,
|
|
29305
|
+
len,
|
|
29306
|
+
lead,
|
|
29307
|
+
trail
|
|
29308
|
+
};
|
|
29309
|
+
}
|
|
29310
|
+
/** Moves the lead in front of the opening marker and the trail past the closing
|
|
29311
|
+
* one. Moving the whitespace rather than the markers keeps an annotation on
|
|
29312
|
+
* the text on the text. */
|
|
29313
|
+
function repairChanges(state, r) {
|
|
29314
|
+
const changes = [];
|
|
29315
|
+
if (r.lead) changes.push({
|
|
29316
|
+
from: r.from,
|
|
29317
|
+
insert: state.sliceDoc(r.from + r.len, r.from + r.len + r.lead)
|
|
29318
|
+
}, {
|
|
29319
|
+
from: r.from + r.len,
|
|
29320
|
+
to: r.from + r.len + r.lead
|
|
29321
|
+
});
|
|
29322
|
+
if (r.trail) changes.push({
|
|
29323
|
+
from: r.to - r.len - r.trail,
|
|
29324
|
+
to: r.to - r.len
|
|
29325
|
+
}, {
|
|
29326
|
+
from: r.to,
|
|
29327
|
+
insert: state.sliceDoc(r.to - r.len - r.trail, r.to - r.len)
|
|
29328
|
+
});
|
|
29329
|
+
return changes;
|
|
29330
|
+
}
|
|
29331
|
+
/** Where a position lands after the repair. The markers and the whitespace swap
|
|
29332
|
+
* places, and a caret in the whitespace goes with it past the marker: after
|
|
29333
|
+
* the space it typed, outside the run. With `stay` it stays with the text,
|
|
29334
|
+
* inside the markers. That is what a blur wants: a toolbar click blurs the
|
|
29335
|
+
* editor before its command runs, and the command must find the caret where
|
|
29336
|
+
* the typing was. */
|
|
29337
|
+
function mapRepair(pos, r, stay) {
|
|
29338
|
+
const contentStart = r.from + r.len + r.lead;
|
|
29339
|
+
const contentEnd = r.to - r.len - r.trail;
|
|
29340
|
+
if (r.lead) {
|
|
29341
|
+
if (pos > r.from && pos < r.from + r.len) return pos + r.lead;
|
|
29342
|
+
if (pos >= r.from + r.len && pos < contentStart) return stay ? contentStart : pos - r.len;
|
|
29343
|
+
}
|
|
29344
|
+
if (r.trail) {
|
|
29345
|
+
if (pos > contentEnd && pos <= r.to - r.len) return stay ? contentEnd : pos + r.len;
|
|
29346
|
+
if (pos > r.to - r.len && pos < r.to) return pos - r.trail;
|
|
29347
|
+
}
|
|
29348
|
+
return pos;
|
|
29349
|
+
}
|
|
29350
|
+
function repairSpec(state, held, stay) {
|
|
29351
|
+
const r = repairFor(state, held);
|
|
29352
|
+
if (!r) return null;
|
|
29353
|
+
const sel = state.selection;
|
|
29354
|
+
return {
|
|
29355
|
+
changes: repairChanges(state, r),
|
|
29356
|
+
selection: EditorSelection.create(sel.ranges.map((range) => EditorSelection.range(mapRepair(range.anchor, r, stay), mapRepair(range.head, r, stay))), sel.mainIndex),
|
|
29357
|
+
userEvent: "input.emphasis"
|
|
29358
|
+
};
|
|
29359
|
+
}
|
|
29360
|
+
/** The changes that move edge whitespace out of `held`, for a command that
|
|
29361
|
+
* steps out of the run itself. Empty when there is nothing to move. */
|
|
29362
|
+
function repairChangesFor(state, held) {
|
|
29363
|
+
const r = repairFor(state, held);
|
|
29364
|
+
return r ? repairChanges(state, r) : [];
|
|
29365
|
+
}
|
|
29366
|
+
/** Ends a hold at once, for a blur. The display must be right while the editor
|
|
29367
|
+
* is unfocused, and the value it commits must be markdown that renders the way
|
|
29368
|
+
* it looked. */
|
|
29369
|
+
function repairHeldEmphasis(view) {
|
|
29370
|
+
const held = view.state.field(heldEmphasisField, false);
|
|
29371
|
+
if (!held || held.live || view.state.readOnly) return;
|
|
29372
|
+
const spec = repairSpec(view.state, held, true);
|
|
29373
|
+
if (spec) view.dispatch(spec);
|
|
29374
|
+
}
|
|
29375
|
+
var heldEmphasis = [heldEmphasisField, ViewPlugin.fromClass(class {
|
|
29376
|
+
constructor(view) {
|
|
29377
|
+
this.view = view;
|
|
29378
|
+
this.pending = null;
|
|
29379
|
+
this.destroyed = false;
|
|
29380
|
+
}
|
|
29381
|
+
update(update) {
|
|
29382
|
+
if (this.pending) this.pending = mapHeld(this.pending, update);
|
|
29383
|
+
const before = update.startState.field(heldEmphasisField);
|
|
29384
|
+
if (!before) return;
|
|
29385
|
+
const gone = mapHeld(before, update);
|
|
29386
|
+
const after = update.state.field(heldEmphasisField);
|
|
29387
|
+
if (after && after.name === gone.name && after.from === gone.from && after.to === gone.to) return;
|
|
29388
|
+
this.pending = gone;
|
|
29389
|
+
queueMicrotask(() => this.flush());
|
|
29390
|
+
}
|
|
29391
|
+
flush() {
|
|
29392
|
+
const held = this.pending;
|
|
29393
|
+
this.pending = null;
|
|
29394
|
+
if (!held || this.destroyed || this.view.state.readOnly) return;
|
|
29395
|
+
const spec = repairSpec(this.view.state, held, false);
|
|
29396
|
+
if (spec) this.view.dispatch(spec);
|
|
29397
|
+
}
|
|
29398
|
+
destroy() {
|
|
29399
|
+
this.destroyed = true;
|
|
29400
|
+
}
|
|
29401
|
+
})];
|
|
28976
29402
|
//#endregion
|
|
28977
29403
|
//#region src/components/inputs/text-editor/text-editor.markdown.ts
|
|
28978
29404
|
var NODE_CLASS = {
|
|
@@ -29105,6 +29531,12 @@ function buildMarkDecorations(view) {
|
|
|
29105
29531
|
else if (MARK_NODES.has(node.name)) ranges.push(dimDeco.range(node.from, node.to));
|
|
29106
29532
|
}
|
|
29107
29533
|
});
|
|
29534
|
+
const held = view.state.field(heldEmphasisField, false);
|
|
29535
|
+
if (held && !held.live) {
|
|
29536
|
+
const len = held.marker.length;
|
|
29537
|
+
ranges.push(classDeco(NODE_CLASS[held.name]).range(held.from, held.to));
|
|
29538
|
+
ranges.push(dimDeco.range(held.from, held.from + len), dimDeco.range(held.to - len, held.to));
|
|
29539
|
+
}
|
|
29108
29540
|
return Decoration.set(ranges, true);
|
|
29109
29541
|
}
|
|
29110
29542
|
var markDecorationPlugin = ViewPlugin.fromClass(class {
|
|
@@ -29123,20 +29555,22 @@ function hangingLineDeco(length) {
|
|
|
29123
29555
|
}
|
|
29124
29556
|
/** Whether `pos` sits inside a fenced or indented code block — where a leading
|
|
29125
29557
|
* `-`/`1.`/`>` is literal code, not a list or quote marker. */
|
|
29558
|
+
var CODE_BLOCK_NODES = /* @__PURE__ */ new Set(["FencedCode", "CodeBlock"]);
|
|
29126
29559
|
function inCodeBlock(state, pos) {
|
|
29127
|
-
|
|
29128
|
-
return false;
|
|
29560
|
+
return enclosingNamed(state, pos, 1, CODE_BLOCK_NODES) !== null;
|
|
29129
29561
|
}
|
|
29130
29562
|
function buildHangingIndent(state) {
|
|
29131
29563
|
const ranges = [];
|
|
29132
|
-
|
|
29133
|
-
|
|
29134
|
-
const
|
|
29135
|
-
|
|
29564
|
+
let from = 0;
|
|
29565
|
+
for (const iter = state.doc.iterLines(); !iter.next().done;) {
|
|
29566
|
+
const text = iter.value;
|
|
29567
|
+
const match = HANGING_RE.exec(text);
|
|
29568
|
+
if (match && match[1].length && !inCodeBlock(state, from)) {
|
|
29136
29569
|
const length = match[1].length;
|
|
29137
|
-
ranges.push(hangingLineDeco(length).range(
|
|
29138
|
-
ranges.push(prefixMonoDeco.range(
|
|
29570
|
+
ranges.push(hangingLineDeco(length).range(from));
|
|
29571
|
+
ranges.push(prefixMonoDeco.range(from, from + length));
|
|
29139
29572
|
}
|
|
29573
|
+
from += text.length + 1;
|
|
29140
29574
|
}
|
|
29141
29575
|
return Decoration.set(ranges, true);
|
|
29142
29576
|
}
|
|
@@ -29191,9 +29625,28 @@ function buildMentionChips(state) {
|
|
|
29191
29625
|
} });
|
|
29192
29626
|
return Decoration.set(ranges, true);
|
|
29193
29627
|
}
|
|
29628
|
+
/** Whether moving the selection from `before` to `after` changes which mention a
|
|
29629
|
+
* selection covers. Only then is the chip set worth rebuilding: walking the
|
|
29630
|
+
* whole syntax tree on every arrow key, to find that nothing looks different,
|
|
29631
|
+
* is the expensive way to do nothing. */
|
|
29632
|
+
function coverageChanged(chips, before, after) {
|
|
29633
|
+
let changed = false;
|
|
29634
|
+
chips.between(0, 1e9, (from, to) => {
|
|
29635
|
+
const covers = (sel) => sel.from !== sel.to && sel.from <= from && sel.to >= to;
|
|
29636
|
+
if (covers(before) !== covers(after)) {
|
|
29637
|
+
changed = true;
|
|
29638
|
+
return false;
|
|
29639
|
+
}
|
|
29640
|
+
});
|
|
29641
|
+
return changed;
|
|
29642
|
+
}
|
|
29194
29643
|
var mentionChipField = StateField.define({
|
|
29195
29644
|
create: (state) => buildMentionChips(state),
|
|
29196
|
-
update: (value, tr) =>
|
|
29645
|
+
update: (value, tr) => {
|
|
29646
|
+
if (tr.docChanged) return buildMentionChips(tr.state);
|
|
29647
|
+
if (tr.startState.selection.eq(tr.state.selection)) return value;
|
|
29648
|
+
return coverageChanged(value, tr.startState.selection.main, tr.state.selection.main) ? buildMentionChips(tr.state) : value;
|
|
29649
|
+
},
|
|
29197
29650
|
provide: (field) => EditorView.decorations.from(field)
|
|
29198
29651
|
});
|
|
29199
29652
|
var mentionAtomicRanges = EditorView.atomicRanges.of((view) => view.state.field(mentionChipField, false) ?? Decoration.none);
|
|
@@ -29201,21 +29654,21 @@ var mentionAtomicRanges = EditorView.atomicRanges.of((view) => view.state.field(
|
|
|
29201
29654
|
var markdownEditing = [
|
|
29202
29655
|
markdown({ extensions: GFM }),
|
|
29203
29656
|
markDecorationPlugin,
|
|
29657
|
+
heldEmphasis,
|
|
29204
29658
|
hangingIndentField,
|
|
29205
29659
|
Prec.highest(mentionChipField),
|
|
29206
29660
|
mentionAtomicRanges
|
|
29207
29661
|
];
|
|
29208
29662
|
function mentionLinkAt(state, pos, side) {
|
|
29209
|
-
|
|
29210
|
-
if (node.name !== "Link")
|
|
29663
|
+
return enclosingNode(state, pos, side, (node) => {
|
|
29664
|
+
if (node.name !== "Link") return false;
|
|
29211
29665
|
let url = null;
|
|
29212
29666
|
for (let child = node.firstChild; child; child = child.nextSibling) if (child.name === "URL") {
|
|
29213
29667
|
url = child;
|
|
29214
29668
|
break;
|
|
29215
29669
|
}
|
|
29216
|
-
|
|
29217
|
-
}
|
|
29218
|
-
return null;
|
|
29670
|
+
return url !== null && state.sliceDoc(url.from, url.to).startsWith("user:");
|
|
29671
|
+
});
|
|
29219
29672
|
}
|
|
29220
29673
|
/** The mention whose collapsed token contains `pos` (used to select it on click). */
|
|
29221
29674
|
function mentionRangeAt(state, pos) {
|
|
@@ -29286,54 +29739,40 @@ function desiredSentinels(groups, cleanText, canPlace = canPlaceSentinel) {
|
|
|
29286
29739
|
}
|
|
29287
29740
|
return out;
|
|
29288
29741
|
}
|
|
29289
|
-
/**
|
|
29290
|
-
|
|
29291
|
-
function buildDesiredDoc(cleanText, desired) {
|
|
29742
|
+
/** How many sentinels each clean position wants (touching groups want two). */
|
|
29743
|
+
function desiredCounts(desired) {
|
|
29292
29744
|
const counts = /* @__PURE__ */ new Map();
|
|
29293
29745
|
for (const d of desired) counts.set(d.pos, (counts.get(d.pos) ?? 0) + 1);
|
|
29294
|
-
|
|
29295
|
-
for (let i = 0; i <= cleanText.length; i++) {
|
|
29296
|
-
const n = counts.get(i) ?? 0;
|
|
29297
|
-
if (n) out += "".repeat(n);
|
|
29298
|
-
if (i < cleanText.length) out += cleanText[i];
|
|
29299
|
-
}
|
|
29300
|
-
return out;
|
|
29746
|
+
return counts;
|
|
29301
29747
|
}
|
|
29302
29748
|
/** Minimal changes (in current-doc coords) to turn `doc` into a document that holds
|
|
29303
29749
|
* exactly the sentinels the groups want — touching only sentinel characters, never
|
|
29304
|
-
* the real text. `doc
|
|
29305
|
-
*
|
|
29750
|
+
* the real text. One walk over `doc`, comparing the sentinel run at each clean
|
|
29751
|
+
* position with the number wanted there. Building the target document first would
|
|
29752
|
+
* cost a second copy of the text on every edit. */
|
|
29306
29753
|
function reconcileSentinels(doc, groups, canPlace = canPlaceSentinel) {
|
|
29307
|
-
const
|
|
29308
|
-
const desired = buildDesiredDoc(cleanText, desiredSentinels(groups, cleanText, canPlace));
|
|
29754
|
+
const want = desiredCounts(desiredSentinels(groups, groups.length ? stripSentinels(doc) : "", canPlace));
|
|
29309
29755
|
const changes = [];
|
|
29310
|
-
let
|
|
29311
|
-
let
|
|
29312
|
-
|
|
29313
|
-
|
|
29314
|
-
|
|
29315
|
-
|
|
29316
|
-
|
|
29317
|
-
|
|
29318
|
-
|
|
29319
|
-
|
|
29320
|
-
|
|
29321
|
-
|
|
29322
|
-
|
|
29323
|
-
|
|
29324
|
-
}
|
|
29325
|
-
|
|
29326
|
-
|
|
29327
|
-
|
|
29328
|
-
|
|
29329
|
-
});
|
|
29330
|
-
j++;
|
|
29331
|
-
} else {
|
|
29332
|
-
i++;
|
|
29333
|
-
j++;
|
|
29334
|
-
}
|
|
29756
|
+
let pos = 0;
|
|
29757
|
+
let clean = 0;
|
|
29758
|
+
for (;;) {
|
|
29759
|
+
let have = 0;
|
|
29760
|
+
while (pos + have < doc.length && doc[pos + have] === "") have++;
|
|
29761
|
+
const need = want.get(clean) ?? 0;
|
|
29762
|
+
if (have > need) changes.push({
|
|
29763
|
+
from: pos + need,
|
|
29764
|
+
to: pos + have
|
|
29765
|
+
});
|
|
29766
|
+
else if (need > have) changes.push({
|
|
29767
|
+
from: pos + have,
|
|
29768
|
+
to: pos + have,
|
|
29769
|
+
insert: "".repeat(need - have)
|
|
29770
|
+
});
|
|
29771
|
+
pos += have;
|
|
29772
|
+
if (pos >= doc.length) return changes;
|
|
29773
|
+
pos++;
|
|
29774
|
+
clean++;
|
|
29335
29775
|
}
|
|
29336
|
-
return changes;
|
|
29337
29776
|
}
|
|
29338
29777
|
var LINE_START_MARKER = /^(\s*)(#{1,6}\s|[-*+]\s|\d+[.)]\s|>|`{3,}|~{3,})/;
|
|
29339
29778
|
/** Default placement guard. Blocks the sentinel where U+2060 would break the
|
|
@@ -29341,13 +29780,13 @@ var LINE_START_MARKER = /^(\s*)(#{1,6}\s|[-*+]\s|\d+[.)]\s|>|`{3,}|~{3,})/;
|
|
|
29341
29780
|
* strikethrough run (`~~...~~`). Blocked edges fall back to a single caret stop. */
|
|
29342
29781
|
function canPlaceSentinel(cleanText, pos, _kind) {
|
|
29343
29782
|
const lineStart = cleanText.lastIndexOf("\n", pos - 1) + 1;
|
|
29344
|
-
const
|
|
29783
|
+
const lineEnd = cleanText.indexOf("\n", pos) === -1 ? cleanText.length : cleanText.indexOf("\n", pos);
|
|
29784
|
+
const lineText = cleanText.slice(lineStart, lineEnd);
|
|
29785
|
+
const marker = lineText.match(LINE_START_MARKER);
|
|
29345
29786
|
if (marker) {
|
|
29346
29787
|
if (pos < lineStart + marker[0].length) return false;
|
|
29347
29788
|
}
|
|
29348
|
-
|
|
29349
|
-
const rel = pos - lineStart;
|
|
29350
|
-
if ((lineText.slice(0, rel).match(/~~/g) ?? []).length % 2 === 1) return false;
|
|
29789
|
+
if ((lineText.slice(0, pos - lineStart).match(/~~/g) ?? []).length % 2 === 1) return false;
|
|
29351
29790
|
return true;
|
|
29352
29791
|
}
|
|
29353
29792
|
//#endregion
|
|
@@ -29444,7 +29883,10 @@ var AnnotationBadge = class extends WidgetType {
|
|
|
29444
29883
|
top: badge.top,
|
|
29445
29884
|
bottom: badge.bottom
|
|
29446
29885
|
};
|
|
29447
|
-
const
|
|
29886
|
+
const tint = dom.closest(".cm-annotation");
|
|
29887
|
+
const rects = tint ? tint.getClientRects() : null;
|
|
29888
|
+
const lastLine = rects && rects.length ? rects[rects.length - 1] : null;
|
|
29889
|
+
const x = pos <= 0 ? badge.left - parseFloat(cs.marginLeft) : lastLine ? lastLine.right : badge.right + parseFloat(cs.marginRight);
|
|
29448
29890
|
return {
|
|
29449
29891
|
left: x,
|
|
29450
29892
|
right: x,
|
|
@@ -29508,7 +29950,12 @@ function resolveGroup(group, doc, sents) {
|
|
|
29508
29950
|
endSent: textTo < doc.length && doc[textTo] === "" ? textTo : null
|
|
29509
29951
|
};
|
|
29510
29952
|
}
|
|
29953
|
+
var NOTHING = {
|
|
29954
|
+
deco: Decoration.none,
|
|
29955
|
+
atomic: Decoration.none
|
|
29956
|
+
};
|
|
29511
29957
|
function buildAll(state, label) {
|
|
29958
|
+
if (!state.field(annotationField).length) return NOTHING;
|
|
29512
29959
|
const doc = state.doc.toString();
|
|
29513
29960
|
const sel = state.selection.main;
|
|
29514
29961
|
const sents = sentinelPositions(doc);
|
|
@@ -29560,6 +30007,7 @@ function makeAnnotationRender(label) {
|
|
|
29560
30007
|
return StateField.define({
|
|
29561
30008
|
create: (state) => buildAll(state, label),
|
|
29562
30009
|
update: (value, tr) => {
|
|
30010
|
+
if (value === NOTHING && !tr.state.field(annotationField).length) return value;
|
|
29563
30011
|
if (tr.docChanged || !tr.startState.selection.eq(tr.state.selection) || tr.effects.some((e) => e.is(setAnnotations))) return buildAll(tr.state, label);
|
|
29564
30012
|
return value;
|
|
29565
30013
|
},
|
|
@@ -29572,6 +30020,7 @@ function makeAnnotationRender(label) {
|
|
|
29572
30020
|
var annotationSentinelFilter = EditorState.transactionFilter.of((tr) => {
|
|
29573
30021
|
const set = tr.effects.find((e) => e.is(setAnnotations));
|
|
29574
30022
|
if (!tr.docChanged && !set) return tr;
|
|
30023
|
+
if (!(set || tr.effects.some((e) => e.is(pasteAnnotations) || e.is(annotationMove))) && !(tr.startState.field(annotationField, false) ?? []).length) return tr;
|
|
29575
30024
|
const postUserDoc = tr.newDoc.toString();
|
|
29576
30025
|
const cleanLen = stripSentinels(postUserDoc).length;
|
|
29577
30026
|
let anns;
|
|
@@ -29698,8 +30147,26 @@ function renumberOrderedLists(doc) {
|
|
|
29698
30147
|
}
|
|
29699
30148
|
/** Renumbers ordered lists in the same transaction as the edit that disturbed them,
|
|
29700
30149
|
* so it's one atomic (single-undo) step and the caret/selection maps through it. */
|
|
30150
|
+
/** Whether this change can have disturbed any numbering. It can when it adds or
|
|
30151
|
+
* removes a line break, or when a line it touches is (or was) an ordered item.
|
|
30152
|
+
* Typing inside a paragraph cannot, and that is the common case: without this
|
|
30153
|
+
* test every keystroke read the whole document out and walked every line. */
|
|
30154
|
+
function mayRenumber(tr) {
|
|
30155
|
+
let may = false;
|
|
30156
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
|
30157
|
+
if (may) return;
|
|
30158
|
+
const before = tr.startState.doc;
|
|
30159
|
+
if (inserted.lines > 1 || before.lineAt(fromA).number !== before.lineAt(toA).number) {
|
|
30160
|
+
may = true;
|
|
30161
|
+
return;
|
|
30162
|
+
}
|
|
30163
|
+
const ordered = (text) => ORDERED_RE.test(text.slice(BQ_PREFIX_RE.exec(text)[0].length));
|
|
30164
|
+
if (ordered(before.lineAt(fromA).text) || ordered(tr.newDoc.lineAt(fromB).text) || ordered(tr.newDoc.lineAt(toB).text)) may = true;
|
|
30165
|
+
});
|
|
30166
|
+
return may;
|
|
30167
|
+
}
|
|
29701
30168
|
var orderedListRenumber = EditorState.transactionFilter.of((tr) => {
|
|
29702
|
-
if (!tr.docChanged) return tr;
|
|
30169
|
+
if (!tr.docChanged || !mayRenumber(tr)) return tr;
|
|
29703
30170
|
const changes = renumberOrderedLists(tr.newDoc.toString());
|
|
29704
30171
|
if (changes.length === 0) return tr;
|
|
29705
30172
|
return [tr, {
|
|
@@ -29921,6 +30388,205 @@ var dragToMove = [
|
|
|
29921
30388
|
dragMovePlugin
|
|
29922
30389
|
];
|
|
29923
30390
|
//#endregion
|
|
30391
|
+
//#region src/components/inputs/text-editor/text-editor.cursor.ts
|
|
30392
|
+
/** Below this the two edges of one position are the same place drawn twice, and
|
|
30393
|
+
* only glyph overhang and pixel rounding tell them apart. A widget is a full
|
|
30394
|
+
* icon wide and a line wrap is a line away, so neither comes near it. */
|
|
30395
|
+
var GLYPH_NOISE_PX = 2;
|
|
30396
|
+
/** The side the main caret is drawn on at `head`, when that is not for the
|
|
30397
|
+
* selection's own assoc to say. Set by a step-over (its assoc does not survive
|
|
30398
|
+
* the transaction: a later filter rebuilds the selection without it), by a
|
|
30399
|
+
* click (CodeMirror reads the side of a click from the line, not from the
|
|
30400
|
+
* pointer, and would land left of a badge you clicked right of), and by an
|
|
30401
|
+
* edit: typing and a backward delete leave the caret at the end of what was
|
|
30402
|
+
* just edited, so on the side that text is, the left; a forward delete leaves
|
|
30403
|
+
* it where the removed text began, the right. */
|
|
30404
|
+
var sideHint = /* @__PURE__ */ new WeakMap();
|
|
30405
|
+
/** The side a step-over asks for, carried as an annotation. */
|
|
30406
|
+
var caretSide = Annotation.define();
|
|
30407
|
+
/** Where the pointer last went down or dragged, to read the side of a click. */
|
|
30408
|
+
var lastPointer = /* @__PURE__ */ new WeakMap();
|
|
30409
|
+
function edges(view, head) {
|
|
30410
|
+
const before = view.coordsAtPos(head, -1);
|
|
30411
|
+
const after = view.coordsAtPos(head, 1);
|
|
30412
|
+
return before && after ? {
|
|
30413
|
+
before,
|
|
30414
|
+
after
|
|
30415
|
+
} : null;
|
|
30416
|
+
}
|
|
30417
|
+
/** A line wrap puts the two sides a whole line apart. A few pixels is not that:
|
|
30418
|
+
* a syntax marker is set in monospace, whose glyph box sits a little higher or
|
|
30419
|
+
* lower than the body text's, and Safari rounds each edge to a whole pixel. */
|
|
30420
|
+
var WRAP_PX = 8;
|
|
30421
|
+
function onOneLine(e) {
|
|
30422
|
+
return Math.abs(e.before.top - e.after.top) < WRAP_PX;
|
|
30423
|
+
}
|
|
30424
|
+
/** The side the caret is drawn on at `head`: 1 unless the two sides are
|
|
30425
|
+
* genuinely apart and a hint, or else the arrival direction, says "before". */
|
|
30426
|
+
function drawnAssoc(view, head, assoc) {
|
|
30427
|
+
const e = edges(view, head);
|
|
30428
|
+
if (e && onOneLine(e) && Math.abs(e.before.left - e.after.left) <= GLYPH_NOISE_PX) return 1;
|
|
30429
|
+
const hint = sideHint.get(view);
|
|
30430
|
+
if (hint && hint.head === head) {
|
|
30431
|
+
if (hint.side !== "pointer") return hint.side;
|
|
30432
|
+
const p = lastPointer.get(view);
|
|
30433
|
+
if (p && e) return Math.abs(p.x - e.before.left) <= Math.abs(p.x - e.after.left) ? -1 : 1;
|
|
30434
|
+
}
|
|
30435
|
+
if (assoc) return assoc < 0 ? -1 : 1;
|
|
30436
|
+
return 1;
|
|
30437
|
+
}
|
|
30438
|
+
var pointerTracker = EditorView.domEventHandlers({
|
|
30439
|
+
mousedown(event, view) {
|
|
30440
|
+
lastPointer.set(view, {
|
|
30441
|
+
x: event.clientX,
|
|
30442
|
+
y: event.clientY
|
|
30443
|
+
});
|
|
30444
|
+
return false;
|
|
30445
|
+
},
|
|
30446
|
+
mousemove(event, view) {
|
|
30447
|
+
if (event.buttons) lastPointer.set(view, {
|
|
30448
|
+
x: event.clientX,
|
|
30449
|
+
y: event.clientY
|
|
30450
|
+
});
|
|
30451
|
+
return false;
|
|
30452
|
+
},
|
|
30453
|
+
touchstart(event, view) {
|
|
30454
|
+
const touch = event.touches[0];
|
|
30455
|
+
if (touch) lastPointer.set(view, {
|
|
30456
|
+
x: touch.clientX,
|
|
30457
|
+
y: touch.clientY
|
|
30458
|
+
});
|
|
30459
|
+
return false;
|
|
30460
|
+
}
|
|
30461
|
+
});
|
|
30462
|
+
/** Puts the caret on `side` of the link badge it stands at, without moving it in
|
|
30463
|
+
* the document. Nothing to do (so the key falls through to its usual command)
|
|
30464
|
+
* when there is no badge here, or the caret is on that side already. Only a
|
|
30465
|
+
* link badge qualifies: a mention token or an annotation badge keeps its own
|
|
30466
|
+
* Backspace and arrow behavior. The badge's two sides are not asked to share a
|
|
30467
|
+
* line: the marker before it may measure a rounded pixel off in Safari, and a
|
|
30468
|
+
* wrap can fall between the two. */
|
|
30469
|
+
function stepOver(side) {
|
|
30470
|
+
return (view) => {
|
|
30471
|
+
const { main } = view.state.selection;
|
|
30472
|
+
if (!main.empty || !linkEndsAt(view.state, main.head) || !edges(view, main.head)) return false;
|
|
30473
|
+
if (drawnAssoc(view, main.head, main.assoc) === side) return false;
|
|
30474
|
+
view.dispatch({
|
|
30475
|
+
selection: EditorSelection.cursor(main.head, side),
|
|
30476
|
+
annotations: caretSide.of(side),
|
|
30477
|
+
userEvent: "select"
|
|
30478
|
+
});
|
|
30479
|
+
return true;
|
|
30480
|
+
};
|
|
30481
|
+
}
|
|
30482
|
+
var stepOverKeymap = Prec.high(keymap.of([
|
|
30483
|
+
{
|
|
30484
|
+
key: "ArrowLeft",
|
|
30485
|
+
run: stepOver(-1)
|
|
30486
|
+
},
|
|
30487
|
+
{
|
|
30488
|
+
key: "ArrowRight",
|
|
30489
|
+
run: stepOver(1)
|
|
30490
|
+
},
|
|
30491
|
+
{
|
|
30492
|
+
key: "Backspace",
|
|
30493
|
+
run: stepOver(-1)
|
|
30494
|
+
},
|
|
30495
|
+
{
|
|
30496
|
+
key: "Delete",
|
|
30497
|
+
run: stepOver(1)
|
|
30498
|
+
}
|
|
30499
|
+
]));
|
|
30500
|
+
/** Characters that end a bare URL by themselves (GFM: whitespace, `<`, and the
|
|
30501
|
+
* punctuation it leaves off the end), so text starting with one lands after
|
|
30502
|
+
* the badge on its own. Anything else would join the URL. */
|
|
30503
|
+
var ENDS_URL = /^[\s<?!.,:*_~)]/;
|
|
30504
|
+
/** Text typed right of the badge of a bare URL lands right of the badge. There
|
|
30505
|
+
* is no boundary in markdown to put it behind: `www.apple.comx` is one URL. A
|
|
30506
|
+
* space is that boundary, so the editor writes it before the text. */
|
|
30507
|
+
var typePastBadge = EditorView.inputHandler.of((view, from, to, text) => {
|
|
30508
|
+
if (from !== to || !text || view.composing || ENDS_URL.test(text)) return false;
|
|
30509
|
+
const { main } = view.state.selection;
|
|
30510
|
+
if (!main.empty || main.head !== from || !bareUrlEndsAt(view.state, from) || !edges(view, from)) return false;
|
|
30511
|
+
if (drawnAssoc(view, from, main.assoc) !== 1) return false;
|
|
30512
|
+
view.dispatch({
|
|
30513
|
+
changes: {
|
|
30514
|
+
from,
|
|
30515
|
+
insert: ` ${text}`
|
|
30516
|
+
},
|
|
30517
|
+
selection: { anchor: from + 1 + text.length },
|
|
30518
|
+
userEvent: "input.type",
|
|
30519
|
+
scrollIntoView: true
|
|
30520
|
+
});
|
|
30521
|
+
return true;
|
|
30522
|
+
});
|
|
30523
|
+
var stableCursor = [
|
|
30524
|
+
layer({
|
|
30525
|
+
above: true,
|
|
30526
|
+
class: "cm-nldd-cursorLayer",
|
|
30527
|
+
markers(view) {
|
|
30528
|
+
const { state } = view;
|
|
30529
|
+
const conf = getDrawSelectionConfig(state);
|
|
30530
|
+
const out = [];
|
|
30531
|
+
for (const r of state.selection.ranges) {
|
|
30532
|
+
if (!r.empty && !conf.drawRangeCursor) continue;
|
|
30533
|
+
const className = r === state.selection.main ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary";
|
|
30534
|
+
const cursor = EditorSelection.cursor(r.head, drawnAssoc(view, r.head, r.assoc));
|
|
30535
|
+
out.push(...RectangleMarker.forRange(view, className, cursor));
|
|
30536
|
+
}
|
|
30537
|
+
return out;
|
|
30538
|
+
},
|
|
30539
|
+
update(update, dom) {
|
|
30540
|
+
if (update.docChanged || update.selectionSet) {
|
|
30541
|
+
const { view } = update;
|
|
30542
|
+
const head = update.state.selection.main.head;
|
|
30543
|
+
const kept = sideHint.get(view);
|
|
30544
|
+
let hint = kept ? {
|
|
30545
|
+
...kept,
|
|
30546
|
+
head: update.changes.mapPos(kept.head)
|
|
30547
|
+
} : null;
|
|
30548
|
+
const oldHead = update.startState.selection.main.head;
|
|
30549
|
+
for (const tr of update.transactions) {
|
|
30550
|
+
const asked = tr.annotation(caretSide);
|
|
30551
|
+
if (asked) hint = {
|
|
30552
|
+
head,
|
|
30553
|
+
side: asked
|
|
30554
|
+
};
|
|
30555
|
+
else if (tr.isUserEvent("select.pointer")) hint = {
|
|
30556
|
+
head,
|
|
30557
|
+
side: "pointer"
|
|
30558
|
+
};
|
|
30559
|
+
else if (tr.isUserEvent("input") || tr.isUserEvent("delete.backward")) hint = {
|
|
30560
|
+
head,
|
|
30561
|
+
side: linkEndsAt(update.state, head) && !linkEndsAt(update.startState, oldHead) ? 1 : -1
|
|
30562
|
+
};
|
|
30563
|
+
else if (tr.isUserEvent("delete.forward")) hint = {
|
|
30564
|
+
head,
|
|
30565
|
+
side: 1
|
|
30566
|
+
};
|
|
30567
|
+
else if (tr.selection) hint = null;
|
|
30568
|
+
}
|
|
30569
|
+
if (hint) sideHint.set(view, hint);
|
|
30570
|
+
else sideHint.delete(view);
|
|
30571
|
+
}
|
|
30572
|
+
if (update.transactions.some((tr) => tr.selection)) dom.style.animationName = dom.style.animationName === "cm-blink" ? "cm-blink2" : "cm-blink";
|
|
30573
|
+
return update.docChanged || update.selectionSet;
|
|
30574
|
+
},
|
|
30575
|
+
mount(dom, view) {
|
|
30576
|
+
dom.style.animationDuration = `${getDrawSelectionConfig(view.state).cursorBlinkRate}ms`;
|
|
30577
|
+
}
|
|
30578
|
+
}),
|
|
30579
|
+
pointerTracker,
|
|
30580
|
+
stepOverKeymap,
|
|
30581
|
+
typePastBadge,
|
|
30582
|
+
EditorView.theme({
|
|
30583
|
+
".cm-cursorLayer": { display: "none" },
|
|
30584
|
+
".cm-nldd-cursorLayer": { pointerEvents: "none" },
|
|
30585
|
+
"&.cm-focused > .cm-scroller > .cm-nldd-cursorLayer": { animation: "steps(1) cm-blink 1.2s infinite" },
|
|
30586
|
+
"&.cm-focused > .cm-scroller > .cm-nldd-cursorLayer .cm-cursor": { display: "block" }
|
|
30587
|
+
})
|
|
30588
|
+
];
|
|
30589
|
+
//#endregion
|
|
29924
30590
|
//#region src/components/inputs/text-editor/text-editor.commands.ts
|
|
29925
30591
|
var EMPTY_FORMATS = {
|
|
29926
30592
|
bold: false,
|
|
@@ -29931,12 +30597,12 @@ var EMPTY_FORMATS = {
|
|
|
29931
30597
|
link: false,
|
|
29932
30598
|
bulletList: false,
|
|
29933
30599
|
orderedList: false,
|
|
30600
|
+
taskList: false,
|
|
29934
30601
|
quote: false,
|
|
29935
30602
|
heading: 0
|
|
29936
30603
|
};
|
|
29937
30604
|
function enclosing(view, pos, nodeName, side = 1) {
|
|
29938
|
-
|
|
29939
|
-
return null;
|
|
30605
|
+
return enclosingNamed(view.state, pos, side, nodeName);
|
|
29940
30606
|
}
|
|
29941
30607
|
/** An inline format is "active" for the caret only when the node encloses it on
|
|
29942
30608
|
* *both* sides. At the outer edge (just before the opening marker or just after
|
|
@@ -29947,31 +30613,67 @@ function enclosingInline(view, pos, nodeName) {
|
|
|
29947
30613
|
const right = enclosing(view, pos, nodeName, 1);
|
|
29948
30614
|
return left && right && left.from === right.from && left.to === right.to ? right : null;
|
|
29949
30615
|
}
|
|
29950
|
-
/** Wrap
|
|
30616
|
+
/** Wrap each selection range with `marker`, or unwrap it when it is already
|
|
30617
|
+
* wrapped. A caret at the very end of the wrapped text steps out of the run
|
|
30618
|
+
* instead: bold, type, bold ends with the caret after the bold, ready for the
|
|
30619
|
+
* next word, not with the bold undone. */
|
|
29951
30620
|
function toggleInlineWrap(view, marker, nodeName) {
|
|
29952
30621
|
if (view.state.readOnly) return;
|
|
30622
|
+
const { state } = view;
|
|
29953
30623
|
const len = marker.length;
|
|
29954
|
-
|
|
29955
|
-
|
|
29956
|
-
|
|
29957
|
-
|
|
30624
|
+
const held = state.field(heldEmphasisField, false);
|
|
30625
|
+
view.dispatch(state.changeByRange((range) => {
|
|
30626
|
+
const text = state.sliceDoc(range.from, range.to);
|
|
30627
|
+
const lead = /^\s*/.exec(text)[0].length;
|
|
30628
|
+
if (!range.empty && lead === text.length) return { range };
|
|
30629
|
+
const from = range.from + lead;
|
|
30630
|
+
const to = range.to - /\s*$/.exec(text)[0].length;
|
|
30631
|
+
const wrap = enclosing(view, from, nodeName) ?? (held && held.name === nodeName && from >= held.from && to <= held.to ? held : null);
|
|
30632
|
+
if (wrap) {
|
|
30633
|
+
const content = state.sliceDoc(wrap.from + len, wrap.to - len);
|
|
30634
|
+
if (range.empty && from === wrap.to - len && content.trim()) {
|
|
30635
|
+
const run = {
|
|
30636
|
+
from: wrap.from,
|
|
30637
|
+
to: wrap.to,
|
|
30638
|
+
name: nodeName,
|
|
30639
|
+
marker: state.sliceDoc(wrap.from, wrap.from + len),
|
|
30640
|
+
live: false
|
|
30641
|
+
};
|
|
30642
|
+
const changes = EMPHASIS_MARKERS.has(nodeName) ? repairChangesFor(state, run) : [];
|
|
30643
|
+
let pos = wrap.to;
|
|
30644
|
+
while (/[ \t]/.test(state.sliceDoc(pos, pos + 1))) pos++;
|
|
30645
|
+
return {
|
|
30646
|
+
changes,
|
|
30647
|
+
range: EditorSelection.cursor(pos)
|
|
30648
|
+
};
|
|
30649
|
+
}
|
|
30650
|
+
const changes = state.changes([{
|
|
29958
30651
|
from: wrap.from,
|
|
29959
30652
|
to: wrap.from + len
|
|
29960
30653
|
}, {
|
|
29961
30654
|
from: wrap.to - len,
|
|
29962
30655
|
to: wrap.to
|
|
29963
|
-
}]
|
|
29964
|
-
|
|
29965
|
-
|
|
30656
|
+
}]);
|
|
30657
|
+
return {
|
|
30658
|
+
changes,
|
|
30659
|
+
range: EditorSelection.range(changes.mapPos(range.anchor), changes.mapPos(range.head))
|
|
30660
|
+
};
|
|
30661
|
+
}
|
|
29966
30662
|
return {
|
|
29967
30663
|
changes: [{
|
|
29968
|
-
from
|
|
30664
|
+
from,
|
|
29969
30665
|
insert: marker
|
|
29970
30666
|
}, {
|
|
29971
|
-
from:
|
|
30667
|
+
from: to,
|
|
29972
30668
|
insert: marker
|
|
29973
30669
|
}],
|
|
29974
|
-
range: EditorSelection.range(
|
|
30670
|
+
range: EditorSelection.range(from + len, to + len),
|
|
30671
|
+
effects: range.empty && range === state.selection.main && EMPHASIS_MARKERS.has(nodeName) ? holdEmphasis.of({
|
|
30672
|
+
from,
|
|
30673
|
+
to: from + 2 * len,
|
|
30674
|
+
name: nodeName,
|
|
30675
|
+
marker
|
|
30676
|
+
}) : void 0
|
|
29975
30677
|
};
|
|
29976
30678
|
}));
|
|
29977
30679
|
view.focus();
|
|
@@ -29993,20 +30695,51 @@ function minimalLineChange(line, next) {
|
|
|
29993
30695
|
insert: next.slice(p, next.length - s)
|
|
29994
30696
|
};
|
|
29995
30697
|
}
|
|
29996
|
-
|
|
29997
|
-
|
|
30698
|
+
/** Dispatch line-level changes with the selection carried along. A caret that
|
|
30699
|
+
* sits exactly where a marker is inserted (column 0 of an empty line, say) is
|
|
30700
|
+
* mapped to *after* the insertion, so what is typed next lands in the item and
|
|
30701
|
+
* not in front of its marker. Plain mapping would leave it before. */
|
|
30702
|
+
function dispatchLineChanges(view, changes) {
|
|
30703
|
+
if (changes.length) {
|
|
30704
|
+
const { state } = view;
|
|
30705
|
+
const set = state.changes(changes);
|
|
30706
|
+
const sel = state.selection.main;
|
|
30707
|
+
view.dispatch({
|
|
30708
|
+
changes: set,
|
|
30709
|
+
selection: {
|
|
30710
|
+
anchor: set.mapPos(sel.anchor, 1),
|
|
30711
|
+
head: set.mapPos(sel.head, 1)
|
|
30712
|
+
}
|
|
30713
|
+
});
|
|
30714
|
+
}
|
|
30715
|
+
view.focus();
|
|
30716
|
+
}
|
|
30717
|
+
/** The selected line range, and whether it is a single blank line. The line
|
|
30718
|
+
* commands skip blank lines because they separate items, but when the blank
|
|
30719
|
+
* line is the only one selected (an empty document, a fresh paragraph) it is
|
|
30720
|
+
* the whole target and must take the marker. */
|
|
30721
|
+
function selectedLines(view) {
|
|
29998
30722
|
const { state } = view;
|
|
29999
30723
|
const { from, to } = state.selection.main;
|
|
30000
30724
|
const first = state.doc.lineAt(from).number;
|
|
30001
30725
|
const last = state.doc.lineAt(to).number;
|
|
30726
|
+
return {
|
|
30727
|
+
first,
|
|
30728
|
+
last,
|
|
30729
|
+
loneBlank: first === last && state.doc.line(first).text.trim() === ""
|
|
30730
|
+
};
|
|
30731
|
+
}
|
|
30732
|
+
function mapSelectedLines(view, transform) {
|
|
30733
|
+
if (view.state.readOnly) return;
|
|
30734
|
+
const { state } = view;
|
|
30735
|
+
const { first, last } = selectedLines(view);
|
|
30002
30736
|
const changes = [];
|
|
30003
30737
|
for (let i = first; i <= last; i++) {
|
|
30004
30738
|
const line = state.doc.line(i);
|
|
30005
30739
|
const change = minimalLineChange(line, transform(line.text));
|
|
30006
30740
|
if (change) changes.push(change);
|
|
30007
30741
|
}
|
|
30008
|
-
|
|
30009
|
-
view.focus();
|
|
30742
|
+
dispatchLineChanges(view, changes);
|
|
30010
30743
|
}
|
|
30011
30744
|
function everySelectedLine(view, predicate) {
|
|
30012
30745
|
const { state } = view;
|
|
@@ -30036,39 +30769,56 @@ function setHeading(view, level) {
|
|
|
30036
30769
|
}
|
|
30037
30770
|
function toggleBulletList(view) {
|
|
30038
30771
|
const re = /^(\s*)[-*+]\s+/;
|
|
30039
|
-
const
|
|
30772
|
+
const { loneBlank } = selectedLines(view);
|
|
30773
|
+
const allBulleted = !loneBlank && everySelectedLine(view, (t) => re.test(t) || t.trim() === "");
|
|
30040
30774
|
mapSelectedLines(view, (t) => {
|
|
30041
|
-
if (t.trim() === "") return t;
|
|
30775
|
+
if (t.trim() === "" && !loneBlank) return t;
|
|
30042
30776
|
if (allBulleted) return t.replace(re, "$1");
|
|
30043
30777
|
return re.test(t) ? t : t.replace(/^(\s*)/, "$1- ");
|
|
30044
30778
|
});
|
|
30045
30779
|
}
|
|
30046
|
-
var
|
|
30780
|
+
var TASK_RE = /^(\s*)[-*+]\s+\[[ xX]\]\s+/;
|
|
30781
|
+
/** Turn the selected lines into GFM task items (`- [ ] `), or back into plain
|
|
30782
|
+
* bullets when they all are tasks already. A bullet or numbered item keeps its
|
|
30783
|
+
* indent and becomes a task; toggling off leaves a bullet rather than bare text,
|
|
30784
|
+
* so the list survives and only the box goes. Checking a box is not this
|
|
30785
|
+
* command's job. */
|
|
30786
|
+
function toggleTaskList(view) {
|
|
30787
|
+
const { loneBlank } = selectedLines(view);
|
|
30788
|
+
const allTasks = !loneBlank && everySelectedLine(view, (t) => TASK_RE.test(t) || t.trim() === "");
|
|
30789
|
+
mapSelectedLines(view, (t) => {
|
|
30790
|
+
if (t.trim() === "" && !loneBlank) return t;
|
|
30791
|
+
if (allTasks) return t.replace(TASK_RE, "$1- ");
|
|
30792
|
+
if (TASK_RE.test(t)) return t;
|
|
30793
|
+
return t.replace(LIST_STRIP_RE, "$1").replace(/^(\s*)/, "$1- [ ] ");
|
|
30794
|
+
});
|
|
30795
|
+
}
|
|
30796
|
+
var LIST_STRIP_RE = /^(\s*)(?:[-*+]|\d+[.)])(?:\s+|$)/;
|
|
30797
|
+
var TASK_BOX_RE = /^(\s*)\[[ xX]\]\s+/;
|
|
30047
30798
|
/** Set the selected lines to a list of `type`, replacing any existing list
|
|
30048
30799
|
* marker; `'none'` strips it. Ordered items are numbered within the selection.
|
|
30049
30800
|
* Unlike the toggles, this cleanly switches between list types (for a picker). */
|
|
30050
30801
|
function setList(view, type) {
|
|
30051
30802
|
if (view.state.readOnly) return;
|
|
30052
30803
|
const { state } = view;
|
|
30053
|
-
const {
|
|
30054
|
-
const first = state.doc.lineAt(from).number;
|
|
30055
|
-
const last = state.doc.lineAt(to).number;
|
|
30804
|
+
const { first, last, loneBlank } = selectedLines(view);
|
|
30056
30805
|
const changes = [];
|
|
30057
30806
|
let number = 0;
|
|
30058
30807
|
for (let i = first; i <= last; i++) {
|
|
30059
30808
|
const line = state.doc.line(i);
|
|
30060
|
-
const
|
|
30809
|
+
const withoutMarker = line.text.replace(LIST_STRIP_RE, type === "none" ? "" : "$1");
|
|
30810
|
+
const wasItem = withoutMarker !== line.text;
|
|
30811
|
+
const stripped = wasItem ? withoutMarker.replace(TASK_BOX_RE, type === "none" ? "" : "$1") : withoutMarker;
|
|
30061
30812
|
let next = stripped;
|
|
30062
|
-
if (type !== "none" && stripped.trim() !== "") {
|
|
30813
|
+
if (type !== "none" && (stripped.trim() !== "" || wasItem || loneBlank)) {
|
|
30063
30814
|
number += 1;
|
|
30064
|
-
const marker = type === "bullet" ? "- " : `${number}. `;
|
|
30815
|
+
const marker = type === "bullet" ? "- " : type === "task" ? "- [ ] " : `${number}. `;
|
|
30065
30816
|
next = stripped.replace(/^(\s*)/, `$1${marker}`);
|
|
30066
30817
|
}
|
|
30067
30818
|
const change = minimalLineChange(line, next);
|
|
30068
30819
|
if (change) changes.push(change);
|
|
30069
30820
|
}
|
|
30070
|
-
|
|
30071
|
-
view.focus();
|
|
30821
|
+
dispatchLineChanges(view, changes);
|
|
30072
30822
|
}
|
|
30073
30823
|
/** Nest the selected list item(s) under the nearest preceding item at the same
|
|
30074
30824
|
* level, indenting only as far as that parent's content column. That keeps the
|
|
@@ -30270,7 +31020,8 @@ function toggleCodeBlock(view) {
|
|
|
30270
31020
|
function readActiveFormats(view) {
|
|
30271
31021
|
const { state } = view;
|
|
30272
31022
|
const pos = state.selection.main.head;
|
|
30273
|
-
const
|
|
31023
|
+
const held = state.field(heldEmphasisField, false);
|
|
31024
|
+
const has = (name) => enclosingInline(view, pos, name) !== null || held?.name === name;
|
|
30274
31025
|
const lineText = state.doc.lineAt(pos).text;
|
|
30275
31026
|
const lineStart = state.doc.lineAt(pos).from;
|
|
30276
31027
|
const headingMatch = lineText.match(/^(#{1,6})\s/);
|
|
@@ -30284,6 +31035,7 @@ function readActiveFormats(view) {
|
|
|
30284
31035
|
link: realLinkAt(view, pos) !== null,
|
|
30285
31036
|
bulletList: !codeBlock && /^\s*[-*+]\s/.test(lineText),
|
|
30286
31037
|
orderedList: !codeBlock && /^\s*\d+[.)]\s/.test(lineText),
|
|
31038
|
+
taskList: !codeBlock && TASK_RE.test(lineText),
|
|
30287
31039
|
quote: enclosing(view, lineStart, "Blockquote") !== null,
|
|
30288
31040
|
heading: codeBlock || !headingMatch ? 0 : headingMatch[1].length
|
|
30289
31041
|
};
|
|
@@ -30296,13 +31048,16 @@ var textEditorStyles = css`
|
|
|
30296
31048
|
/* # Host */
|
|
30297
31049
|
|
|
30298
31050
|
:host {
|
|
30299
|
-
--
|
|
31051
|
+
--_caret-width: var(--primitives-border-width-regular);
|
|
31052
|
+
--_caret-ring-width: var(--primitives-border-width-thin);
|
|
30300
31053
|
--_corner-radius: 0;
|
|
30301
31054
|
--_background-color: transparent;
|
|
30302
31055
|
--_highlight-border-color: transparent;
|
|
30303
31056
|
--_highlight-border-shadow: none;
|
|
30304
31057
|
--_padding-block: 0px;
|
|
30305
|
-
|
|
31058
|
+
/* Room for the caret's own ink at the first and last position of a line:
|
|
31059
|
+
its width plus its ring. Without it the edge carets are clipped. */
|
|
31060
|
+
--_padding-inline: calc(var(--_caret-width) + var(--_caret-ring-width));
|
|
30306
31061
|
--_content-color: var(--semantics-content-color);
|
|
30307
31062
|
--_text-font: var(--primitives-font-body-md-regular-snug);
|
|
30308
31063
|
--_code-font: var(--primitives-font-monospace-md-regular-snug);
|
|
@@ -30439,16 +31194,14 @@ var textEditorStyles = css`
|
|
|
30439
31194
|
surfaces in light and dark (accent-600 fell just short on white), so the
|
|
30440
31195
|
caret stays clearly visible without washing out. */
|
|
30441
31196
|
border-left-color: var(--primitives-color-accent-700);
|
|
30442
|
-
border-left-width: var(--
|
|
30443
|
-
/*
|
|
31197
|
+
border-left-width: var(--_caret-width);
|
|
31198
|
+
/* CodeMirror centers its own 1.2px caret with a -0.6px margin. Ours is wider,
|
|
31199
|
+
so recenter it on the insertion point from its own width. */
|
|
31200
|
+
margin-left: calc(var(--_caret-width) / -2);
|
|
31201
|
+
/* A thin surface-colored ring, like the drop cursor, so the caret stays legible
|
|
30444
31202
|
even over a tinted token (annotation, inline code) where the accent alone can
|
|
30445
31203
|
blend in. Blinks with the caret (opacity covers the shadow too). */
|
|
30446
|
-
box-shadow: 0 0 0 var(--
|
|
30447
|
-
/* CodeMirror draws the caret ~0.6px left of the text position. At a line start
|
|
30448
|
-
with no inline padding (the simple variant) that overhangs the scroller's
|
|
30449
|
-
overflow edge, so the left of the 2px gets clipped and the caret looks thinner
|
|
30450
|
-
there than mid-line. Nudge it right so the full width stays inside the content. */
|
|
30451
|
-
transform: translateX(0.6px);
|
|
31204
|
+
box-shadow: 0 0 0 var(--_caret-ring-width) var(--semantics-surfaces-base-background-color);
|
|
30452
31205
|
}
|
|
30453
31206
|
|
|
30454
31207
|
:host .cm-scroller {
|
|
@@ -30912,12 +31665,20 @@ var nlddTextEditorTranslations = {
|
|
|
30912
31665
|
*
|
|
30913
31666
|
* Headless: there is no built-in toolbar. A consumer drives formatting via the
|
|
30914
31667
|
* command methods (toggleBold/toggleItalic/toggleInlineCode/toggleStrikethrough/
|
|
30915
|
-
* toggleHeading/toggleBulletList/toggleQuote/toggleLink/runCommand
|
|
31668
|
+
* toggleHeading/toggleBulletList/toggleTaskList/toggleQuote/toggleLink/runCommand
|
|
31669
|
+
* to toggle, and
|
|
30916
31670
|
* setHeading/setList for picker-style "set" semantics), reads the active formats
|
|
30917
31671
|
* with getState(), listens to the nldd-text-editor-state event to render toggle
|
|
30918
31672
|
* states, and forwards padding clicks with focusFromPoint(). Cmd/Ctrl+B/I/E/K are
|
|
30919
|
-
* bound out of the box. Commands keep focus on the editor. An
|
|
30920
|
-
*
|
|
31673
|
+
* bound out of the box. Commands keep focus on the editor. An inline toggle wraps
|
|
31674
|
+
* the selected text (whitespace at its edges stays outside the markers), unwraps
|
|
31675
|
+
* a run the caret is in, and with the caret at the very end of a run steps out
|
|
31676
|
+
* of it. Bold that a typed space has broken (`**woord **`) keeps its styling
|
|
31677
|
+
* while the caret is inside; the space moves outside the markers when the caret
|
|
31678
|
+
* leaves. insertAtCursor(text) puts text at the caret and replaceRange(from, to,
|
|
31679
|
+
* text) writes at the same clean offsets getSelection() reads. An @-mention typeahead
|
|
31680
|
+
* (mentionSource) collapses to an atomic token, further typeahead lists on their
|
|
31681
|
+
* own trigger (typeaheads) write what you tell them to, and a W3C-style annotation overlay
|
|
30921
31682
|
* (annotations) marks ranges with a dashed underline, light tint and a count badge
|
|
30922
31683
|
* without touching the underlying text.
|
|
30923
31684
|
*
|
|
@@ -30937,6 +31698,7 @@ var nlddTextEditorTranslations = {
|
|
|
30937
31698
|
* @attr {string} accessible-label - Accessible label forwarded to the editor. Set automatically by nldd-form-field.
|
|
30938
31699
|
*
|
|
30939
31700
|
* @prop {MentionSource} mentionSource - Consumer-supplied @-mention candidate source (property only). Without it, @-typeahead is inert.
|
|
31701
|
+
* @prop {Typeahead[]} typeaheads - Your own typeahead lists next to the @-mention (property only): each a trigger character (`#`, `:`, `/`), a `source` that returns candidates for the text typed after it, and an optional `insert` that decides what a choice writes (by default the trigger, the text and a space). Lists on one trigger are merged in order. A candidate is `{ id, text, supportingText? }` and can carry an `avatar` (its row then takes two lines, the supporting text under the text), an `icon` or a `symbol` for its row.
|
|
30940
31702
|
* @attr {boolean} annotatable - Enable the annotation overlay (off by default). Annotations only render when this is set.
|
|
30941
31703
|
* @prop {Annotation[]} annotations - Consumer-supplied annotation overlay (property only). Anchored by offset and mapped through edits; the text stays clean. Requires `annotatable`. Assign a NEW array to apply changes (Lit dirty-checks by identity, so in-place mutation like `.push()` won't re-render): `editor.annotations = [...editor.annotations, next]`.
|
|
30942
31704
|
* @attr {object} translations - Override the editor's assistive-tech strings (the open-in-new-tab link badge and the annotation count badge). Unset keys fall back to Dutch.
|
|
@@ -30945,7 +31707,8 @@ var nlddTextEditorTranslations = {
|
|
|
30945
31707
|
* @fires input - When the content changes (detail: { value })
|
|
30946
31708
|
* @fires change - When the content is committed on blur (detail: { value })
|
|
30947
31709
|
* @fires nldd-text-editor-state - When the selection or content changes (detail: TextEditorState), for toolbar toggle state
|
|
30948
|
-
* @fires nldd-text-editor-mention - When an @-mention is inserted (detail: MentionInsertedDetail with id,
|
|
31710
|
+
* @fires nldd-text-editor-mention - When an @-mention is inserted (detail: MentionInsertedDetail with id, text, from, to; clean offsets, like getSelection())
|
|
31711
|
+
* @fires nldd-text-editor-typeahead - When a candidate from one of the `typeaheads` is chosen (detail: TypeaheadChosenDetail with trigger, candidate, from, to; clean offsets)
|
|
30949
31712
|
* @fires nldd-text-editor-annotation-click - When an annotation's count badge is clicked (detail: { ids: string[], rect: DOMRect }); rect is the badge's viewport box so a consumer can anchor its own note UI to it
|
|
30950
31713
|
*/
|
|
30951
31714
|
var _NLDDTextEditor;
|
|
@@ -30967,6 +31730,12 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
30967
31730
|
this.resize = "auto";
|
|
30968
31731
|
this.variant = "simple";
|
|
30969
31732
|
this.accessibleLabel = "";
|
|
31733
|
+
this.typeaheads = [];
|
|
31734
|
+
this._mentionTypeahead = {
|
|
31735
|
+
trigger: "@",
|
|
31736
|
+
source: (query) => this.mentionSource?.(query) ?? [],
|
|
31737
|
+
insert: mentionInsert
|
|
31738
|
+
};
|
|
30970
31739
|
this.annotatable = false;
|
|
30971
31740
|
this.annotations = [];
|
|
30972
31741
|
this.translations = {};
|
|
@@ -30977,6 +31746,7 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
30977
31746
|
this._historyCompartment = new Compartment();
|
|
30978
31747
|
this.invalid = false;
|
|
30979
31748
|
this._cutBuffer = null;
|
|
31749
|
+
this._lastState = null;
|
|
30980
31750
|
this._onScrollerPointerDown = (event) => {
|
|
30981
31751
|
if (event.target !== this.view?.scrollDOM) return;
|
|
30982
31752
|
if (this.view.state.readOnly) return;
|
|
@@ -31029,7 +31799,7 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31029
31799
|
return [
|
|
31030
31800
|
nlddCodeMirrorTheme,
|
|
31031
31801
|
markdownEditing,
|
|
31032
|
-
|
|
31802
|
+
typeaheads(() => this._typeaheadLists(), (choice) => this._onTypeaheadChosen(choice)),
|
|
31033
31803
|
Prec.low(orderedListRenumber),
|
|
31034
31804
|
annotations((count, quote) => this._t("components.text-editor.annotation-count-label", {
|
|
31035
31805
|
count,
|
|
@@ -31039,6 +31809,7 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31039
31809
|
Prec.highest(linkOpenBadge((url) => this._t("components.text-editor.open-in-new-tab-label", { url }))),
|
|
31040
31810
|
this._historyCompartment.of(history()),
|
|
31041
31811
|
drawSelection(),
|
|
31812
|
+
stableCursor,
|
|
31042
31813
|
dropCursor(),
|
|
31043
31814
|
dragToMove,
|
|
31044
31815
|
Prec.highest(keymap.of([{
|
|
@@ -31082,6 +31853,20 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31082
31853
|
key: "Delete",
|
|
31083
31854
|
run: (view) => this._selectMentionBeforeDelete(view, 1)
|
|
31084
31855
|
},
|
|
31856
|
+
{
|
|
31857
|
+
key: "Mod-]",
|
|
31858
|
+
run: (view) => {
|
|
31859
|
+
indentListItems(view);
|
|
31860
|
+
return true;
|
|
31861
|
+
}
|
|
31862
|
+
},
|
|
31863
|
+
{
|
|
31864
|
+
key: "Mod-[",
|
|
31865
|
+
run: (view) => {
|
|
31866
|
+
outdentListItems(view);
|
|
31867
|
+
return true;
|
|
31868
|
+
}
|
|
31869
|
+
},
|
|
31085
31870
|
...defaultKeymap,
|
|
31086
31871
|
...historyKeymap
|
|
31087
31872
|
]),
|
|
@@ -31097,7 +31882,8 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31097
31882
|
focus: () => {
|
|
31098
31883
|
this._valueAtFocus = this.value;
|
|
31099
31884
|
},
|
|
31100
|
-
blur: () => {
|
|
31885
|
+
blur: (_event, view) => {
|
|
31886
|
+
repairHeldEmphasis(view);
|
|
31101
31887
|
if (this.value !== this._valueAtFocus) this._emitChange();
|
|
31102
31888
|
},
|
|
31103
31889
|
mousedown: (event, view) => {
|
|
@@ -31154,7 +31940,7 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31154
31940
|
firstUpdated() {
|
|
31155
31941
|
this._initialValue = this.value;
|
|
31156
31942
|
this.style.setProperty("--_rows", String(this.rows));
|
|
31157
|
-
this.mountEditor(this.value);
|
|
31943
|
+
this.mountEditor(stripSentinels(this.value));
|
|
31158
31944
|
this.onEditorMounted();
|
|
31159
31945
|
}
|
|
31160
31946
|
onEditorMounted() {
|
|
@@ -31170,7 +31956,7 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31170
31956
|
if (changed.has("rows")) this.style.setProperty("--_rows", String(this.rows));
|
|
31171
31957
|
if (this.view) {
|
|
31172
31958
|
if (changed.has("value")) {
|
|
31173
|
-
if (stripSentinels(this.doc) !== this.value) this.setDoc(this.value);
|
|
31959
|
+
if (stripSentinels(this.doc) !== this.value) this.setDoc(stripSentinels(this.value));
|
|
31174
31960
|
this.commitFormValue();
|
|
31175
31961
|
}
|
|
31176
31962
|
if (changed.has("disabled") || changed.has("readonly")) this.reconfigure(this._editableCompartment, this._editableExtension());
|
|
@@ -31221,8 +32007,14 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31221
32007
|
toggleBulletList() {
|
|
31222
32008
|
if (this.view) toggleBulletList(this.view);
|
|
31223
32009
|
}
|
|
32010
|
+
/** Turn the selected lines into GFM task items (`- [ ] `), or back into
|
|
32011
|
+
* bullets when they all are tasks. Checking a box is not a command. */
|
|
32012
|
+
toggleTaskList() {
|
|
32013
|
+
if (this.view) toggleTaskList(this.view);
|
|
32014
|
+
}
|
|
31224
32015
|
/** Set the list type, replacing any existing list ('none' strips it) — for an
|
|
31225
|
-
* exclusive list picker.
|
|
32016
|
+
* exclusive list picker. A task keeps its checkbox only within its own type:
|
|
32017
|
+
* switching to bullet or ordered takes the box along with the marker. */
|
|
31226
32018
|
setList(type) {
|
|
31227
32019
|
if (this.view) setList(this.view, type);
|
|
31228
32020
|
}
|
|
@@ -31331,6 +32123,45 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31331
32123
|
this._pasteText(stripSentinels(raw));
|
|
31332
32124
|
this.view?.focus();
|
|
31333
32125
|
}
|
|
32126
|
+
/** Puts `text` at the caret, in place of the selection when there is one, and
|
|
32127
|
+
* leaves the caret after it, with focus on the editor. Plain text: markdown
|
|
32128
|
+
* in it stays as written and is styled like anything typed. Does nothing on
|
|
32129
|
+
* a read-only editor. */
|
|
32130
|
+
insertAtCursor(text) {
|
|
32131
|
+
if (!this.view || this.view.state.readOnly) return;
|
|
32132
|
+
const clean = stripSentinels(text);
|
|
32133
|
+
if (clean) this.view.dispatch({
|
|
32134
|
+
...this.view.state.replaceSelection(clean),
|
|
32135
|
+
userEvent: "input"
|
|
32136
|
+
});
|
|
32137
|
+
this.view.focus();
|
|
32138
|
+
}
|
|
32139
|
+
/** Replaces the text between two offsets with `text`, and leaves the caret
|
|
32140
|
+
* after it. The offsets are CLEAN, the same coordinates `getSelection()` and
|
|
32141
|
+
* the annotations speak, so a consumer can act on what it read there. Both
|
|
32142
|
+
* are clamped into the text, and `to` below `from` counts as an insert at
|
|
32143
|
+
* `from`. Does nothing on a read-only editor. */
|
|
32144
|
+
replaceRange(from, to, text) {
|
|
32145
|
+
if (!this.view || this.view.state.readOnly) return;
|
|
32146
|
+
const doc = this.view.state.doc.toString();
|
|
32147
|
+
const sentinels = sentinelPositions(doc);
|
|
32148
|
+
const cleanLength = doc.length - sentinels.length;
|
|
32149
|
+
const start = Math.max(0, Math.min(from, cleanLength));
|
|
32150
|
+
const end = Math.max(start, Math.min(to, cleanLength));
|
|
32151
|
+
const insert = stripSentinels(text);
|
|
32152
|
+
const docFrom = cleanToDoc(sentinels, start);
|
|
32153
|
+
const docTo = cleanToDoc(sentinels, end);
|
|
32154
|
+
this.view.dispatch({
|
|
32155
|
+
changes: {
|
|
32156
|
+
from: docFrom,
|
|
32157
|
+
to: docTo,
|
|
32158
|
+
insert
|
|
32159
|
+
},
|
|
32160
|
+
selection: { anchor: docFrom + insert.length },
|
|
32161
|
+
userEvent: "input"
|
|
32162
|
+
});
|
|
32163
|
+
this.view.focus();
|
|
32164
|
+
}
|
|
31334
32165
|
/** Insert `text` at the selection, re-attaching the cut annotations when it matches
|
|
31335
32166
|
* a cut made in this editor (a move, one-shot). Shared by the toolbar's paste()
|
|
31336
32167
|
* and the native Cmd/Ctrl+V handler. */
|
|
@@ -31340,7 +32171,10 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31340
32171
|
const sameText = (a, b) => a.replace(/\r\n/g, "\n") === b.replace(/\r\n/g, "\n");
|
|
31341
32172
|
const carry = !!(buffer && sameText(buffer.text, text) && buffer.anns.length > 0);
|
|
31342
32173
|
const at = docToClean(this.view.state.doc.toString(), this.view.state.selection.main.from);
|
|
31343
|
-
const spec =
|
|
32174
|
+
const spec = {
|
|
32175
|
+
...this.view.state.replaceSelection(text),
|
|
32176
|
+
userEvent: "input.paste"
|
|
32177
|
+
};
|
|
31344
32178
|
this.view.dispatch(carry ? {
|
|
31345
32179
|
...spec,
|
|
31346
32180
|
effects: pasteAnnotations.of({
|
|
@@ -31350,10 +32184,20 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31350
32184
|
} : spec);
|
|
31351
32185
|
if (carry) this._cutBuffer = null;
|
|
31352
32186
|
}
|
|
31353
|
-
/** Escape hatch: run a command by name
|
|
31354
|
-
*
|
|
31355
|
-
*
|
|
32187
|
+
/** Escape hatch: run a command by name, so a toolbar can carry the name in its
|
|
32188
|
+
* markup instead of a method reference. Every method above is reachable.
|
|
32189
|
+
*
|
|
32190
|
+
* Toggles (no payload): `bold`, `italic`, `inlineCode`, `strikethrough`,
|
|
32191
|
+
* `bulletList`, `taskList`, `quote`, `codeBlock`, `heading` (payload: the
|
|
32192
|
+
* level, default 1), `link` (payload: the href).
|
|
32193
|
+
* Setters: `setHeading` (payload: the level, 0 for a paragraph), `setList`
|
|
32194
|
+
* (payload: 'none' | 'bullet' | 'ordered' | 'task').
|
|
32195
|
+
* The rest: `indent`, `outdent`, `undo`, `redo`, `copy`, `cut`, `paste`.
|
|
32196
|
+
*
|
|
32197
|
+
* An unknown name warns rather than doing nothing quietly: a typo in a
|
|
32198
|
+
* toolbar is otherwise invisible. */
|
|
31356
32199
|
runCommand(name, payload) {
|
|
32200
|
+
const level = (fallback) => typeof payload === "number" ? payload : fallback;
|
|
31357
32201
|
switch (name) {
|
|
31358
32202
|
case "bold":
|
|
31359
32203
|
this.toggleBold();
|
|
@@ -31370,22 +32214,49 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31370
32214
|
case "bulletList":
|
|
31371
32215
|
this.toggleBulletList();
|
|
31372
32216
|
break;
|
|
32217
|
+
case "taskList":
|
|
32218
|
+
this.toggleTaskList();
|
|
32219
|
+
break;
|
|
31373
32220
|
case "quote":
|
|
31374
32221
|
this.toggleQuote();
|
|
31375
32222
|
break;
|
|
32223
|
+
case "codeBlock":
|
|
32224
|
+
this.toggleCodeBlock();
|
|
32225
|
+
break;
|
|
31376
32226
|
case "heading":
|
|
31377
|
-
this.toggleHeading(
|
|
32227
|
+
this.toggleHeading(level(1));
|
|
32228
|
+
break;
|
|
32229
|
+
case "setHeading":
|
|
32230
|
+
this.setHeading(level(0));
|
|
32231
|
+
break;
|
|
32232
|
+
case "setList":
|
|
32233
|
+
this.setList(typeof payload === "string" ? payload : "none");
|
|
31378
32234
|
break;
|
|
31379
32235
|
case "link":
|
|
31380
32236
|
this.toggleLink(typeof payload === "string" ? payload : "");
|
|
31381
32237
|
break;
|
|
32238
|
+
case "indent":
|
|
32239
|
+
this.indent();
|
|
32240
|
+
break;
|
|
32241
|
+
case "outdent":
|
|
32242
|
+
this.outdent();
|
|
32243
|
+
break;
|
|
32244
|
+
case "undo":
|
|
32245
|
+
this.undo();
|
|
32246
|
+
break;
|
|
32247
|
+
case "redo":
|
|
32248
|
+
this.redo();
|
|
32249
|
+
break;
|
|
31382
32250
|
case "copy":
|
|
31383
32251
|
this.copy();
|
|
31384
32252
|
break;
|
|
31385
32253
|
case "cut":
|
|
31386
32254
|
this.cut();
|
|
31387
32255
|
break;
|
|
31388
|
-
case "paste":
|
|
32256
|
+
case "paste":
|
|
32257
|
+
this.paste();
|
|
32258
|
+
break;
|
|
32259
|
+
default: console.warn(`<nldd-text-editor>: runCommand('${name}') is not a command.`);
|
|
31389
32260
|
}
|
|
31390
32261
|
}
|
|
31391
32262
|
/** The formats active at the current selection (drives a toolbar's state). */
|
|
@@ -31451,8 +32322,43 @@ var NLDDTextEditor = (_NLDDTextEditor = class NLDDTextEditor extends DescribedBy
|
|
|
31451
32322
|
}));
|
|
31452
32323
|
}
|
|
31453
32324
|
_emitState() {
|
|
32325
|
+
const state = this.getState();
|
|
32326
|
+
const last = this._lastState;
|
|
32327
|
+
if (last && last.empty === state.empty && last.canIndent === state.canIndent && last.canOutdent === state.canOutdent && last.canUndo === state.canUndo && last.canRedo === state.canRedo && Object.keys(state.active).every((key) => last.active[key] === state.active[key])) return;
|
|
32328
|
+
this._lastState = state;
|
|
31454
32329
|
this.dispatchEvent(new CustomEvent("nldd-text-editor-state", {
|
|
31455
|
-
detail:
|
|
32330
|
+
detail: state,
|
|
32331
|
+
bubbles: true,
|
|
32332
|
+
composed: true
|
|
32333
|
+
}));
|
|
32334
|
+
}
|
|
32335
|
+
_typeaheadLists() {
|
|
32336
|
+
return this.mentionSource ? [this._mentionTypeahead, ...this.typeaheads] : this.typeaheads;
|
|
32337
|
+
}
|
|
32338
|
+
/** A choice from any list. Offsets in the events are clean, like
|
|
32339
|
+
* getSelection() and the annotations: the document carries sentinels the
|
|
32340
|
+
* value never shows. */
|
|
32341
|
+
_onTypeaheadChosen(choice) {
|
|
32342
|
+
if (!this.view) return;
|
|
32343
|
+
const doc = this.view.state.doc.toString();
|
|
32344
|
+
const from = docToClean(doc, choice.from);
|
|
32345
|
+
if (choice.typeahead === this._mentionTypeahead) {
|
|
32346
|
+
const { id, text } = choice.candidate;
|
|
32347
|
+
this._emitMention({
|
|
32348
|
+
id,
|
|
32349
|
+
text,
|
|
32350
|
+
from,
|
|
32351
|
+
to: from + mentionToken(choice.candidate).length
|
|
32352
|
+
});
|
|
32353
|
+
return;
|
|
32354
|
+
}
|
|
32355
|
+
this.dispatchEvent(new CustomEvent("nldd-text-editor-typeahead", {
|
|
32356
|
+
detail: {
|
|
32357
|
+
trigger: choice.trigger,
|
|
32358
|
+
candidate: choice.candidate,
|
|
32359
|
+
from,
|
|
32360
|
+
to: docToClean(doc, choice.to)
|
|
32361
|
+
},
|
|
31456
32362
|
bubbles: true,
|
|
31457
32363
|
composed: true
|
|
31458
32364
|
}));
|
|
@@ -31552,6 +32458,7 @@ __decorate([property({
|
|
|
31552
32458
|
attribute: "accessible-label"
|
|
31553
32459
|
})], NLDDTextEditor.prototype, "accessibleLabel", void 0);
|
|
31554
32460
|
__decorate([property({ attribute: false })], NLDDTextEditor.prototype, "mentionSource", void 0);
|
|
32461
|
+
__decorate([property({ attribute: false })], NLDDTextEditor.prototype, "typeaheads", void 0);
|
|
31555
32462
|
__decorate([property({
|
|
31556
32463
|
type: Boolean,
|
|
31557
32464
|
reflect: true
|
|
@@ -40160,10 +41067,6 @@ var sheetStyles = css`
|
|
|
40160
41067
|
background: var(--semantics-overlays-backdrop-color);
|
|
40161
41068
|
}
|
|
40162
41069
|
|
|
40163
|
-
:host([modeless]) .sheet::backdrop {
|
|
40164
|
-
background: transparent;
|
|
40165
|
-
}
|
|
40166
|
-
|
|
40167
41070
|
:host([placement="left"]) .sheet {
|
|
40168
41071
|
@media (min-width: ${mdMin$4}) {
|
|
40169
41072
|
inset: var(--semantics-overlays-inset) auto var(--semantics-overlays-inset) var(--semantics-overlays-inset);
|
|
@@ -40243,7 +41146,7 @@ function sheetTemplate(component) {
|
|
|
40243
41146
|
return html`
|
|
40244
41147
|
<dialog class="sheet"
|
|
40245
41148
|
aria-label=${component.accessibleLabel}
|
|
40246
|
-
aria-modal
|
|
41149
|
+
aria-modal="true"
|
|
40247
41150
|
@pointerdown=${component._handleDialogPointerDown}
|
|
40248
41151
|
@click=${component._handleDialogClick}
|
|
40249
41152
|
@cancel=${component._handleCancel}
|
|
@@ -40356,7 +41259,6 @@ function openWhenRendered(host, getDialog, open) {
|
|
|
40356
41259
|
*
|
|
40357
41260
|
* @attr {string} placement - Sheet position: 'left' | 'right' | 'bottom' (default: 'right')
|
|
40358
41261
|
* @attr {string} height - Custom height for bottom sheets (and for any sheet on sm viewports, where all placements collapse to bottom). Accepts: `'full'` (default — viewport minus top-inset, identical to omitting the attribute), `'fit-content'` (collapse to content size), or any CSS length/percentage (e.g. `'50dvh'`, `'480px'`, `'50%'`). Always clamped to `100dvh - top-inset` so the sheet can't extend past the dismiss-tap area. No effect on side sheets at md+.
|
|
40359
|
-
* @attr {boolean} modeless - Non-modal (no backdrop or focus lock); the sheet is modal by default
|
|
40360
41262
|
* @attr {string} accessible-label - Accessible name for the dialog, forwarded as aria-label (default: 'Venster')
|
|
40361
41263
|
* @attr {string} width - Custom width for side sheets (left/right) as a CSS length (e.g. '480px', '32rem'). Applied from the md breakpoint up; ignored on sm (bottom sheet) and for `placement="bottom"`. Clamped to `100vw - 2 * inset` so the sheet always fits.
|
|
40362
41264
|
*
|
|
@@ -40379,7 +41281,6 @@ var NLDDSheet = (_NLDDSheet = class NLDDSheet extends LitElement {
|
|
|
40379
41281
|
super(..._args);
|
|
40380
41282
|
this.placement = "right";
|
|
40381
41283
|
this.height = "";
|
|
40382
|
-
this.modeless = false;
|
|
40383
41284
|
this.accessibleLabel = "Venster";
|
|
40384
41285
|
this.width = "";
|
|
40385
41286
|
this._hasWarnedLabel = false;
|
|
@@ -40430,8 +41331,7 @@ var NLDDSheet = (_NLDDSheet = class NLDDSheet extends LitElement {
|
|
|
40430
41331
|
this._cancelPendingOpen?.();
|
|
40431
41332
|
this._cancelPendingOpen = null;
|
|
40432
41333
|
this._closeEmitted = false;
|
|
40433
|
-
|
|
40434
|
-
else dialog.showModal();
|
|
41334
|
+
dialog.showModal();
|
|
40435
41335
|
this._manageFocus();
|
|
40436
41336
|
this.dispatchEvent(new CustomEvent("open", {
|
|
40437
41337
|
bubbles: true,
|
|
@@ -40470,7 +41370,6 @@ var NLDDSheet = (_NLDDSheet = class NLDDSheet extends LitElement {
|
|
|
40470
41370
|
this._pointerDownOnBackdrop = e.target === this._dialog;
|
|
40471
41371
|
}
|
|
40472
41372
|
_handleDialogClick(e) {
|
|
40473
|
-
if (this.modeless) return;
|
|
40474
41373
|
if (e.target === this._dialog && this._pointerDownOnBackdrop) this.hide();
|
|
40475
41374
|
}
|
|
40476
41375
|
_emitClose() {
|
|
@@ -40503,10 +41402,6 @@ __decorate([property({
|
|
|
40503
41402
|
type: String,
|
|
40504
41403
|
reflect: true
|
|
40505
41404
|
})], NLDDSheet.prototype, "height", void 0);
|
|
40506
|
-
__decorate([property({
|
|
40507
|
-
type: Boolean,
|
|
40508
|
-
reflect: true
|
|
40509
|
-
})], NLDDSheet.prototype, "modeless", void 0);
|
|
40510
41405
|
__decorate([property({
|
|
40511
41406
|
type: String,
|
|
40512
41407
|
attribute: "accessible-label"
|
|
@@ -41707,7 +42602,7 @@ function windowTemplate(component) {
|
|
|
41707
42602
|
return html`
|
|
41708
42603
|
<dialog class="window"
|
|
41709
42604
|
aria-label=${component._resolvedAccessibleLabel}
|
|
41710
|
-
aria-modal
|
|
42605
|
+
aria-modal="true"
|
|
41711
42606
|
@pointerdown=${component._handleDialogPointerDown}
|
|
41712
42607
|
@click=${component._handleDialogClick}
|
|
41713
42608
|
@cancel=${component._handleCancel}
|
|
@@ -41727,15 +42622,14 @@ var nlddWindowTranslations = { "components.window.accessible-label": "Venster" }
|
|
|
41727
42622
|
/**
|
|
41728
42623
|
* Nederlandse Digitale Dienst Window Component (Lit + TypeScript)
|
|
41729
42624
|
*
|
|
41730
|
-
* A floating window based on the native <dialog> element
|
|
41731
|
-
*
|
|
42625
|
+
* A floating window based on the native <dialog> element, positionable through
|
|
42626
|
+
* CSS values. Always modal.
|
|
41732
42627
|
*
|
|
41733
42628
|
* No header of its own: consumers use nldd-page with a sticky header inside for
|
|
41734
42629
|
* a title bar.
|
|
41735
42630
|
*
|
|
41736
42631
|
* @element nldd-window
|
|
41737
42632
|
*
|
|
41738
|
-
* @attr {boolean} modeless - Modeless (no backdrop or focus trap); the window is modal by default
|
|
41739
42633
|
* @attr {boolean} no-light-dismiss - A click on the backdrop does not close the window. For windows where dismissing by accident costs work: a wizard, a form with filled-in fields. Escape and the dismiss button keep working.
|
|
41740
42634
|
* @attr {string} accessible-label - (required) Accessible name (aria-label). Falls back to the i18n default ('Venster') when unset. Always pass a unique, descriptive name per window.
|
|
41741
42635
|
* @attr {object} translations - Override translation keys; unset keys fall back to the Dutch default.
|
|
@@ -41760,7 +42654,6 @@ var _NLDDWindow;
|
|
|
41760
42654
|
var NLDDWindow = (_NLDDWindow = class NLDDWindow extends LitElement {
|
|
41761
42655
|
constructor(..._args) {
|
|
41762
42656
|
super(..._args);
|
|
41763
|
-
this.modeless = false;
|
|
41764
42657
|
this.noLightDismiss = false;
|
|
41765
42658
|
this.accessibleLabel = "";
|
|
41766
42659
|
this.translations = {};
|
|
@@ -41779,7 +42672,7 @@ var NLDDWindow = (_NLDDWindow = class NLDDWindow extends LitElement {
|
|
|
41779
42672
|
this._pointerDownOnBackdrop = this._isOnBackdrop(e);
|
|
41780
42673
|
};
|
|
41781
42674
|
this._handleDialogClick = (e) => {
|
|
41782
|
-
if (this.
|
|
42675
|
+
if (this.noLightDismiss) return;
|
|
41783
42676
|
if (this._isOnBackdrop(e) && this._pointerDownOnBackdrop) this.hide();
|
|
41784
42677
|
};
|
|
41785
42678
|
this._handleCancel = (e) => {
|
|
@@ -41833,8 +42726,7 @@ var NLDDWindow = (_NLDDWindow = class NLDDWindow extends LitElement {
|
|
|
41833
42726
|
const dialog = this._dialog;
|
|
41834
42727
|
if (!dialog) return;
|
|
41835
42728
|
this._closeEmitted = false;
|
|
41836
|
-
|
|
41837
|
-
else dialog.showModal();
|
|
42729
|
+
dialog.showModal();
|
|
41838
42730
|
this._applyPositionStyles();
|
|
41839
42731
|
this._manageFocus();
|
|
41840
42732
|
this.dispatchEvent(new CustomEvent("open", {
|
|
@@ -41896,10 +42788,6 @@ var NLDDWindow = (_NLDDWindow = class NLDDWindow extends LitElement {
|
|
|
41896
42788
|
return windowTemplate(this);
|
|
41897
42789
|
}
|
|
41898
42790
|
}, _NLDDWindow.styles = windowStyles, _NLDDWindow);
|
|
41899
|
-
__decorate([property({
|
|
41900
|
-
type: Boolean,
|
|
41901
|
-
reflect: true
|
|
41902
|
-
})], NLDDWindow.prototype, "modeless", void 0);
|
|
41903
42791
|
__decorate([property({
|
|
41904
42792
|
type: Boolean,
|
|
41905
42793
|
reflect: true,
|
|
@@ -43436,7 +44324,7 @@ var template$8 = function() {
|
|
|
43436
44324
|
*
|
|
43437
44325
|
* @element nldd-title-cell
|
|
43438
44326
|
* @attr {1|2|3|4|5|6} size - Visual size of the title (default: 5)
|
|
43439
|
-
* @attr {'
|
|
44327
|
+
* @attr {'content' | 'secondary' | 'accent' | 'success' | 'warning' | 'critical'} color - Text color variant (default: 'content'). `secondary` demotes the title to match the muted overline/supporting-text. `accent`, `success`, `warning` and `critical` tint all three regions so the cell reads as a coherent state.
|
|
43440
44328
|
* @attr {string} width - 'full' | 'fit-content' | CSS length (e.g. '200px', '20rem'). Default: 'full'
|
|
43441
44329
|
* @attr {string} min-width - Minimum width as CSS length (e.g. '80px', '5rem')
|
|
43442
44330
|
* @attr {string} max-width - Maximum width as CSS length (e.g. '300px', '20rem')
|
|
@@ -43473,7 +44361,7 @@ var NLDDTitleCell = (_NLDDTitleCell = class NLDDTitleCell extends VisibilityMixi
|
|
|
43473
44361
|
constructor(..._args) {
|
|
43474
44362
|
super(..._args);
|
|
43475
44363
|
this.size = 5;
|
|
43476
|
-
this.color = "
|
|
44364
|
+
this.color = "content";
|
|
43477
44365
|
this.width = "full";
|
|
43478
44366
|
this.horizontalAlignment = "left";
|
|
43479
44367
|
this.verticalAlignment = "center";
|
|
@@ -43531,7 +44419,7 @@ __decorate([property({
|
|
|
43531
44419
|
})], NLDDTitleCell.prototype, "size", void 0);
|
|
43532
44420
|
__decorate([property({
|
|
43533
44421
|
reflect: true,
|
|
43534
|
-
converter: reflectNonDefault("
|
|
44422
|
+
converter: reflectNonDefault("content")
|
|
43535
44423
|
})], NLDDTitleCell.prototype, "color", void 0);
|
|
43536
44424
|
__decorate([property({
|
|
43537
44425
|
reflect: true,
|
|
@@ -45437,7 +46325,7 @@ var nlddLinkTranslations = { "components.link.opens-in-new-tab-label": "Opent in
|
|
|
45437
46325
|
* @attr {string} href - Link target
|
|
45438
46326
|
* @attr {string} target - Link target (e.g. '_blank'); adjusts rel automatically. With '_blank' the link adds a visually hidden "Opent in nieuw tabblad" announcement for screen readers (WCAG 2.1 SC 3.2.2).
|
|
45439
46327
|
* @attr {string} rel - Link rel attribute; defaults to 'noopener noreferrer' with target='_blank'
|
|
45440
|
-
* @attr {string} size - Text size: 'xs' | 'sm' | 'md' | 'lg'
|
|
46328
|
+
* @attr {string} size - Text size: 'inherit' (the default) follows the surrounding text and lays the link out inline, so it wraps in running prose. 'xs' | 'sm' | 'md' | 'lg' pin a size and switch to inline-flex, which baseline-aligns a start or end icon with an explicit gap.
|
|
45441
46329
|
* @attr {string} text - Link text (alternative to the default slot)
|
|
45442
46330
|
* @attr {string} start-icon - Icon before the text
|
|
45443
46331
|
* @attr {string} end-icon - Icon after the text
|
|
@@ -45457,6 +46345,7 @@ var NLDDLink = (_NLDDLink = class NLDDLink extends withTranslations(LitElement,
|
|
|
45457
46345
|
this.href = void 0;
|
|
45458
46346
|
this.target = void 0;
|
|
45459
46347
|
this.rel = void 0;
|
|
46348
|
+
this.size = "inherit";
|
|
45460
46349
|
this.text = "";
|
|
45461
46350
|
this.startIcon = "";
|
|
45462
46351
|
this.endIcon = "";
|
|
@@ -45490,8 +46379,8 @@ __decorate([property({
|
|
|
45490
46379
|
__decorate([property({ type: String })], NLDDLink.prototype, "target", void 0);
|
|
45491
46380
|
__decorate([property({ type: String })], NLDDLink.prototype, "rel", void 0);
|
|
45492
46381
|
__decorate([property({
|
|
45493
|
-
|
|
45494
|
-
|
|
46382
|
+
reflect: true,
|
|
46383
|
+
converter: reflectNonDefault("inherit")
|
|
45495
46384
|
})], NLDDLink.prototype, "size", void 0);
|
|
45496
46385
|
__decorate([property({
|
|
45497
46386
|
reflect: true,
|
|
@@ -46447,7 +47336,7 @@ var NLDDTopNavigationBar = (_NLDDTopNavigationBar = class NLDDTopNavigationBar e
|
|
|
46447
47336
|
Promise.resolve().then(() => list_item_exports),
|
|
46448
47337
|
Promise.resolve().then(() => text_cell_exports),
|
|
46449
47338
|
Promise.resolve().then(() => icon_cell_exports),
|
|
46450
|
-
import("./icon-
|
|
47339
|
+
import("./icon-C_zwJZ_g.js").then((n) => n.n)
|
|
46451
47340
|
]);
|
|
46452
47341
|
}
|
|
46453
47342
|
_createGlobalMenuSheet() {
|
|
@@ -47748,7 +48637,7 @@ function documentTabBarItemTemplate(component) {
|
|
|
47748
48637
|
@click=${component._handleClick}
|
|
47749
48638
|
>${tabContent}</button>`;
|
|
47750
48639
|
return html`
|
|
47751
|
-
<nldd-tooltip text=${tooltipText} timing=${component._isShort ? "
|
|
48640
|
+
<nldd-tooltip text=${tooltipText} timing=${component._isShort ? "delay" : "never"}>
|
|
47752
48641
|
<div class="document-tab-bar__item">
|
|
47753
48642
|
${tab}
|
|
47754
48643
|
<button class="document-tab-bar__item-dismiss-button"
|
|
@@ -49097,6 +49986,7 @@ function modalDialogTemplate(component) {
|
|
|
49097
49986
|
icon=${component.icon || nothing}
|
|
49098
49987
|
text=${component.text || nothing}
|
|
49099
49988
|
supporting-text=${component.supportingText || nothing}
|
|
49989
|
+
horizontal-alignment=${component.horizontalAlignment || nothing}
|
|
49100
49990
|
heading-level="2"
|
|
49101
49991
|
>
|
|
49102
49992
|
<slot></slot>
|
|
@@ -49119,6 +50009,7 @@ function modalDialogTemplate(component) {
|
|
|
49119
50009
|
* @attr {string} icon - Forwarded to nldd-inline-dialog; absent when not set
|
|
49120
50010
|
* @attr {string} text - Forwarded to nldd-inline-dialog; main text
|
|
49121
50011
|
* @attr {string} supporting-text - Forwarded to nldd-inline-dialog; supporting text
|
|
50012
|
+
* @attr {'left'|'center'} horizontal-alignment - Forwarded to nldd-inline-dialog. Unset derives it there: slotted content aligns left, a bare message stays centered.
|
|
49122
50013
|
* @attr {string} accessible-label - Accessible name for the dialog (aria-label); falls back to text
|
|
49123
50014
|
*
|
|
49124
50015
|
* @slot - Optional custom content, forwarded to nldd-inline-dialog
|
|
@@ -49142,6 +50033,7 @@ var NLDDModalDialog = (_NLDDModalDialog = class NLDDModalDialog extends LitEleme
|
|
|
49142
50033
|
this.icon = "";
|
|
49143
50034
|
this.text = "";
|
|
49144
50035
|
this.supportingText = "";
|
|
50036
|
+
this.horizontalAlignment = "";
|
|
49145
50037
|
this.accessibleLabel = "";
|
|
49146
50038
|
this._closing = false;
|
|
49147
50039
|
this._cancelPendingOpen = null;
|
|
@@ -49242,6 +50134,11 @@ __decorate([property({
|
|
|
49242
50134
|
attribute: "supporting-text",
|
|
49243
50135
|
converter: reflectNonDefault("")
|
|
49244
50136
|
})], NLDDModalDialog.prototype, "supportingText", void 0);
|
|
50137
|
+
__decorate([property({
|
|
50138
|
+
reflect: true,
|
|
50139
|
+
attribute: "horizontal-alignment",
|
|
50140
|
+
converter: reflectNonDefault("")
|
|
50141
|
+
})], NLDDModalDialog.prototype, "horizontalAlignment", void 0);
|
|
49245
50142
|
__decorate([property({
|
|
49246
50143
|
type: String,
|
|
49247
50144
|
attribute: "accessible-label"
|