@dxos/react-ui-editor 0.5.9-main.17d92ec → 0.5.9-main.1c50f63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +108 -19
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/linkPaste.d.ts +15 -0
- package/dist/types/src/extensions/markdown/linkPaste.d.ts.map +1 -0
- package/package.json +25 -25
- package/src/extensions/markdown/bundle.ts +3 -0
- package/src/extensions/markdown/highlight.ts +1 -18
- package/src/extensions/markdown/linkPaste.ts +104 -0
|
@@ -3588,13 +3588,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
3588
3588
|
tag: tags.strikethrough,
|
|
3589
3589
|
class: strikethrough
|
|
3590
3590
|
},
|
|
3591
|
-
// Naked URLs.
|
|
3592
|
-
{
|
|
3593
|
-
tag: [
|
|
3594
|
-
markdownTags.URL
|
|
3595
|
-
],
|
|
3596
|
-
class: inlineUrl
|
|
3597
|
-
},
|
|
3598
3591
|
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
3599
3592
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
3600
3593
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
@@ -3627,6 +3620,101 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
3627
3620
|
});
|
|
3628
3621
|
};
|
|
3629
3622
|
|
|
3623
|
+
// packages/ui/react-ui-editor/src/extensions/markdown/linkPaste.ts
|
|
3624
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
3625
|
+
import { Transaction } from "@codemirror/state";
|
|
3626
|
+
import { ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
3627
|
+
var VALID_PROTOCOLS = [
|
|
3628
|
+
"http:",
|
|
3629
|
+
"https:",
|
|
3630
|
+
"mailto:",
|
|
3631
|
+
"tel:"
|
|
3632
|
+
];
|
|
3633
|
+
var createTextLink = (text, url) => `[${text}](${url})`;
|
|
3634
|
+
var createUrlLink = (url) => {
|
|
3635
|
+
const displayUrl = formatUrlForDisplay(url);
|
|
3636
|
+
return `[${displayUrl}](${url})`;
|
|
3637
|
+
};
|
|
3638
|
+
var formatUrlForDisplay = (url) => {
|
|
3639
|
+
const withoutProtocol = url.replace(/^https?:\/\//, "");
|
|
3640
|
+
return truncateQueryParams(withoutProtocol);
|
|
3641
|
+
};
|
|
3642
|
+
var truncateQueryParams = (url, maxQueryLength = 15) => {
|
|
3643
|
+
const [urlBase, queryString] = url.split("?");
|
|
3644
|
+
if (!queryString) {
|
|
3645
|
+
return urlBase;
|
|
3646
|
+
}
|
|
3647
|
+
if (queryString.length > maxQueryLength) {
|
|
3648
|
+
const truncatedQuery = queryString.slice(0, maxQueryLength) + "...";
|
|
3649
|
+
return `${urlBase}?${truncatedQuery}`;
|
|
3650
|
+
} else {
|
|
3651
|
+
return `${urlBase}?${queryString}`;
|
|
3652
|
+
}
|
|
3653
|
+
};
|
|
3654
|
+
var isValidUrl = (str) => {
|
|
3655
|
+
try {
|
|
3656
|
+
const url = new URL(str);
|
|
3657
|
+
return VALID_PROTOCOLS.includes(url.protocol);
|
|
3658
|
+
} catch (e) {
|
|
3659
|
+
return false;
|
|
3660
|
+
}
|
|
3661
|
+
};
|
|
3662
|
+
var onNextUpdate = (callback) => setTimeout(callback, 0);
|
|
3663
|
+
var linkPastePlugin = ViewPlugin4.fromClass(class {
|
|
3664
|
+
constructor(view) {
|
|
3665
|
+
this.view = view;
|
|
3666
|
+
}
|
|
3667
|
+
update(update2) {
|
|
3668
|
+
for (const tr of update2.transactions) {
|
|
3669
|
+
const event = tr.annotation(Transaction.userEvent);
|
|
3670
|
+
if (event === "input.paste") {
|
|
3671
|
+
this.handleInputRead(this.view, tr);
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
handleInputRead(view, tr) {
|
|
3676
|
+
const changes = tr.changes;
|
|
3677
|
+
if (changes.empty) {
|
|
3678
|
+
return;
|
|
3679
|
+
}
|
|
3680
|
+
changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
3681
|
+
const insertedText = view.state.sliceDoc(fromB, toB);
|
|
3682
|
+
if (isValidUrl(insertedText) && !this.isInCodeBlock(view.state, fromB)) {
|
|
3683
|
+
const replacedText = tr.startState.sliceDoc(fromA, toA);
|
|
3684
|
+
onNextUpdate(() => {
|
|
3685
|
+
view.dispatch(this.createLinkTransaction(view.state, fromA, toB, insertedText, replacedText));
|
|
3686
|
+
});
|
|
3687
|
+
}
|
|
3688
|
+
});
|
|
3689
|
+
}
|
|
3690
|
+
/**
|
|
3691
|
+
* Determines if a given position is within a code block.
|
|
3692
|
+
* Traverses the syntax tree upwards from the position,
|
|
3693
|
+
* checking for CodeBlock or FencedCode nodes.
|
|
3694
|
+
*/
|
|
3695
|
+
isInCodeBlock(state2, pos) {
|
|
3696
|
+
const tree = syntaxTree2(state2);
|
|
3697
|
+
let node = tree.resolveInner(pos, -1);
|
|
3698
|
+
while (node) {
|
|
3699
|
+
if (node.name.includes("Code") || node.name.includes("FencedCode")) {
|
|
3700
|
+
return true;
|
|
3701
|
+
}
|
|
3702
|
+
node = node.parent;
|
|
3703
|
+
}
|
|
3704
|
+
return false;
|
|
3705
|
+
}
|
|
3706
|
+
createLinkTransaction(state2, from, to, url, text) {
|
|
3707
|
+
const linkText = text.trim() ? createTextLink(text, url) : createUrlLink(url);
|
|
3708
|
+
return state2.update({
|
|
3709
|
+
changes: {
|
|
3710
|
+
from,
|
|
3711
|
+
to,
|
|
3712
|
+
insert: linkText
|
|
3713
|
+
}
|
|
3714
|
+
});
|
|
3715
|
+
}
|
|
3716
|
+
});
|
|
3717
|
+
|
|
3630
3718
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
3631
3719
|
var createMarkdownExtensions = ({ themeMode } = {}) => {
|
|
3632
3720
|
return [
|
|
@@ -3652,6 +3740,7 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
|
|
|
3652
3740
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
|
|
3653
3741
|
// Custom styles.
|
|
3654
3742
|
syntaxHighlighting(markdownHighlightStyle()),
|
|
3743
|
+
linkPastePlugin,
|
|
3655
3744
|
keymap7.of([
|
|
3656
3745
|
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
3657
3746
|
indentWithTab2,
|
|
@@ -3664,9 +3753,9 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
|
|
|
3664
3753
|
};
|
|
3665
3754
|
|
|
3666
3755
|
// packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
|
|
3667
|
-
import { syntaxTree as
|
|
3756
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
3668
3757
|
import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
|
|
3669
|
-
import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as
|
|
3758
|
+
import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
3670
3759
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
3671
3760
|
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
3672
3761
|
toDOM() {
|
|
@@ -3765,7 +3854,7 @@ var buildDecorations = (view, options, focus) => {
|
|
|
3765
3854
|
const atomicDeco = new RangeSetBuilder2();
|
|
3766
3855
|
const { state: state2 } = view;
|
|
3767
3856
|
for (const { from, to } of view.visibleRanges) {
|
|
3768
|
-
|
|
3857
|
+
syntaxTree3(state2).iterate({
|
|
3769
3858
|
from,
|
|
3770
3859
|
to,
|
|
3771
3860
|
enter: (node) => {
|
|
@@ -3882,7 +3971,7 @@ var buildDecorations = (view, options, focus) => {
|
|
|
3882
3971
|
var forceUpdate = StateEffect4.define();
|
|
3883
3972
|
var decorateMarkdown = (options = {}) => {
|
|
3884
3973
|
return [
|
|
3885
|
-
|
|
3974
|
+
ViewPlugin5.fromClass(class {
|
|
3886
3975
|
constructor(view) {
|
|
3887
3976
|
({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
|
|
3888
3977
|
}
|
|
@@ -3971,7 +4060,7 @@ var formattingStyles = EditorView12.baseTheme({
|
|
|
3971
4060
|
});
|
|
3972
4061
|
|
|
3973
4062
|
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
3974
|
-
import { syntaxTree as
|
|
4063
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
3975
4064
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
3976
4065
|
import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3977
4066
|
var image = (options = {}) => {
|
|
@@ -4014,7 +4103,7 @@ var preloadImage = (url) => {
|
|
|
4014
4103
|
var buildDecorations2 = (from, to, state2) => {
|
|
4015
4104
|
const decorations = [];
|
|
4016
4105
|
const cursor = state2.selection.main.head;
|
|
4017
|
-
|
|
4106
|
+
syntaxTree4(state2).iterate({
|
|
4018
4107
|
enter: (node) => {
|
|
4019
4108
|
if (node.name === "Image") {
|
|
4020
4109
|
const urlNode = node.node.getChild("URL");
|
|
@@ -4054,11 +4143,11 @@ var imageUpload = (options = {}) => {
|
|
|
4054
4143
|
};
|
|
4055
4144
|
|
|
4056
4145
|
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
4057
|
-
import { syntaxTree as
|
|
4146
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
4058
4147
|
import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
|
|
4059
4148
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
4060
4149
|
var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
|
|
4061
|
-
const syntax =
|
|
4150
|
+
const syntax = syntaxTree5(view.state).resolveInner(pos, side);
|
|
4062
4151
|
let link = null;
|
|
4063
4152
|
for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
|
|
4064
4153
|
link = node.name === "Link" ? node : null;
|
|
@@ -4088,7 +4177,7 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
|
|
|
4088
4177
|
});
|
|
4089
4178
|
|
|
4090
4179
|
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
4091
|
-
import { syntaxTree as
|
|
4180
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
4092
4181
|
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
|
|
4093
4182
|
import { Decoration as Decoration7, EditorView as EditorView14, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
4094
4183
|
var table = (options = {}) => {
|
|
@@ -4107,7 +4196,7 @@ var update = (state2, options) => {
|
|
|
4107
4196
|
const table2 = getTable();
|
|
4108
4197
|
return table2.rows?.[table2.rows.length - 1];
|
|
4109
4198
|
};
|
|
4110
|
-
|
|
4199
|
+
syntaxTree6(state2).iterate({
|
|
4111
4200
|
enter: (node) => {
|
|
4112
4201
|
switch (node.name) {
|
|
4113
4202
|
case "Table": {
|
|
@@ -4267,7 +4356,7 @@ var EditorModes = {
|
|
|
4267
4356
|
};
|
|
4268
4357
|
|
|
4269
4358
|
// packages/ui/react-ui-editor/src/extensions/state.ts
|
|
4270
|
-
import { Transaction } from "@codemirror/state";
|
|
4359
|
+
import { Transaction as Transaction2 } from "@codemirror/state";
|
|
4271
4360
|
import { EditorView as EditorView15, keymap as keymap9 } from "@codemirror/view";
|
|
4272
4361
|
import { debounce as debounce2 } from "@dxos/async";
|
|
4273
4362
|
import { invariant as invariant4 } from "@dxos/invariant";
|
|
@@ -4343,7 +4432,7 @@ var state = ({ getState, setState } = {}) => {
|
|
|
4343
4432
|
yMargin: 0
|
|
4344
4433
|
}),
|
|
4345
4434
|
selection: state2.selection,
|
|
4346
|
-
annotations:
|
|
4435
|
+
annotations: Transaction2.userEvent.of(scrollAnnotation)
|
|
4347
4436
|
});
|
|
4348
4437
|
}
|
|
4349
4438
|
return true;
|