@dxos/react-ui-editor 0.3.9-main.eb5df3b → 0.3.9-main.ec541d7

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.
Files changed (48) hide show
  1. package/dist/lib/browser/index.mjs +298 -26
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/automerge/automerge-plugin/index.d.ts +1 -1
  5. package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +1 -1
  6. package/dist/types/src/automerge/automerge.stories.d.ts.map +1 -1
  7. package/dist/types/src/components/Editor/Editor.stories.d.ts +3 -2
  8. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/Markdown/Markdown.d.ts +2 -1
  10. package/dist/types/src/components/Markdown/Markdown.d.ts.map +1 -1
  11. package/dist/types/src/components/Markdown/Markdown.stories.d.ts +2 -1
  12. package/dist/types/src/components/Markdown/Markdown.stories.d.ts.map +1 -1
  13. package/dist/types/src/components/Markdown/markdownTheme.d.ts +2 -16
  14. package/dist/types/src/components/Markdown/markdownTheme.d.ts.map +1 -1
  15. package/dist/types/src/components/RichText/RichText.stories.d.ts +2 -1
  16. package/dist/types/src/components/RichText/RichText.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/TextEditor/TextEditor.d.ts +39 -0
  18. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -0
  19. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +32 -0
  20. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -0
  21. package/dist/types/src/components/TextEditor/extensions/hyperlink.d.ts +10 -0
  22. package/dist/types/src/components/TextEditor/extensions/hyperlink.d.ts.map +1 -0
  23. package/dist/types/src/components/TextEditor/extensions/hyperlinkTooltip.d.ts +9 -0
  24. package/dist/types/src/components/TextEditor/extensions/hyperlinkTooltip.d.ts.map +1 -0
  25. package/dist/types/src/components/TextEditor/extensions/index.d.ts +3 -0
  26. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -0
  27. package/dist/types/src/components/TextEditor/index.d.ts +6 -0
  28. package/dist/types/src/components/TextEditor/index.d.ts.map +1 -0
  29. package/dist/types/src/components/TextEditor/theme.d.ts +8 -0
  30. package/dist/types/src/components/TextEditor/theme.d.ts.map +1 -0
  31. package/dist/types/src/components/index.d.ts +1 -0
  32. package/dist/types/src/components/index.d.ts.map +1 -1
  33. package/package.json +20 -16
  34. package/src/automerge/automerge-plugin/index.ts +1 -1
  35. package/src/automerge/automerge.stories.tsx +1 -2
  36. package/src/components/Editor/Editor.stories.tsx +2 -0
  37. package/src/components/Markdown/Markdown.stories.tsx +2 -0
  38. package/src/components/Markdown/Markdown.tsx +6 -2
  39. package/src/components/Markdown/markdownTheme.ts +20 -16
  40. package/src/components/RichText/RichText.stories.tsx +2 -0
  41. package/src/components/TextEditor/TextEditor.stories.tsx +83 -0
  42. package/src/components/TextEditor/TextEditor.tsx +130 -0
  43. package/src/components/TextEditor/extensions/hyperlink.tsx +108 -0
  44. package/src/components/TextEditor/extensions/hyperlinkTooltip.tsx +76 -0
  45. package/src/components/TextEditor/extensions/index.ts +6 -0
  46. package/src/components/TextEditor/index.ts +11 -0
  47. package/src/components/TextEditor/theme.ts +33 -0
  48. package/src/components/index.ts +1 -0
@@ -261,10 +261,7 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
261
261
  var tokens = tailwindConfig({}).theme;
262
262
 
263
263
  // packages/ui/react-ui-editor/src/components/Markdown/markdownTheme.ts
264
- var ivory = "#abb2bf";
265
264
  var malibu = "#61afef";
266
- var highlightBackground = "#2c313a";
267
- var tooltipBackground = "#353a42";
268
265
  var cursor = "#ffffff";
269
266
  var monospace = get(tokens, "fontFamily.mono", [
270
267
  "monospace"
@@ -307,24 +304,28 @@ var markdownTheme = {
307
304
  // border: 'none',
308
305
  // color: '#ddd'
309
306
  // },
310
- ".dark & .cm-tooltip": {
311
- border: "none",
312
- backgroundColor: tooltipBackground
313
- },
314
- ".dark & .cm-tooltip .cm-tooltip-arrow:before": {
315
- borderTopColor: "transparent",
316
- borderBottomColor: "transparent"
317
- },
318
- ".dark & .cm-tooltip .cm-tooltip-arrow:after": {
319
- borderTopColor: tooltipBackground,
320
- borderBottomColor: tooltipBackground
321
- },
322
- ".dark & .cm-tooltip-autocomplete": {
323
- "& > ul > li[aria-selected]": {
324
- backgroundColor: highlightBackground,
325
- color: ivory
326
- }
307
+ ".cm-tooltip": {
308
+ backgroundColor: "transparent",
309
+ border: "none"
327
310
  },
311
+ // '.dark & .cm-tooltip': {
312
+ // border: 'none',
313
+ // backgroundColor: tooltipBackground,
314
+ // },
315
+ // '.dark & .cm-tooltip .cm-tooltip-arrow:before': {
316
+ // borderTopColor: 'transparent',
317
+ // borderBottomColor: 'transparent',
318
+ // },
319
+ // '.dark & .cm-tooltip .cm-tooltip-arrow:after': {
320
+ // borderTopColor: tooltipBackground,
321
+ // borderBottomColor: tooltipBackground,
322
+ // },
323
+ // '.dark & .cm-tooltip-autocomplete': {
324
+ // '& > ul > li[aria-selected]': {
325
+ // backgroundColor: highlightBackground,
326
+ // color: ivory,
327
+ // },
328
+ // },
328
329
  "&.cm-focused": {
329
330
  outline: "none"
330
331
  },
@@ -541,7 +542,7 @@ var EditorModes = [
541
542
  "default",
542
543
  "vim"
543
544
  ];
544
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode, onChange }, forwardedRef) => {
545
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode, extensions = [], onChange }, forwardedRef) => {
545
546
  const { id, content, provider, peer } = model ?? {};
546
547
  const { themeMode } = useThemeContext();
547
548
  const tabsterDOMAttribute = useFocusableGroup({
@@ -650,7 +651,9 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode
650
651
  // Replication and awareness (incl. remote selection).
651
652
  ...content instanceof YText ? [
652
653
  yCollab(content, provider?.awareness)
653
- ] : []
654
+ ] : [],
655
+ // Custom.
656
+ ...extensions
654
657
  ]
655
658
  });
656
659
  setState(state2);
@@ -709,7 +712,7 @@ import StarterKit from "@tiptap/starter-kit";
709
712
  import React2, { forwardRef as forwardRef2, useImperativeHandle as useImperativeHandle2, useMemo as useMemo3 } from "react";
710
713
  import { generateName as generateName2 } from "@dxos/display-name";
711
714
  import { mx as mx2 } from "@dxos/react-ui-theme";
712
- var useEditor = ({ model, placeholder: placeholder2 = "Enter text\u2026", slots = {} }) => {
715
+ var useEditor = ({ model, placeholder: placeholder3 = "Enter text\u2026", slots = {} }) => {
713
716
  const extensions = useMemo3(() => [
714
717
  StarterKit.configure({
715
718
  // Extensions
@@ -814,7 +817,7 @@ var useEditor = ({ model, placeholder: placeholder2 = "Enter text\u2026", slots
814
817
  })
815
818
  ] : [],
816
819
  Placeholder.configure({
817
- placeholder: placeholder2,
820
+ placeholder: placeholder3,
818
821
  emptyEditorClass: "before:content-[attr(data-placeholder)] before:absolute opacity-50 cursor-text"
819
822
  })
820
823
  ], [
@@ -862,18 +865,287 @@ var Editor = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef3(({ slots, ...param
862
865
  }
863
866
  }));
864
867
 
868
+ // packages/ui/react-ui-editor/src/components/TextEditor/index.ts
869
+ import { tags as tags2 } from "@lezer/highlight";
870
+
871
+ // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
872
+ import { closeBrackets as closeBrackets2 } from "@codemirror/autocomplete";
873
+ import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
874
+ import { EditorState as EditorState2 } from "@codemirror/state";
875
+ import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
876
+ import { EditorView as EditorView2, placeholder as placeholder2 } from "@codemirror/view";
877
+ import React4, { forwardRef as forwardRef4, useEffect as useEffect2, useImperativeHandle as useImperativeHandle3, useState as useState2, useCallback as useCallback2 } from "react";
878
+ import { yCollab as yCollab2 } from "y-codemirror.next";
879
+ import { useThemeContext as useThemeContext2 } from "@dxos/react-ui";
880
+ import { YText as YText2 } from "@dxos/text-model";
881
+
882
+ // packages/ui/react-ui-editor/src/components/TextEditor/theme.ts
883
+ import get2 from "lodash.get";
884
+ import { tailwindConfig as tailwindConfig2 } from "@dxos/react-ui-theme";
885
+ var tokens2 = tailwindConfig2({}).theme;
886
+ var defaultStyles = {
887
+ "&.cm-focused": {
888
+ outline: "none"
889
+ },
890
+ ".cm-placeholder": {
891
+ fontFamily: get2(tokens2, "fontFamily.body", []).join(",")
892
+ },
893
+ "& .cm-scroller": {
894
+ fontFamily: get2(tokens2, "fontFamily.body", []).join(","),
895
+ overflow: "visible"
896
+ },
897
+ ".cm-tooltip": {
898
+ backgroundColor: "transparent",
899
+ border: "none"
900
+ }
901
+ };
902
+
903
+ // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
904
+ var TextEditor = /* @__PURE__ */ forwardRef4(({ model, extensions = [], theme = defaultStyles, slots = {}, onKeyDown, ...props }, forwardedRef) => {
905
+ const { id, content } = model ?? {};
906
+ const { themeMode } = useThemeContext2();
907
+ const [parent, setParent] = useState2(null);
908
+ const [state, setState] = useState2();
909
+ const [view, setView] = useState2();
910
+ useImperativeHandle3(forwardedRef, () => {
911
+ return {
912
+ editor: parent,
913
+ state,
914
+ view
915
+ };
916
+ }, [
917
+ view
918
+ ]);
919
+ useEffect2(() => {
920
+ if (!parent) {
921
+ return;
922
+ }
923
+ view?.destroy();
924
+ const state2 = EditorState2.create({
925
+ doc: content?.toString(),
926
+ extensions: [
927
+ bracketMatching2(),
928
+ closeBrackets2(),
929
+ placeholder2(slots.editor?.placeholder ?? ""),
930
+ EditorView2.lineWrapping,
931
+ // Themes.
932
+ EditorView2.theme(theme),
933
+ ...themeMode === "dark" ? [
934
+ syntaxHighlighting2(oneDarkHighlightStyle2)
935
+ ] : [
936
+ syntaxHighlighting2(defaultHighlightStyle2)
937
+ ],
938
+ // Replication.
939
+ ...content instanceof YText2 ? [
940
+ yCollab2(content, void 0)
941
+ ] : [],
942
+ // Custom.
943
+ ...extensions
944
+ ]
945
+ });
946
+ setState(state2);
947
+ setView(new EditorView2({
948
+ state: state2,
949
+ parent
950
+ }));
951
+ return () => {
952
+ view?.destroy();
953
+ setView(void 0);
954
+ setState(void 0);
955
+ };
956
+ }, [
957
+ parent,
958
+ content,
959
+ themeMode
960
+ ]);
961
+ const handleKeyDown = useCallback2((event) => {
962
+ if (view) {
963
+ const { head, from, to } = view.state.selection.ranges[0];
964
+ const { number } = view.state.doc.lineAt(head);
965
+ const after = view.state.sliceDoc(from);
966
+ onKeyDown?.(event, {
967
+ from,
968
+ to,
969
+ line: number,
970
+ lines: view.state.doc.lines,
971
+ after
972
+ });
973
+ }
974
+ }, [
975
+ view
976
+ ]);
977
+ return /* @__PURE__ */ React4.createElement("div", {
978
+ key: id,
979
+ ref: setParent,
980
+ ...slots.root,
981
+ onKeyDown: handleKeyDown,
982
+ ...props
983
+ });
984
+ });
985
+
986
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink.tsx
987
+ import { Decoration, EditorView as EditorView3, MatchDecorator, ViewPlugin } from "@codemirror/view";
988
+ var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)(!?)/gi;
989
+ var linkDecorator = () => new MatchDecorator({
990
+ regexp: markdownLinkRegexp,
991
+ decorate: (add, from, to, match, view) => {
992
+ const [_, label, url] = match;
993
+ const p0 = {
994
+ start: from,
995
+ end: from + 1
996
+ };
997
+ const p1 = {
998
+ start: from + 1,
999
+ end: from + 1 + label.length
1000
+ };
1001
+ const p2 = {
1002
+ start: p1.end,
1003
+ end: p1.end + 1
1004
+ };
1005
+ const p3 = {
1006
+ start: p1.end + 1,
1007
+ end: p1.end + 1 + url.length + 2
1008
+ };
1009
+ add(p0.start, p0.end, Decoration.mark({
1010
+ class: "cm-hyperlink-bracket"
1011
+ }));
1012
+ add(p1.start, p1.end, Decoration.mark({
1013
+ class: "cm-hyperlink-label"
1014
+ }));
1015
+ add(p2.start, p2.end, Decoration.mark({
1016
+ class: "cm-hyperlink-bracket"
1017
+ }));
1018
+ add(p3.start, p3.end, Decoration.mark({
1019
+ class: "cm-hyperlink-url",
1020
+ __attributes: {
1021
+ style: "display: none"
1022
+ }
1023
+ }));
1024
+ }
1025
+ });
1026
+ function hyperLinkExtension() {
1027
+ return ViewPlugin.fromClass(class HyperLinkView {
1028
+ constructor(view) {
1029
+ this.decorator = linkDecorator();
1030
+ this.decorations = this.decorator.createDeco(view);
1031
+ }
1032
+ update(update) {
1033
+ if (update.docChanged || update.viewportChanged) {
1034
+ this.decorations = this.decorator.updateDeco(update, this.decorations);
1035
+ }
1036
+ }
1037
+ }, {
1038
+ decorations: (view) => view.decorations,
1039
+ eventHandlers: {
1040
+ // TODO(burdon): CLick to expand link.
1041
+ // https://discuss.codemirror.net/t/decorator-iteration-on-click-event/4226/2
1042
+ mousedown: function(event, view) {
1043
+ const pos = view.posAtDOM(event.target);
1044
+ if (pos !== 0) {
1045
+ console.log(this);
1046
+ }
1047
+ },
1048
+ // TODO(burdon): Hide when cursor moves away.
1049
+ keydown: (event, view) => {
1050
+ view.update([]);
1051
+ }
1052
+ }
1053
+ });
1054
+ }
1055
+ var hyperLinkStyle = EditorView3.baseTheme({
1056
+ ".cm-hyperlink-label": {
1057
+ cursor: "pointer",
1058
+ textDecoration: "underline"
1059
+ },
1060
+ ".cm-hyperlink-bracket": {
1061
+ opacity: 0.2
1062
+ },
1063
+ ".cm-hyperlink-url": {
1064
+ opacity: 0.5,
1065
+ fontFamily: "monospace"
1066
+ }
1067
+ });
1068
+ var hyperlink = [
1069
+ hyperLinkExtension(),
1070
+ hyperLinkStyle
1071
+ ];
1072
+
1073
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlinkTooltip.tsx
1074
+ import { hoverTooltip } from "@codemirror/view";
1075
+ import { ArrowCircleUp } from "@phosphor-icons/react";
1076
+ import React5, { StrictMode } from "react";
1077
+ import { createRoot } from "react-dom/client";
1078
+ import { getSize, mx as mx3, tooltipContent } from "@dxos/react-ui-theme";
1079
+ var markdownLinkRegexp2 = /\[([^\]]+)]\(([^)]+)\)/;
1080
+ var createHyperlinkTooltip = (onHover, regexp = markdownLinkRegexp2) => hoverTooltip((view, pos) => {
1081
+ const { from, text } = view.state.doc.lineAt(pos);
1082
+ const p = pos - from;
1083
+ let idx = 0;
1084
+ let match;
1085
+ do {
1086
+ match = text.substring(idx).match(regexp);
1087
+ if (!match) {
1088
+ match = void 0;
1089
+ break;
1090
+ }
1091
+ idx = text.indexOf(match[0]);
1092
+ if (p >= idx && p < idx + match[0].length) {
1093
+ break;
1094
+ }
1095
+ idx += match[0].length;
1096
+ } while (true);
1097
+ if (!match) {
1098
+ return null;
1099
+ }
1100
+ const [, , url] = match ?? [];
1101
+ return {
1102
+ pos: idx + from,
1103
+ end: idx + from + match[0].length,
1104
+ above: true,
1105
+ create: () => {
1106
+ const el = document.createElement("a");
1107
+ el.innerText = "_";
1108
+ el.className = tooltipContent({}, "mb-2 p-1");
1109
+ el.setAttribute("target", "_blank");
1110
+ el.setAttribute("href", url);
1111
+ onHover(el, url);
1112
+ return {
1113
+ dom: el
1114
+ };
1115
+ }
1116
+ };
1117
+ });
1118
+ var defaultHyperLinkTooltip = createHyperlinkTooltip((el, url) => {
1119
+ const web = new URL(url);
1120
+ createRoot(el).render(/* @__PURE__ */ React5.createElement(StrictMode, null, /* @__PURE__ */ React5.createElement("div", {
1121
+ className: "flex gap-1 items-center"
1122
+ }, /* @__PURE__ */ React5.createElement(ArrowCircleUp, {
1123
+ className: mx3(getSize(6), "text-blue-500")
1124
+ }), /* @__PURE__ */ React5.createElement("p", {
1125
+ className: "pr-1"
1126
+ }, web.origin))));
1127
+ });
1128
+
865
1129
  // packages/ui/react-ui-editor/src/index.ts
866
1130
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
867
- import { Doc, YText as YText2, YXmlFragment as YXmlFragment2 } from "@dxos/text-model";
1131
+ import { Doc, YText as YText3, YXmlFragment as YXmlFragment2 } from "@dxos/text-model";
868
1132
  export {
869
1133
  Doc,
870
1134
  Editor,
871
1135
  EditorModes,
872
1136
  MarkdownEditor,
873
1137
  RichTextEditor,
1138
+ TextEditor,
874
1139
  TextKind,
875
- YText2 as YText,
1140
+ YText3 as YText,
876
1141
  YXmlFragment2 as YXmlFragment,
1142
+ createHyperlinkTooltip,
1143
+ defaultHyperLinkTooltip,
1144
+ defaultStyles,
1145
+ hyperLinkExtension,
1146
+ hyperLinkStyle,
1147
+ hyperlink,
1148
+ tags2 as tags,
877
1149
  useTextModel
878
1150
  };
879
1151
  //# sourceMappingURL=index.mjs.map