@dxos/react-ui-editor 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/index.mjs +82 -70
- package/dist/lib/index.mjs.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/menu.d.ts +2 -0
- package/dist/types/src/components/EditorMenuProvider/menu.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/popover.d.ts +7 -1
- package/dist/types/src/components/EditorMenuProvider/popover.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts +2 -2
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.test.d.ts +2 -0
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.test.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Widgets.stories.d.ts +5 -0
- package/dist/types/src/stories/Widgets.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +33 -33
- package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +1 -1
- package/src/components/EditorMenuProvider/menu.ts +2 -0
- package/src/components/EditorMenuProvider/popover.ts +12 -3
- package/src/components/EditorMenuProvider/useEditorMenu.test.tsx +125 -0
- package/src/components/EditorMenuProvider/useEditorMenu.ts +79 -56
- package/src/hooks/useTextEditor.test.tsx +45 -4
- package/src/hooks/useTextEditor.ts +37 -9
- package/src/stories/Comments.stories.tsx +25 -21
- package/src/stories/Widgets.stories.tsx +59 -0
package/dist/lib/index.mjs
CHANGED
|
@@ -115,7 +115,7 @@ var popover = (options = {}) => {
|
|
|
115
115
|
(options.activateOnTyping || options.activateOnDelimiters?.length) && popoverAutoActivate(options),
|
|
116
116
|
popoverAnchorDecoration(options),
|
|
117
117
|
modalStateField,
|
|
118
|
-
options.trigger && placeholder({
|
|
118
|
+
options.trigger && options.placeholder !== false && placeholder({
|
|
119
119
|
content: `Press '${Array.isArray(options.trigger) ? options.trigger[0] : options.trigger}' for commands`,
|
|
120
120
|
focusOnly: true,
|
|
121
121
|
...options.placeholder
|
|
@@ -129,8 +129,9 @@ var popoverTriggerListener = (options) => EditorView$1.updateListener.of(({ view
|
|
|
129
129
|
const { range: activeRange, trigger } = view.state.field(popoverStateField) ?? {};
|
|
130
130
|
if (!activeRange) return;
|
|
131
131
|
const text = view.state.doc.sliceString(activeRange.from, activeRange.to);
|
|
132
|
+
const query = trigger ? text.slice(1) : text;
|
|
132
133
|
const selection = view.state.selection.main;
|
|
133
|
-
const shouldClose = (trigger ? trigger !== text[0] : false) ||
|
|
134
|
+
const shouldClose = (trigger ? trigger !== text[0] : false) || (trigger && options.multiWordTriggers?.includes(trigger) ? /^\s|[^\S ]| {2}/.test(query) : /\s/.test(query)) || selection.head < activeRange.from || selection.head > activeRange.to + 1;
|
|
134
135
|
const nextRange = shouldClose ? null : docChanged ? {
|
|
135
136
|
from: activeRange.from,
|
|
136
137
|
to: selection.head
|
|
@@ -596,7 +597,10 @@ var MenuItem = ({ item, current, onSelect }) => {
|
|
|
596
597
|
className: "dx-menu-item",
|
|
597
598
|
"data-highlighted": current ? "" : void 0,
|
|
598
599
|
onClick: handleSelect,
|
|
599
|
-
children: [item.icon && /* @__PURE__ */ jsx(Icon.Icon, {
|
|
600
|
+
children: [item.icon && /* @__PURE__ */ jsx(Icon.Icon, {
|
|
601
|
+
icon: item.icon,
|
|
602
|
+
hue: item.iconHue
|
|
603
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
600
604
|
className: "dx-menu-item-text",
|
|
601
605
|
children: Theme.toLocalizedString(item.label, t)
|
|
602
606
|
})]
|
|
@@ -616,7 +620,7 @@ var __dxlog_file$2 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/components/
|
|
|
616
620
|
* );
|
|
617
621
|
* ```
|
|
618
622
|
*/
|
|
619
|
-
var useEditorMenu = ({ trigger, triggerKey, placeholder, activateOnTyping, activateOnDelimiters, filter = true, searchTriggers, getMenu }) => {
|
|
623
|
+
var useEditorMenu = ({ trigger, triggerKey, placeholder, activateOnTyping, activateOnDelimiters, multiWordTriggers, filter = true, searchTriggers, getMenu }) => {
|
|
620
624
|
const groupsRef = useRef([]);
|
|
621
625
|
const currentRef = useRef(null);
|
|
622
626
|
const [currentItem, setCurrentItem] = useState();
|
|
@@ -626,17 +630,44 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder, activateOnTyping, activ
|
|
|
626
630
|
const [_, refresh] = useState({});
|
|
627
631
|
const contextRef = useRef(null);
|
|
628
632
|
const requestRef = useRef(0);
|
|
633
|
+
const getMenuRef = useRef(getMenu);
|
|
634
|
+
useLayoutEffect(() => {
|
|
635
|
+
getMenuRef.current = getMenu;
|
|
636
|
+
}, [getMenu]);
|
|
629
637
|
/**
|
|
630
638
|
* Get filtered options.
|
|
631
639
|
*/
|
|
632
640
|
const getMenuOptions = useCallback(async ({ text, trigger, ...props }) => {
|
|
633
|
-
const groups = await
|
|
641
|
+
const groups = await getMenuRef.current?.({
|
|
634
642
|
text,
|
|
635
643
|
trigger,
|
|
636
644
|
...props
|
|
637
645
|
}) ?? [];
|
|
638
646
|
return filter && trigger !== "@" ? filterMenuGroups(groups, (item) => text ? item.label.toLowerCase().startsWith(text.toLowerCase()) : true) : groups;
|
|
639
|
-
}, [
|
|
647
|
+
}, [filter]);
|
|
648
|
+
const handleOpenChange = useCallback(async ({ view, open }) => {
|
|
649
|
+
invariant(view, void 0, {
|
|
650
|
+
"~LogMeta": "~LogMeta",
|
|
651
|
+
F: __dxlog_file$2,
|
|
652
|
+
L: 128,
|
|
653
|
+
S: void 0,
|
|
654
|
+
A: ["view", ""]
|
|
655
|
+
});
|
|
656
|
+
setOpen(open);
|
|
657
|
+
if (!open) {
|
|
658
|
+
setCurrentItem(void 0);
|
|
659
|
+
setSearch(false);
|
|
660
|
+
setQuery("");
|
|
661
|
+
contextRef.current = null;
|
|
662
|
+
requestRef.current++;
|
|
663
|
+
groupsRef.current = [];
|
|
664
|
+
currentRef.current = null;
|
|
665
|
+
view.dispatch({ effects: [popoverRangeEffect.of(null)] });
|
|
666
|
+
}
|
|
667
|
+
requestAnimationFrame(() => {
|
|
668
|
+
view.dispatch({ effects: [modalStateEffect.of(open)] });
|
|
669
|
+
});
|
|
670
|
+
}, [getMenuOptions]);
|
|
640
671
|
/**
|
|
641
672
|
* Recompute the menu and preselect the first item.
|
|
642
673
|
*/
|
|
@@ -660,29 +691,6 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder, activateOnTyping, activ
|
|
|
660
691
|
}
|
|
661
692
|
refresh({});
|
|
662
693
|
}, [getMenuOptions]);
|
|
663
|
-
const handleOpenChange = useCallback(async ({ view, open }) => {
|
|
664
|
-
invariant(view, void 0, {
|
|
665
|
-
"~LogMeta": "~LogMeta",
|
|
666
|
-
F: __dxlog_file$2,
|
|
667
|
-
L: 137,
|
|
668
|
-
S: void 0,
|
|
669
|
-
A: ["view", ""]
|
|
670
|
-
});
|
|
671
|
-
setOpen(open);
|
|
672
|
-
if (!open) {
|
|
673
|
-
setCurrentItem(void 0);
|
|
674
|
-
setSearch(false);
|
|
675
|
-
setQuery("");
|
|
676
|
-
contextRef.current = null;
|
|
677
|
-
requestRef.current++;
|
|
678
|
-
groupsRef.current = [];
|
|
679
|
-
currentRef.current = null;
|
|
680
|
-
view.dispatch({ effects: [popoverRangeEffect.of(null)] });
|
|
681
|
-
}
|
|
682
|
-
requestAnimationFrame(() => {
|
|
683
|
-
view.dispatch({ effects: [modalStateEffect.of(open)] });
|
|
684
|
-
});
|
|
685
|
-
}, [getMenuOptions]);
|
|
686
694
|
const handleActivate = useCallback(async ({ view, trigger }) => {
|
|
687
695
|
const item = getMenuItem(groupsRef.current, currentItem);
|
|
688
696
|
if (item) currentRef.current = item;
|
|
@@ -707,7 +715,7 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder, activateOnTyping, activ
|
|
|
707
715
|
}, []);
|
|
708
716
|
const handleCancel = useCallback(({ view }) => {
|
|
709
717
|
const { range, trigger } = view.state.field(popoverStateField) ?? {};
|
|
710
|
-
if (range && trigger) view.dispatch({ changes: {
|
|
718
|
+
if (range && trigger && !contextRef.current?.multiWord) view.dispatch({ changes: {
|
|
711
719
|
...range,
|
|
712
720
|
insert: ""
|
|
713
721
|
} });
|
|
@@ -728,18 +736,23 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder, activateOnTyping, activ
|
|
|
728
736
|
return next.id;
|
|
729
737
|
});
|
|
730
738
|
}, []);
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
739
|
+
const arraysKey = JSON.stringify({
|
|
740
|
+
trigger,
|
|
741
|
+
searchTriggers,
|
|
742
|
+
activateOnDelimiters,
|
|
743
|
+
multiWordTriggers
|
|
744
|
+
});
|
|
734
745
|
return {
|
|
735
746
|
groupsRef,
|
|
736
747
|
extension: useMemo(() => {
|
|
748
|
+
const arrays = JSON.parse(arraysKey);
|
|
737
749
|
return popover({
|
|
738
|
-
trigger,
|
|
750
|
+
trigger: arrays.trigger,
|
|
739
751
|
triggerKey,
|
|
740
752
|
placeholder,
|
|
741
753
|
activateOnTyping,
|
|
742
|
-
activateOnDelimiters,
|
|
754
|
+
activateOnDelimiters: arrays.activateOnDelimiters,
|
|
755
|
+
multiWordTriggers: arrays.multiWordTriggers,
|
|
743
756
|
onClose: ({ view }) => handleOpenChange({
|
|
744
757
|
view,
|
|
745
758
|
open: false
|
|
@@ -757,29 +770,25 @@ var useEditorMenu = ({ trigger, triggerKey, placeholder, activateOnTyping, activ
|
|
|
757
770
|
onArrowUp: () => handleNavigate("up"),
|
|
758
771
|
onArrowDown: () => handleNavigate("down"),
|
|
759
772
|
onTextChange: async ({ view, pos, text, trigger }) => {
|
|
760
|
-
|
|
773
|
+
const context = {
|
|
761
774
|
view,
|
|
762
775
|
pos,
|
|
763
776
|
text,
|
|
764
|
-
trigger
|
|
777
|
+
trigger,
|
|
778
|
+
multiWord: !!trigger && !!arrays.multiWordTriggers?.includes(trigger)
|
|
765
779
|
};
|
|
766
|
-
|
|
780
|
+
contextRef.current = context;
|
|
781
|
+
setSearch(!!trigger && !!arrays.searchTriggers?.includes(trigger));
|
|
767
782
|
setQuery("");
|
|
768
|
-
await updateGroups(
|
|
769
|
-
view,
|
|
770
|
-
pos,
|
|
771
|
-
text,
|
|
772
|
-
trigger
|
|
773
|
-
});
|
|
783
|
+
await updateGroups(context);
|
|
774
784
|
}
|
|
775
785
|
});
|
|
776
786
|
}, [
|
|
777
787
|
handleOpenChange,
|
|
778
788
|
handleNavigate,
|
|
779
789
|
updateGroups,
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
serializedDelimiters,
|
|
790
|
+
arraysKey,
|
|
791
|
+
triggerKey,
|
|
783
792
|
placeholder,
|
|
784
793
|
activateOnTyping
|
|
785
794
|
]),
|
|
@@ -1090,6 +1099,8 @@ var useBasicMarkdownExtensions = ({ placeholder, decorate = true, readonly = fal
|
|
|
1090
1099
|
//#region src/hooks/useTextEditor.ts
|
|
1091
1100
|
var __dxlog_file$1 = "/__w/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
1092
1101
|
var instanceCount = 0;
|
|
1102
|
+
/** Whether every position in a recorded state lies within a document of `length`. */
|
|
1103
|
+
var fitsDocument = ({ scrollTo, selection }, length) => (scrollTo ?? 0) <= length && (selection?.anchor ?? 0) <= length && (selection?.head ?? 0) <= length;
|
|
1093
1104
|
/**
|
|
1094
1105
|
* Creates codemirror text editor.
|
|
1095
1106
|
*/
|
|
@@ -1108,7 +1119,7 @@ var useTextEditor = (props = {}, deps = []) => {
|
|
|
1108
1119
|
}, {
|
|
1109
1120
|
"~LogMeta": "~LogMeta",
|
|
1110
1121
|
F: __dxlog_file$1,
|
|
1111
|
-
L:
|
|
1122
|
+
L: 87,
|
|
1112
1123
|
S: void 0
|
|
1113
1124
|
});
|
|
1114
1125
|
const length = (doc ?? initialValue)?.length ?? 0;
|
|
@@ -1125,7 +1136,7 @@ var useTextEditor = (props = {}, deps = []) => {
|
|
|
1125
1136
|
log.catch(err, void 0, {
|
|
1126
1137
|
"~LogMeta": "~LogMeta",
|
|
1127
1138
|
F: __dxlog_file$1,
|
|
1128
|
-
L:
|
|
1139
|
+
L: 108,
|
|
1129
1140
|
S: void 0
|
|
1130
1141
|
});
|
|
1131
1142
|
})
|
|
@@ -1150,35 +1161,36 @@ var useTextEditor = (props = {}, deps = []) => {
|
|
|
1150
1161
|
log("destroy", { id }, {
|
|
1151
1162
|
"~LogMeta": "~LogMeta",
|
|
1152
1163
|
F: __dxlog_file$1,
|
|
1153
|
-
L:
|
|
1164
|
+
L: 132,
|
|
1154
1165
|
S: void 0
|
|
1155
1166
|
});
|
|
1156
1167
|
view?.destroy();
|
|
1157
1168
|
};
|
|
1158
1169
|
}, deps);
|
|
1159
1170
|
useEffect(() => {
|
|
1160
|
-
if (view)
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
scrollOffset,
|
|
1178
|
-
selection
|
|
1171
|
+
if (!view || scrollTo == null && !selection) return;
|
|
1172
|
+
const state = {
|
|
1173
|
+
scrollTo,
|
|
1174
|
+
scrollOffset,
|
|
1175
|
+
selection
|
|
1176
|
+
};
|
|
1177
|
+
if (fitsDocument(state, view.state.doc.length)) {
|
|
1178
|
+
restoreEditorState(view, state);
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
let active = true;
|
|
1182
|
+
let pending = true;
|
|
1183
|
+
view.dispatch({ effects: StateEffect.appendConfig.of(EditorView$1.updateListener.of((update) => {
|
|
1184
|
+
if (pending && update.docChanged && fitsDocument(state, update.state.doc.length)) {
|
|
1185
|
+
pending = false;
|
|
1186
|
+
queueMicrotask(() => {
|
|
1187
|
+
if (active) restoreEditorState(update.view, state);
|
|
1179
1188
|
});
|
|
1180
1189
|
}
|
|
1181
|
-
}
|
|
1190
|
+
})) });
|
|
1191
|
+
return () => {
|
|
1192
|
+
active = false;
|
|
1193
|
+
};
|
|
1182
1194
|
}, [
|
|
1183
1195
|
view,
|
|
1184
1196
|
scrollTo,
|