@dxos/react-ui-editor 0.5.9-main.f099efe → 0.5.9-next.73dcc17
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 +112 -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/formatting.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/formatting.ts +4 -0
- package/src/extensions/markdown/highlight.ts +1 -18
- package/src/extensions/markdown/linkPaste.ts +104 -0
|
@@ -3163,6 +3163,10 @@ var formattingKeymap = (options = {}) => {
|
|
|
3163
3163
|
{
|
|
3164
3164
|
key: "meta-b",
|
|
3165
3165
|
run: toggleStrong
|
|
3166
|
+
},
|
|
3167
|
+
{
|
|
3168
|
+
key: "meta-i",
|
|
3169
|
+
run: toggleEmphasis
|
|
3166
3170
|
}
|
|
3167
3171
|
])
|
|
3168
3172
|
];
|
|
@@ -3584,13 +3588,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
3584
3588
|
tag: tags.strikethrough,
|
|
3585
3589
|
class: strikethrough
|
|
3586
3590
|
},
|
|
3587
|
-
// Naked URLs.
|
|
3588
|
-
{
|
|
3589
|
-
tag: [
|
|
3590
|
-
markdownTags.URL
|
|
3591
|
-
],
|
|
3592
|
-
class: inlineUrl
|
|
3593
|
-
},
|
|
3594
3591
|
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
3595
3592
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
3596
3593
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
@@ -3623,6 +3620,101 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
3623
3620
|
});
|
|
3624
3621
|
};
|
|
3625
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
|
+
|
|
3626
3718
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
3627
3719
|
var createMarkdownExtensions = ({ themeMode } = {}) => {
|
|
3628
3720
|
return [
|
|
@@ -3648,6 +3740,7 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
|
|
|
3648
3740
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
|
|
3649
3741
|
// Custom styles.
|
|
3650
3742
|
syntaxHighlighting(markdownHighlightStyle()),
|
|
3743
|
+
linkPastePlugin,
|
|
3651
3744
|
keymap7.of([
|
|
3652
3745
|
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
3653
3746
|
indentWithTab2,
|
|
@@ -3660,9 +3753,9 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
|
|
|
3660
3753
|
};
|
|
3661
3754
|
|
|
3662
3755
|
// packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
|
|
3663
|
-
import { syntaxTree as
|
|
3756
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
3664
3757
|
import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
|
|
3665
|
-
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";
|
|
3666
3759
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
3667
3760
|
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
3668
3761
|
toDOM() {
|
|
@@ -3761,7 +3854,7 @@ var buildDecorations = (view, options, focus) => {
|
|
|
3761
3854
|
const atomicDeco = new RangeSetBuilder2();
|
|
3762
3855
|
const { state: state2 } = view;
|
|
3763
3856
|
for (const { from, to } of view.visibleRanges) {
|
|
3764
|
-
|
|
3857
|
+
syntaxTree3(state2).iterate({
|
|
3765
3858
|
from,
|
|
3766
3859
|
to,
|
|
3767
3860
|
enter: (node) => {
|
|
@@ -3878,7 +3971,7 @@ var buildDecorations = (view, options, focus) => {
|
|
|
3878
3971
|
var forceUpdate = StateEffect4.define();
|
|
3879
3972
|
var decorateMarkdown = (options = {}) => {
|
|
3880
3973
|
return [
|
|
3881
|
-
|
|
3974
|
+
ViewPlugin5.fromClass(class {
|
|
3882
3975
|
constructor(view) {
|
|
3883
3976
|
({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
|
|
3884
3977
|
}
|
|
@@ -3967,7 +4060,7 @@ var formattingStyles = EditorView12.baseTheme({
|
|
|
3967
4060
|
});
|
|
3968
4061
|
|
|
3969
4062
|
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
3970
|
-
import { syntaxTree as
|
|
4063
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
3971
4064
|
import { StateField as StateField5 } from "@codemirror/state";
|
|
3972
4065
|
import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3973
4066
|
var image = (options = {}) => {
|
|
@@ -4010,7 +4103,7 @@ var preloadImage = (url) => {
|
|
|
4010
4103
|
var buildDecorations2 = (from, to, state2) => {
|
|
4011
4104
|
const decorations = [];
|
|
4012
4105
|
const cursor = state2.selection.main.head;
|
|
4013
|
-
|
|
4106
|
+
syntaxTree4(state2).iterate({
|
|
4014
4107
|
enter: (node) => {
|
|
4015
4108
|
if (node.name === "Image") {
|
|
4016
4109
|
const urlNode = node.node.getChild("URL");
|
|
@@ -4050,11 +4143,11 @@ var imageUpload = (options = {}) => {
|
|
|
4050
4143
|
};
|
|
4051
4144
|
|
|
4052
4145
|
// packages/ui/react-ui-editor/src/extensions/markdown/link.ts
|
|
4053
|
-
import { syntaxTree as
|
|
4146
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
4054
4147
|
import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
|
|
4055
4148
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
4056
4149
|
var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
|
|
4057
|
-
const syntax =
|
|
4150
|
+
const syntax = syntaxTree5(view.state).resolveInner(pos, side);
|
|
4058
4151
|
let link = null;
|
|
4059
4152
|
for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
|
|
4060
4153
|
link = node.name === "Link" ? node : null;
|
|
@@ -4084,7 +4177,7 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
|
|
|
4084
4177
|
});
|
|
4085
4178
|
|
|
4086
4179
|
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
4087
|
-
import { syntaxTree as
|
|
4180
|
+
import { syntaxTree as syntaxTree6 } from "@codemirror/language";
|
|
4088
4181
|
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
|
|
4089
4182
|
import { Decoration as Decoration7, EditorView as EditorView14, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
4090
4183
|
var table = (options = {}) => {
|
|
@@ -4103,7 +4196,7 @@ var update = (state2, options) => {
|
|
|
4103
4196
|
const table2 = getTable();
|
|
4104
4197
|
return table2.rows?.[table2.rows.length - 1];
|
|
4105
4198
|
};
|
|
4106
|
-
|
|
4199
|
+
syntaxTree6(state2).iterate({
|
|
4107
4200
|
enter: (node) => {
|
|
4108
4201
|
switch (node.name) {
|
|
4109
4202
|
case "Table": {
|
|
@@ -4263,7 +4356,7 @@ var EditorModes = {
|
|
|
4263
4356
|
};
|
|
4264
4357
|
|
|
4265
4358
|
// packages/ui/react-ui-editor/src/extensions/state.ts
|
|
4266
|
-
import { Transaction } from "@codemirror/state";
|
|
4359
|
+
import { Transaction as Transaction2 } from "@codemirror/state";
|
|
4267
4360
|
import { EditorView as EditorView15, keymap as keymap9 } from "@codemirror/view";
|
|
4268
4361
|
import { debounce as debounce2 } from "@dxos/async";
|
|
4269
4362
|
import { invariant as invariant4 } from "@dxos/invariant";
|
|
@@ -4339,7 +4432,7 @@ var state = ({ getState, setState } = {}) => {
|
|
|
4339
4432
|
yMargin: 0
|
|
4340
4433
|
}),
|
|
4341
4434
|
selection: state2.selection,
|
|
4342
|
-
annotations:
|
|
4435
|
+
annotations: Transaction2.userEvent.of(scrollAnnotation)
|
|
4343
4436
|
});
|
|
4344
4437
|
}
|
|
4345
4438
|
return true;
|