@rowsncolumns/ui 16.0.3 → 16.0.5
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/cjs/dialog/index.d.ts.map +1 -1
- package/dist/cjs/dialog/index.js +45 -3
- package/dist/cjs/editor-pm/mentions-plugin.d.ts +3 -3
- package/dist/cjs/editor-pm/mentions-plugin.d.ts.map +1 -1
- package/dist/cjs/editor-pm/mentions-plugin.js +11 -0
- package/dist/cjs/editor-pm/prosemirror-editor.d.ts +4 -4
- package/dist/cjs/editor-pm/prosemirror-editor.d.ts.map +1 -1
- package/dist/cjs/editor-pm/prosemirror-editor.js +95 -35
- package/dist/cjs/editor-pm/use-parameter-suggestions.d.ts.map +1 -1
- package/dist/cjs/editor-pm/use-parameter-suggestions.js +27 -9
- package/dist/cjs/hooks/use-dropdown.d.ts +12 -5
- package/dist/cjs/hooks/use-dropdown.d.ts.map +1 -1
- package/dist/cjs/hooks/use-dropdown.js +72 -45
- package/dist/esm/dialog/index.d.ts.map +1 -1
- package/dist/esm/dialog/index.js +33 -2
- package/dist/esm/editor-pm/mentions-plugin.d.ts +3 -3
- package/dist/esm/editor-pm/mentions-plugin.d.ts.map +1 -1
- package/dist/esm/editor-pm/mentions-plugin.js +11 -0
- package/dist/esm/editor-pm/prosemirror-editor.d.ts +4 -4
- package/dist/esm/editor-pm/prosemirror-editor.d.ts.map +1 -1
- package/dist/esm/editor-pm/prosemirror-editor.js +86 -34
- package/dist/esm/editor-pm/use-parameter-suggestions.d.ts.map +1 -1
- package/dist/esm/editor-pm/use-parameter-suggestions.js +27 -9
- package/dist/esm/hooks/use-dropdown.d.ts +12 -5
- package/dist/esm/hooks/use-dropdown.d.ts.map +1 -1
- package/dist/esm/hooks/use-dropdown.js +68 -43
- package/package.json +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __read, __spreadArray } from "tslib";
|
|
2
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
-
import { useIsomorphicLayoutEffect } from "./use-isomorphic-layout-effect.ts";
|
|
4
2
|
import { matchSorter } from "match-sorter";
|
|
3
|
+
import { useCallback, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { useIsomorphicLayoutEffect } from "./use-isomorphic-layout-effect.ts";
|
|
5
5
|
export var sortByUnderscore = function (a, b) {
|
|
6
6
|
var _a, _b;
|
|
7
7
|
var aUnderscore = (_a = String(a === null || a === void 0 ? void 0 : a.title)) === null || _a === void 0 ? void 0 : _a.startsWith("_");
|
|
@@ -55,35 +55,53 @@ var reorderByPriority = function (list) {
|
|
|
55
55
|
export var sanitizeDropdownQuery = function (value) {
|
|
56
56
|
return value.replace(/["'`]/g, "");
|
|
57
57
|
};
|
|
58
|
+
var areSameItems = function (a, b) {
|
|
59
|
+
return a === b || (a.length === b.length && a.every(function (item, i) { return item === b[i]; }));
|
|
60
|
+
};
|
|
58
61
|
export var useDropdown = function (_a) {
|
|
59
|
-
var
|
|
60
|
-
var _d = __read(useState(
|
|
61
|
-
var _e = __read(useState(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
var initialHighlightedIndex = _a.initialHighlightedIndex, initialQuery = _a.initialQuery, onChange = _a.onChange, _b = _a.items, items = _b === void 0 ? [] : _b, isNewValue = _a.isNewValue, _c = _a.limit, limit = _c === void 0 ? 10 : _c, showAllIfEmpty = _a.showAllIfEmpty, itemsWhenEmpty = _a.itemsWhenEmpty, isItemSelected = _a.isItemSelected;
|
|
63
|
+
var _d = __read(useState(initialQuery !== null && initialQuery !== void 0 ? initialQuery : ""), 2), query = _d[0], setQuery = _d[1];
|
|
64
|
+
var _e = __read(useState(initialHighlightedIndex), 2), highlightedIndex = _e[0], setHighlightedIndex = _e[1];
|
|
65
|
+
// The item set the menu was dismissed (Escape) for. The menu is open exactly
|
|
66
|
+
// when it has items and was not dismissed for that set; any change to the
|
|
67
|
+
// set (a keystroke re-filtering it) or an explicit `openMenu` lifts the
|
|
68
|
+
// dismissal.
|
|
69
|
+
var _f = __read(useState(null), 2), dismissedItems = _f[0], setDismissedItems = _f[1];
|
|
65
70
|
// Refs
|
|
66
71
|
var isDirty = useRef(isNewValue);
|
|
67
|
-
var initialQueryRef = useRef(
|
|
72
|
+
var initialQueryRef = useRef(initialQuery !== null && initialQuery !== void 0 ? initialQuery : "");
|
|
68
73
|
var highlightedIndexRef = useRef(undefined);
|
|
69
74
|
var queryRef = useRef(undefined);
|
|
70
|
-
var filteredItemsRef = useRef(undefined);
|
|
71
75
|
useIsomorphicLayoutEffect(function () {
|
|
72
76
|
queryRef.current = query;
|
|
73
77
|
}, [query]);
|
|
74
78
|
useIsomorphicLayoutEffect(function () {
|
|
75
79
|
highlightedIndexRef.current = highlightedIndex;
|
|
76
80
|
}, [highlightedIndex]);
|
|
77
|
-
|
|
81
|
+
// Re-seed for a new editing session. The hosting editor stays mounted
|
|
82
|
+
// (hidden) between sessions, so the query must follow `initialQuery` when a
|
|
83
|
+
// new session starts — otherwise the previous session's filter narrows the
|
|
84
|
+
// next dropdown open.
|
|
85
|
+
//
|
|
86
|
+
// Derived during render (React re-runs the component before committing),
|
|
87
|
+
// deliberately NOT from an effect. The in-cell editor passes the live cell
|
|
88
|
+
// text as `initialQuery`, so an effect here ran after every keystroke and
|
|
89
|
+
// scheduled a second render from the commit phase; together with the
|
|
90
|
+
// open/close effect below that left a render pending at the tail of every
|
|
91
|
+
// commit, which in a typing burst never let React's nested-update counter
|
|
92
|
+
// reset and threw "Maximum update depth exceeded" (Minified React error
|
|
93
|
+
// #185) — dropping the keystroke whose update threw.
|
|
94
|
+
var _g = __read(useState(function () { return ({ initialQuery: initialQuery, isNewValue: isNewValue }); }), 2), seed = _g[0], setSeed = _g[1];
|
|
95
|
+
if (seed.initialQuery !== initialQuery || seed.isNewValue !== isNewValue) {
|
|
96
|
+
setSeed({ initialQuery: initialQuery, isNewValue: isNewValue });
|
|
78
97
|
initialQueryRef.current = initialQuery !== null && initialQuery !== void 0 ? initialQuery : "";
|
|
79
98
|
isDirty.current = Boolean(isNewValue);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}, [initialQuery, isNewValue]);
|
|
99
|
+
if (query !== (initialQuery !== null && initialQuery !== void 0 ? initialQuery : "")) {
|
|
100
|
+
setQuery(initialQuery !== null && initialQuery !== void 0 ? initialQuery : "");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
85
103
|
// Filtered items
|
|
86
|
-
var
|
|
104
|
+
var computedFilteredItems = useMemo(function () {
|
|
87
105
|
if (!query) {
|
|
88
106
|
if (itemsWhenEmpty === null || itemsWhenEmpty === void 0 ? void 0 : itemsWhenEmpty.length) {
|
|
89
107
|
return reorderByPriority(__spreadArray([], __read(itemsWhenEmpty), false));
|
|
@@ -120,10 +138,43 @@ export var useDropdown = function (_a) {
|
|
|
120
138
|
baseSort: dropdownBaseSort,
|
|
121
139
|
});
|
|
122
140
|
return reorderByPriority(sorted).slice(0, limit);
|
|
123
|
-
}, [items, query, limit,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
141
|
+
}, [items, query, limit, showAllIfEmpty, itemsWhenEmpty]);
|
|
142
|
+
// Identity follows content: the open state and the highlight bookkeeping
|
|
143
|
+
// below key off "the item set changed", and a caller re-creating `items`
|
|
144
|
+
// per render must not read as a change (it would reopen a dismissed menu
|
|
145
|
+
// on every render and never let the render-phase derivations settle).
|
|
146
|
+
var filteredItemsRef = useRef(computedFilteredItems);
|
|
147
|
+
var filteredItems = areSameItems(filteredItemsRef.current, computedFilteredItems)
|
|
148
|
+
? filteredItemsRef.current
|
|
149
|
+
: computedFilteredItems;
|
|
150
|
+
filteredItemsRef.current = filteredItems;
|
|
151
|
+
var isOpen = filteredItems.length > 0 && dismissedItems !== filteredItems;
|
|
152
|
+
var openMenu = useCallback(function () { return setDismissedItems(null); }, []);
|
|
153
|
+
var closeMenu = useCallback(function () { return setDismissedItems(filteredItemsRef.current); }, []);
|
|
154
|
+
// Highlight bookkeeping for a changed query / item set, derived during
|
|
155
|
+
// render for the same reason as the re-seed above (an effect-scheduled
|
|
156
|
+
// setState per keystroke): clearing the query drops the highlight, and a
|
|
157
|
+
// pristine session pre-selects the item matching the current value (e.g. a
|
|
158
|
+
// data-validation dropdown highlighting the cell's current entry — Excel
|
|
159
|
+
// behavior); once the user types, the filter owns the highlight. The
|
|
160
|
+
// pre-select wins over the clear, as the former effect ordering did.
|
|
161
|
+
var _h = __read(useState(null), 2), highlightSync = _h[0], setHighlightSync = _h[1];
|
|
162
|
+
if (highlightSync === null ||
|
|
163
|
+
highlightSync.query !== query ||
|
|
164
|
+
highlightSync.filteredItems !== filteredItems ||
|
|
165
|
+
highlightSync.isItemSelected !== isItemSelected) {
|
|
166
|
+
setHighlightSync({ query: query, filteredItems: filteredItems, isItemSelected: isItemSelected });
|
|
167
|
+
var nextHighlightedIndex = highlightedIndex;
|
|
168
|
+
if (!query) {
|
|
169
|
+
nextHighlightedIndex = -1;
|
|
170
|
+
}
|
|
171
|
+
if (isItemSelected && !isDirty.current) {
|
|
172
|
+
nextHighlightedIndex = filteredItems.findIndex(isItemSelected);
|
|
173
|
+
}
|
|
174
|
+
if (nextHighlightedIndex !== highlightedIndex) {
|
|
175
|
+
setHighlightedIndex(nextHighlightedIndex);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
127
178
|
// User selects a value from the dropdown
|
|
128
179
|
var onSelect = useCallback(function (value) {
|
|
129
180
|
onChange === null || onChange === void 0 ? void 0 : onChange(value);
|
|
@@ -190,30 +241,6 @@ export var useDropdown = function (_a) {
|
|
|
190
241
|
}
|
|
191
242
|
}
|
|
192
243
|
}, [isOpen, openMenu, onSelect, closeMenu]);
|
|
193
|
-
useEffect(function () {
|
|
194
|
-
if (filteredItems.length) {
|
|
195
|
-
openMenu();
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
closeMenu();
|
|
199
|
-
}
|
|
200
|
-
// If user clears the
|
|
201
|
-
if (!query) {
|
|
202
|
-
setHighlightedIndex(-1);
|
|
203
|
-
}
|
|
204
|
-
}, [query, filteredItems, closeMenu, openMenu]);
|
|
205
|
-
// Pre-select the item matching the current value (e.g. a data-validation
|
|
206
|
-
// dropdown highlighting the cell's current entry — Excel behavior). Runs
|
|
207
|
-
// only while the session is pristine (`isDirty` flips on the first typed
|
|
208
|
-
// change, handing the highlight to the filter). Declared AFTER the reset
|
|
209
|
-
// effect above so the seed wins the mount-time ordering when the query is
|
|
210
|
-
// empty (a blank cell selecting the list's empty/text-prefix entry).
|
|
211
|
-
useEffect(function () {
|
|
212
|
-
if (!isItemSelected || isDirty.current) {
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
setHighlightedIndex(filteredItems.findIndex(isItemSelected));
|
|
216
|
-
}, [filteredItems, isItemSelected]);
|
|
217
244
|
var handleSetQuery = useCallback(function (value) {
|
|
218
245
|
setQuery(value);
|
|
219
246
|
setHighlightedIndex(0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../dialog/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../dialog/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,MAAM,OAAO,CAAC;AA6C1B,eAAO,MAAM,WAAW,oKAYtB,CAAC;AAGH,eAAO,MAAM,iBAAiB,8KAY5B,CAAC;AAkBH,eAAO,MAAM,aAAa;sBAGJ,MAAM;gBACZ,WAAW,GAAG,IAAI;wCA8ChC,CAAC;AAGH,eAAO,MAAM,MAAM,uCAAuB,CAAC;AAC3C,eAAO,MAAM,aAAa,8GAA0B,CAAC;AACrD,eAAO,MAAM,WAAW,4GAAwB,CAAC;AAEjD,eAAO,MAAM,iBAAiB,4KAS5B,CAAC;AAGH,eAAO,MAAM,UAAU,GAAI,0BAGxB;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,sBAEA,CAAC"}
|
package/dist/esm/dialog/index.js
CHANGED
|
@@ -4,6 +4,18 @@ import React from "react";
|
|
|
4
4
|
import Draggable from "react-draggable";
|
|
5
5
|
import { IconButton } from "./../icon-button";
|
|
6
6
|
import { cn } from "./../utils";
|
|
7
|
+
const FOCUSABLE_SELECTOR = "a[href], button, input, select, textarea, [tabindex], [contenteditable]";
|
|
8
|
+
const TEXT_ENTRY_SELECTOR = 'input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="hidden"]), textarea, [contenteditable]:not([contenteditable="false"])';
|
|
9
|
+
const firstTabbable = (container) => {
|
|
10
|
+
for (const element of Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR))) {
|
|
11
|
+
if (element.tabIndex >= 0 &&
|
|
12
|
+
!element.hasAttribute("disabled") &&
|
|
13
|
+
element.getClientRects().length > 0) {
|
|
14
|
+
return element;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
7
19
|
const DialogPortal = ({ children, className, container, ...props }) => (React.createElement(DialogPrimitive.Portal, { container: container, ...props },
|
|
8
20
|
React.createElement("div", { className: cn("fixed inset-0 z-50 flex items-start justify-center sm:items-center pointer-events-none", className) }, children)));
|
|
9
21
|
DialogPortal.displayName = DialogPrimitive.Portal.displayName;
|
|
@@ -13,13 +25,32 @@ export const DialogDescription = React.forwardRef(({ className, ...props }, ref)
|
|
|
13
25
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
14
26
|
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (React.createElement(DialogPrimitive.Overlay, { ref: ref, className: cn("fixed inset-0 z-50 bg-rnc-background/80 transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in", className), ...props })));
|
|
15
27
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
16
|
-
export const DialogContent = React.forwardRef(({ className, portalClassName, container, children, ...props }, ref) => {
|
|
28
|
+
export const DialogContent = React.forwardRef(({ className, portalClassName, container, children, onOpenAutoFocus, ...props }, ref) => {
|
|
17
29
|
const nodeRef = useRef(null);
|
|
18
30
|
return (React.createElement(DialogPortal, { className: portalClassName, container: container },
|
|
19
31
|
React.createElement(DialogOverlay, null),
|
|
20
32
|
React.createElement("div", { className: "fixed z-50 grid w-full gap-4 animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0 pointer-events-none" },
|
|
21
33
|
React.createElement(Draggable, { handle: ".rnc-drag-handle", nodeRef: nodeRef },
|
|
22
|
-
React.createElement(DialogPrimitive.Content, { ref: nodeRef, className: cn("bg-rnc-background text-rnc-foreground shadow-lg rounded-sm border border-solid border-rnc-border pointer-events-auto min-w-0", className),
|
|
34
|
+
React.createElement(DialogPrimitive.Content, { ref: nodeRef, className: cn("bg-rnc-background text-rnc-foreground shadow-lg rounded-sm border border-solid border-rnc-border pointer-events-auto min-w-0 outline-none", className), onOpenAutoFocus: (event) => {
|
|
35
|
+
onOpenAutoFocus?.(event);
|
|
36
|
+
if (event.defaultPrevented)
|
|
37
|
+
return;
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
const content = nodeRef.current;
|
|
40
|
+
if (!content || content.contains(document.activeElement)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Radix would focus the first tabbable here. Opened from a menu
|
|
44
|
+
// item, that programmatic focus inherits the menu's
|
|
45
|
+
// :focus-visible state, so a leading tab or button paints a
|
|
46
|
+
// keyboard focus ring after a plain mouse click. Text fields
|
|
47
|
+
// always show their ring when focused, so they keep the old
|
|
48
|
+
// behaviour; anything else lands on the dialog itself and the
|
|
49
|
+
// first Tab press reaches it as before.
|
|
50
|
+
const first = firstTabbable(content);
|
|
51
|
+
const target = first && first.matches(TEXT_ENTRY_SELECTOR) ? first : content;
|
|
52
|
+
target.focus({ preventScroll: true });
|
|
53
|
+
}, ...props }, children)))));
|
|
23
54
|
});
|
|
24
55
|
// Exports
|
|
25
56
|
export const Dialog = DialogPrimitive.Root;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import type { Mention } from "@rowsncolumns/common-types";
|
|
1
2
|
import { Plugin, PluginKey } from "prosemirror-state";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { Mention } from "@rowsncolumns/common-types";
|
|
3
|
+
import type { EditorView } from "prosemirror-view";
|
|
4
|
+
import type { MentionRange, MentionState } from "./prosemirror-editor";
|
|
5
5
|
interface MentionPosition {
|
|
6
6
|
left: number;
|
|
7
7
|
top: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mentions-plugin.d.ts","sourceRoot":"","sources":["../../../editor-pm/mentions-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"mentions-plugin.d.ts","sourceRoot":"","sources":["../../../editor-pm/mentions-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAE1D,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEvE,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AACD,QAAA,MAAM,iBAAiB,yBAA0C,CAAC;AAGlE,QAAA,MAAM,aAAa,GACjB,MAAM,UAAU,EAChB,SAAS,OAAO,EAChB,OAAO,YAAY,KAClB,IAOF,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,aAAa,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC7C,cAAc,EAAE,MAAM,OAAO,CAAC;CAC/B,CAAC;AAGF,QAAA,MAAM,oBAAoB,GAAI,oCAG3B,0BAA0B,KAAG,MAAM,CAAC,YAAY,CA8GlD,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC;AAClE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -75,6 +75,17 @@ const createMentionsPlugin = ({ onChangeState, getFormulaMode, }) => {
|
|
|
75
75
|
return pluginState;
|
|
76
76
|
}
|
|
77
77
|
else {
|
|
78
|
+
// Already idle: keep the state (and its identity) as is. Every
|
|
79
|
+
// transaction reaches here while no mention is being typed — the
|
|
80
|
+
// decorations refresh dispatched from the editor's commit phase
|
|
81
|
+
// included — and notifying the host with a fresh-but-equal state
|
|
82
|
+
// each time scheduled a React re-render per transaction.
|
|
83
|
+
if (!pluginState.active &&
|
|
84
|
+
pluginState.query === "" &&
|
|
85
|
+
pluginState.range === null &&
|
|
86
|
+
pluginState.selectedIndex === 0) {
|
|
87
|
+
return pluginState;
|
|
88
|
+
}
|
|
78
89
|
const newPluginState = {
|
|
79
90
|
...pluginState,
|
|
80
91
|
active: false,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { ParsedToken } from "@rowsncolumns/calculator";
|
|
2
2
|
import type { CalculatorFunction, Mention } from "@rowsncolumns/common-types";
|
|
3
3
|
import { type FormulaLocale } from "@rowsncolumns/utils";
|
|
4
|
+
import type { Command } from "prosemirror-state";
|
|
4
5
|
import React from "react";
|
|
5
|
-
import {
|
|
6
|
+
import type { SuggestionsDropdownProps } from "../editor/suggestions-dropdown";
|
|
6
7
|
import { type RunColorResolver } from "./helpers";
|
|
7
|
-
import {
|
|
8
|
-
import { OptionItem, TextFormatRun } from "./types";
|
|
9
|
-
import { MentionTagComponentProps } from "./mention-nodeview";
|
|
8
|
+
import type { MentionTagComponentProps } from "./mention-nodeview";
|
|
9
|
+
import type { OptionItem, TextFormatRun } from "./types";
|
|
10
10
|
export type RichTextEditorAttribues = Omit<React.TextareaHTMLAttributes<HTMLDivElement>, "onChange" | "onSubmit" | "onCopy" | "onPaste" | "onCut">;
|
|
11
11
|
/**
|
|
12
12
|
* This fixes a IME bug in prosemirror
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prosemirror-editor.d.ts","sourceRoot":"","sources":["../../../editor-pm/prosemirror-editor.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prosemirror-editor.d.ts","sourceRoot":"","sources":["../../../editor-pm/prosemirror-editor.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,43 +1,45 @@
|
|
|
1
|
+
import * as Popper from "@radix-ui/react-popper";
|
|
2
|
+
import { Portal } from "@radix-ui/react-portal";
|
|
3
|
+
import { tokenVocabulary } from "@rowsncolumns/fast-formula-parser";
|
|
4
|
+
import { useCallbackRef } from "@rowsncolumns/grid";
|
|
1
5
|
import { LoadingIcon, QuestionMarkIcon } from "@rowsncolumns/icons";
|
|
6
|
+
import { DEFAULT_ARRAY } from "@rowsncolumns/spreadsheet";
|
|
2
7
|
import { canonicalizeFunctionName, clipboardHtmlToRichText, } from "@rowsncolumns/utils";
|
|
3
8
|
import { addressToCell, getHotkeyKey, isAFormula, isNil, log, } from "@rowsncolumns/utils";
|
|
4
|
-
import React, { forwardRef, memo, useCallback, useImperativeHandle, useMemo, useRef, useState, } from "react";
|
|
5
|
-
import { history, undo, redo } from "prosemirror-history";
|
|
6
|
-
import { keymap } from "prosemirror-keymap";
|
|
7
9
|
import { baseKeymap, joinBackward, toggleMark } from "prosemirror-commands";
|
|
10
|
+
import { history, redo, undo } from "prosemirror-history";
|
|
11
|
+
import { keymap } from "prosemirror-keymap";
|
|
12
|
+
import { DOMSerializer, Slice } from "prosemirror-model";
|
|
8
13
|
import { AllSelection, EditorState } from "prosemirror-state";
|
|
9
|
-
import { EditorView, DecorationSet } from "prosemirror-view";
|
|
10
14
|
import { TextSelection } from "prosemirror-state";
|
|
11
|
-
import {
|
|
15
|
+
import { DecorationSet, EditorView } from "prosemirror-view";
|
|
16
|
+
import React, { forwardRef, memo, useCallback, useImperativeHandle, useMemo, useRef, useState, } from "react";
|
|
17
|
+
import { withErrorBoundary } from "react-error-boundary";
|
|
18
|
+
import { ConditionalWrapper } from "../conditional-wrapper";
|
|
19
|
+
import { SPECIAL_ITEMS, THIS_ROW_ITEM } from "../editor/constants";
|
|
20
|
+
import { ErrorFallback } from "../editor/editor-error-boundary";
|
|
21
|
+
import { StyledFormulaHelp } from "../editor/style";
|
|
22
|
+
import { SuggestionsDropdown as DefaultSuggestionsDropdown } from "../editor/suggestions-dropdown";
|
|
12
23
|
import { useCycleFormulaReference } from "../hooks/use-cycle-reference";
|
|
13
24
|
import { useDropdown } from "../hooks/use-dropdown";
|
|
14
|
-
import { useDropdownChangePM } from "./use-dropdown-change-pm";
|
|
15
|
-
import { useEditorKeyDownPM } from "./use-editor-keydown-pm";
|
|
16
|
-
import { useEditorDecoratorPM } from "./use-editor-decorator-pm";
|
|
17
|
-
import { useEditorOnChangePM } from "./use-editor-change-pm";
|
|
18
|
-
import { createDecorationPlugin } from "./decoration-plugin";
|
|
19
|
-
import { createUnfocusedSelectionPlugin } from "./unfocused-selection-plugin";
|
|
20
|
-
import { createPlaceholderPlugin } from "./placeholder-plugin";
|
|
21
25
|
import { useIsomorphicLayoutEffect } from "../hooks/use-isomorphic-layout-effect.ts";
|
|
22
26
|
import { cn } from "../utils";
|
|
23
|
-
import {
|
|
24
|
-
import { applyTextFormatRuns, applyTextFormatToSelection,
|
|
25
|
-
import {
|
|
26
|
-
import { ErrorFallback } from "../editor/editor-error-boundary";
|
|
27
|
-
import { withErrorBoundary } from "react-error-boundary";
|
|
28
|
-
import * as Popper from "@radix-ui/react-popper";
|
|
29
|
-
import { Portal } from "@radix-ui/react-portal";
|
|
30
|
-
import { ConditionalWrapper } from "../conditional-wrapper";
|
|
31
|
-
import { schema } from "./schema";
|
|
32
|
-
import { StyledFormulaHelp } from "../editor/style";
|
|
33
|
-
import { tokenVocabulary } from "@rowsncolumns/fast-formula-parser";
|
|
34
|
-
import { createMentionsPlugin } from "./mentions-plugin";
|
|
27
|
+
import { createDecorationPlugin } from "./decoration-plugin";
|
|
28
|
+
import { applyTextFormatRuns, applyTextFormatToSelection, deserializeString, getPropertyStartIndex, getSelectionFontSize, isCellToken, serializeEditorValue, } from "./helpers";
|
|
29
|
+
import { MentionNodeView } from "./mention-nodeview";
|
|
35
30
|
import { MentionsDropdown } from "./mentions-dropdown";
|
|
31
|
+
import { createMentionsPlugin } from "./mentions-plugin";
|
|
32
|
+
import { createPlaceholderPlugin } from "./placeholder-plugin";
|
|
33
|
+
import { schema } from "./schema";
|
|
34
|
+
import { createUnfocusedSelectionPlugin } from "./unfocused-selection-plugin";
|
|
35
|
+
import { useDropdownChangePM } from "./use-dropdown-change-pm";
|
|
36
|
+
import { useEditorOnChangePM } from "./use-editor-change-pm";
|
|
37
|
+
import { useEditorDecoratorPM } from "./use-editor-decorator-pm";
|
|
38
|
+
import { useEditorKeyDownPM } from "./use-editor-keydown-pm";
|
|
36
39
|
import { useMentionKeyDown } from "./use-mention-keydown";
|
|
37
|
-
import { MentionNodeView } from "./mention-nodeview";
|
|
38
|
-
import { useCallbackRef } from "@rowsncolumns/grid";
|
|
39
40
|
import { useParameterSuggestions } from "./use-parameter-suggestions";
|
|
40
|
-
|
|
41
|
+
/** Meta key of the decorations-refresh transaction dispatched from the commit phase. */
|
|
42
|
+
const UPDATE_DECORATIONS_META = "updateDecorations";
|
|
41
43
|
/**
|
|
42
44
|
* This fixes a IME bug in prosemirror
|
|
43
45
|
* Cmd+a and delete and then entering a character
|
|
@@ -275,9 +277,20 @@ export const ProseMirrorEditorThatMayError = memo(forwardRef(({ value = "", isNe
|
|
|
275
277
|
onChangeIsEdgeOfCell: setIsEdgeOfCell,
|
|
276
278
|
onChangeParameterIndex: setParameterIndex,
|
|
277
279
|
onCellPropertyTokenChange: setCellPropertyToken,
|
|
280
|
+
// The analysis hands over fresh arrays on every run (empty ones
|
|
281
|
+
// outside a formula); only a content change may schedule a render —
|
|
282
|
+
// this runs for the formula bar's value-sync dispatch in the commit
|
|
283
|
+
// phase, where a same-content write is a second render per keystroke.
|
|
278
284
|
onChangeFunctionParameters: (params, ranges) => {
|
|
279
|
-
setParameterArguments(params
|
|
280
|
-
|
|
285
|
+
setParameterArguments((previous) => previous.length === params.length &&
|
|
286
|
+
previous.every((value, index) => value === params[index])
|
|
287
|
+
? previous
|
|
288
|
+
: params);
|
|
289
|
+
setParameterRanges((previous) => previous.length === ranges.length &&
|
|
290
|
+
previous.every((range, index) => range.start === ranges[index].start &&
|
|
291
|
+
range.end === ranges[index].end)
|
|
292
|
+
? previous
|
|
293
|
+
: ranges);
|
|
281
294
|
},
|
|
282
295
|
onChangePreviousToken: setPreviousToken,
|
|
283
296
|
enableContinuousSelection: enableContinuousSelection ?? isNil(navigationMode),
|
|
@@ -325,6 +338,15 @@ export const ProseMirrorEditorThatMayError = memo(forwardRef(({ value = "", isNe
|
|
|
325
338
|
}),
|
|
326
339
|
keymap({
|
|
327
340
|
...baseKeymap,
|
|
341
|
+
// While the grid is navigating, this editor is the invisible sticky buffer and
|
|
342
|
+
// select-all belongs to the GRID (Ctrl/Cmd+A selects the current region). Letting
|
|
343
|
+
// the base binding run left an `AllSelection` in the hidden document that the next
|
|
344
|
+
// seeded value inherited — the first typed character then replaced the seed
|
|
345
|
+
// (Athena-Intel/demo-app-monorepo#37167 UI1-1). Declining lets the grid's own
|
|
346
|
+
// keydown handler take the key (it prevents the native select-all default).
|
|
347
|
+
"Mod-a": (state, dispatch, view) => navigationModeRef.current
|
|
348
|
+
? false
|
|
349
|
+
: baseKeymap["Mod-a"](state, dispatch, view),
|
|
328
350
|
Backspace: (state, dispatch, view) => {
|
|
329
351
|
if (view?.composing) {
|
|
330
352
|
return false;
|
|
@@ -447,8 +469,18 @@ export const ProseMirrorEditorThatMayError = memo(forwardRef(({ value = "", isNe
|
|
|
447
469
|
try {
|
|
448
470
|
const newState = view.state.apply(transaction);
|
|
449
471
|
view.updateState(newState);
|
|
450
|
-
// Call the onChange handler which will handle all token
|
|
451
|
-
|
|
472
|
+
// Call the onChange handler which will handle all token
|
|
473
|
+
// analysis and state updates. A caret-driven decorations
|
|
474
|
+
// refresh (dispatched from the commit phase below) changes
|
|
475
|
+
// neither the document nor the selection, so re-running the
|
|
476
|
+
// analysis would only re-emit the state that triggered it —
|
|
477
|
+
// and every setState from the commit phase costs a second
|
|
478
|
+
// render per keystroke (see the burst-typing spec).
|
|
479
|
+
const decorationsMeta = transaction.getMeta(UPDATE_DECORATIONS_META);
|
|
480
|
+
const caretOnlyRefresh = decorationsMeta?.caretOnly === true &&
|
|
481
|
+
!transaction.docChanged &&
|
|
482
|
+
!transaction.selectionSet;
|
|
483
|
+
if (!navigationModeRef.current && !caretOnlyRefresh) {
|
|
452
484
|
onEditorChange(newState);
|
|
453
485
|
}
|
|
454
486
|
}
|
|
@@ -561,6 +593,15 @@ export const ProseMirrorEditorThatMayError = memo(forwardRef(({ value = "", isNe
|
|
|
561
593
|
if (currentContent !== value) {
|
|
562
594
|
const newDoc = createInitialDocument();
|
|
563
595
|
const tr = viewRef.current.state.tr.replaceWith(0, viewRef.current.state.doc.content.size, newDoc.content);
|
|
596
|
+
// A whole-document replacement is a fresh seed (an `editCell(value)` open, the
|
|
597
|
+
// formula bar echoing the cell): the caret belongs after the seeded text. A cursor
|
|
598
|
+
// already maps there through the replace step, but an `AllSelection` maps to an
|
|
599
|
+
// `AllSelection` over the NEW document — so the next typed character replaced the
|
|
600
|
+
// seed (`=` then `7*6` came out as `7*6`, Athena-Intel/demo-app-monorepo#37167
|
|
601
|
+
// UI1-1). Collapse it to a caret at the end.
|
|
602
|
+
if (tr.selection instanceof AllSelection) {
|
|
603
|
+
tr.setSelection(TextSelection.atEnd(tr.doc));
|
|
604
|
+
}
|
|
564
605
|
viewRef.current.dispatch(tr);
|
|
565
606
|
}
|
|
566
607
|
}
|
|
@@ -569,18 +610,29 @@ export const ProseMirrorEditorThatMayError = memo(forwardRef(({ value = "", isNe
|
|
|
569
610
|
}
|
|
570
611
|
}
|
|
571
612
|
}, [value, createInitialDocument]);
|
|
572
|
-
// Update decorations when formula mode
|
|
613
|
+
// Update decorations when formula mode, active state or the caret
|
|
614
|
+
// position changes. A change of mode/active state re-runs the token
|
|
615
|
+
// analysis (it depends on `isActive`); a caret-only refresh is tagged so
|
|
616
|
+
// `dispatchTransaction` skips the analysis — the caret position came
|
|
617
|
+
// out of that very analysis, so re-running it is a no-op.
|
|
618
|
+
const decorationsContextRef = useRef({ formulaMode, isActive });
|
|
573
619
|
useIsomorphicLayoutEffect(() => {
|
|
574
620
|
if (navigationModeRef.current)
|
|
575
621
|
return;
|
|
622
|
+
const previous = decorationsContextRef.current;
|
|
623
|
+
decorationsContextRef.current = { formulaMode, isActive };
|
|
624
|
+
const caretOnly = previous.formulaMode === formulaMode &&
|
|
625
|
+
previous.isActive === isActive;
|
|
576
626
|
if (viewRef.current) {
|
|
577
627
|
try {
|
|
578
628
|
// Force a decoration update by dispatching a metadata transaction
|
|
579
|
-
const
|
|
629
|
+
const meta = {
|
|
580
630
|
formulaMode,
|
|
581
631
|
isActive,
|
|
582
632
|
cursorPosition,
|
|
583
|
-
|
|
633
|
+
caretOnly,
|
|
634
|
+
};
|
|
635
|
+
const tr = viewRef.current.state.tr.setMeta(UPDATE_DECORATIONS_META, meta);
|
|
584
636
|
viewRef.current.dispatch(tr);
|
|
585
637
|
}
|
|
586
638
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-parameter-suggestions.d.ts","sourceRoot":"","sources":["../../../editor-pm/use-parameter-suggestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"use-parameter-suggestions.d.ts","sourceRoot":"","sources":["../../../editor-pm/use-parameter-suggestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAI5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,KAAK,MAAM,GAAG;IACZ,aAAa,EAAE,WAAW,GAAG,SAAS,CAAC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,6BAA6B,CAAC,EAAE,CAC9B,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAAE,KACjB,OAAO,CAAC;IACb,+BAA+B,CAAC,EAAE,CAChC,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAAE,KAElB,UAAU,EAAE,GACZ,SAAS,GACT,OAAO,CAAC,UAAU,EAAE,GAAG,SAAS,CAAC,GACjC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CAC3B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAAI,wHAMrC,MAAM;;;CA4FR,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
1
|
import { DEFAULT_ARRAY } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
/**
|
|
4
4
|
* Fetch parameter suggestions (sync or async) for the active function.
|
|
5
5
|
* Ensures stale responses are ignored when dependency changes mid-flight.
|
|
@@ -8,6 +8,24 @@ export const useParameterSuggestions = ({ functionToken, parameterIndex, paramet
|
|
|
8
8
|
const [parameterSuggestions, setSuggestions] = useState([]);
|
|
9
9
|
const [isFetchingParameters, setIsFetchingParameters] = useState(false);
|
|
10
10
|
const requestIdRef = useRef(0);
|
|
11
|
+
// Mirrors of the two states so the effect below only writes on a real
|
|
12
|
+
// change: a same-value setState from the commit phase still schedules a
|
|
13
|
+
// render when the fiber is mid-update, and this effect re-runs on every
|
|
14
|
+
// keystroke inside a function call (`parameterArgsKey`).
|
|
15
|
+
const suggestionsRef = useRef(parameterSuggestions);
|
|
16
|
+
const isFetchingRef = useRef(isFetchingParameters);
|
|
17
|
+
const writeSuggestions = (next) => {
|
|
18
|
+
if (suggestionsRef.current === next)
|
|
19
|
+
return;
|
|
20
|
+
suggestionsRef.current = next;
|
|
21
|
+
setSuggestions(next);
|
|
22
|
+
};
|
|
23
|
+
const writeIsFetching = (next) => {
|
|
24
|
+
if (isFetchingRef.current === next)
|
|
25
|
+
return;
|
|
26
|
+
isFetchingRef.current = next;
|
|
27
|
+
setIsFetchingParameters(next);
|
|
28
|
+
};
|
|
11
29
|
const functionName = functionToken?.image ?? "";
|
|
12
30
|
const hasFunctionToken = Boolean(functionToken);
|
|
13
31
|
const parameterArgsKey = useMemo(() => JSON.stringify(parameterArguments ?? []), [parameterArguments]);
|
|
@@ -15,35 +33,35 @@ export const useParameterSuggestions = ({ functionToken, parameterIndex, paramet
|
|
|
15
33
|
requestIdRef.current += 1;
|
|
16
34
|
const requestId = requestIdRef.current;
|
|
17
35
|
if (!hasFunctionToken || !getFunctionParameterSuggestions) {
|
|
18
|
-
|
|
19
|
-
|
|
36
|
+
writeIsFetching(false);
|
|
37
|
+
writeSuggestions(DEFAULT_ARRAY);
|
|
20
38
|
return;
|
|
21
39
|
}
|
|
22
40
|
if (shouldFetchFunctionParameters &&
|
|
23
41
|
!shouldFetchFunctionParameters(functionName, parameterIndex, parameterArguments)) {
|
|
24
|
-
|
|
25
|
-
|
|
42
|
+
writeIsFetching(false);
|
|
43
|
+
writeSuggestions(DEFAULT_ARRAY);
|
|
26
44
|
return;
|
|
27
45
|
}
|
|
28
46
|
let cancelled = false;
|
|
29
47
|
const run = async () => {
|
|
30
48
|
try {
|
|
31
|
-
|
|
49
|
+
writeIsFetching(true);
|
|
32
50
|
const result = await getFunctionParameterSuggestions(functionName, parameterIndex, parameterArguments);
|
|
33
51
|
if (!cancelled && requestIdRef.current === requestId) {
|
|
34
|
-
|
|
52
|
+
writeSuggestions(result ?? []);
|
|
35
53
|
}
|
|
36
54
|
}
|
|
37
55
|
catch (error) {
|
|
38
56
|
// Keep dropdown stable on errors instead of throwing
|
|
39
57
|
if (!cancelled && requestIdRef.current === requestId) {
|
|
40
58
|
console.warn("Error fetching parameter suggestions", error);
|
|
41
|
-
|
|
59
|
+
writeSuggestions([]);
|
|
42
60
|
}
|
|
43
61
|
}
|
|
44
62
|
finally {
|
|
45
63
|
if (!cancelled && requestIdRef.current === requestId) {
|
|
46
|
-
|
|
64
|
+
writeIsFetching(false);
|
|
47
65
|
}
|
|
48
66
|
}
|
|
49
67
|
};
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
+
import type { Maybe } from "@rowsncolumns/common-types";
|
|
1
2
|
import type React from "react";
|
|
2
|
-
import {
|
|
3
|
-
import { OptionItem } from "../editor-pm/types.js";
|
|
3
|
+
import type { OptionItem } from "../editor-pm/types.js";
|
|
4
4
|
type UseDropdownProps<T> = {
|
|
5
5
|
items: T[] | undefined;
|
|
6
6
|
initialQuery?: string;
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* No longer read: the menu is open exactly when it has items to show and
|
|
9
|
+
* was not dismissed (Escape) for that item set — which is the state the
|
|
10
|
+
* former open/close effect settled on right after mount anyway. Kept so
|
|
11
|
+
* existing call sites type-check.
|
|
12
|
+
*/
|
|
13
|
+
initialOpen?: boolean;
|
|
8
14
|
initialHighlightedIndex: number;
|
|
9
15
|
limit?: number;
|
|
10
16
|
showAllIfEmpty?: boolean;
|
|
11
17
|
isNewValue?: boolean;
|
|
12
18
|
itemsWhenEmpty?: T[];
|
|
13
|
-
|
|
19
|
+
/** Not read by the hook (items are matched on `title`); kept for call sites. */
|
|
20
|
+
itemToString?(item: T): string;
|
|
14
21
|
onChange(value: T): void;
|
|
15
22
|
/**
|
|
16
23
|
* Marks the item that matches the current (pre-edit) value so the dropdown
|
|
@@ -22,7 +29,7 @@ type UseDropdownProps<T> = {
|
|
|
22
29
|
};
|
|
23
30
|
export declare const sortByUnderscore: <T extends OptionItem>(a: Maybe<T>, b: Maybe<T>) => 0 | 1 | -1;
|
|
24
31
|
export declare const sanitizeDropdownQuery: (value: string) => string;
|
|
25
|
-
export declare const useDropdown: <T extends OptionItem>({
|
|
32
|
+
export declare const useDropdown: <T extends OptionItem>({ initialHighlightedIndex, initialQuery, onChange, items, isNewValue, limit, showAllIfEmpty, itemsWhenEmpty, isItemSelected, }: UseDropdownProps<T>) => {
|
|
26
33
|
isOpen: boolean;
|
|
27
34
|
highlightedIndex: number;
|
|
28
35
|
onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => void;
|