@lexical/react 0.45.1-nightly.20260622.0 → 0.45.1-nightly.20260623.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/LexicalNodeMenuPlugin.dev.js +2 -45
- package/dist/LexicalNodeMenuPlugin.dev.mjs +3 -46
- package/dist/LexicalNodeMenuPlugin.prod.js +1 -1
- package/dist/LexicalNodeMenuPlugin.prod.mjs +1 -1
- package/dist/LexicalTypeaheadMenuPlugin.d.ts +3 -1
- package/dist/LexicalTypeaheadMenuPlugin.dev.js +4 -45
- package/dist/LexicalTypeaheadMenuPlugin.dev.mjs +5 -46
- package/dist/LexicalTypeaheadMenuPlugin.prod.js +1 -1
- package/dist/LexicalTypeaheadMenuPlugin.prod.mjs +1 -1
- package/package.json +19 -19
- package/src/LexicalTypeaheadMenuPlugin.tsx +3 -1
- package/src/shared/LexicalMenu.tsx +1 -1
- package/dist/shared/getScrollParent.d.ts +0 -19
- package/src/shared/getScrollParent.ts +0 -54
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
12
12
|
var lexical = require('lexical');
|
|
13
13
|
var React = require('react');
|
|
14
|
+
var utils = require('@lexical/utils');
|
|
14
15
|
var ReactDOM = require('react-dom');
|
|
15
16
|
var jsxRuntime = require('react/jsx-runtime');
|
|
16
17
|
|
|
@@ -23,50 +24,6 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
23
24
|
*/
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
// Got from https://stackoverflow.com/a/42543908/2013580
|
|
27
|
-
/**
|
|
28
|
-
* Walks up from `element` and returns the nearest scrollable ancestor (or
|
|
29
|
-
* `ownerDocument.body` if none is found), used to keep the active typeahead
|
|
30
|
-
* option scrolled into view. Set `includeHidden` to also treat
|
|
31
|
-
* `overflow: hidden` ancestors as scroll parents.
|
|
32
|
-
*
|
|
33
|
-
* The walk crosses ShadowRoot→host (via `getParentElement`) so a
|
|
34
|
-
* shadow-mounted editor's scroll parent is found in the enclosing light-DOM
|
|
35
|
-
* ancestor chain, and the styles / body are resolved through the element's
|
|
36
|
-
* own realm so an iframe-mounted editor stays inside its document.
|
|
37
|
-
*/
|
|
38
|
-
function getScrollParent(element, includeHidden) {
|
|
39
|
-
// Resolve through the element's own realm so an iframe-mounted editor's
|
|
40
|
-
// scroll parent and computed styles come from its document, not the top one.
|
|
41
|
-
const ownerDocument = element.ownerDocument;
|
|
42
|
-
const win = ownerDocument.defaultView || window;
|
|
43
|
-
let style = win.getComputedStyle(element);
|
|
44
|
-
const excludeStaticParent = style.position === 'absolute';
|
|
45
|
-
const overflowRegex = /(auto|scroll)/;
|
|
46
|
-
if (style.position === 'fixed') {
|
|
47
|
-
return ownerDocument.body;
|
|
48
|
-
}
|
|
49
|
-
for (let parent = element; parent = lexical.getParentElement(parent);) {
|
|
50
|
-
style = win.getComputedStyle(parent);
|
|
51
|
-
if (excludeStaticParent && style.position === 'static') {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
|
|
55
|
-
return parent;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return ownerDocument.body;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
63
|
-
*
|
|
64
|
-
* This source code is licensed under the MIT license found in the
|
|
65
|
-
* LICENSE file in the root directory of this source tree.
|
|
66
|
-
*
|
|
67
|
-
*/
|
|
68
|
-
|
|
69
|
-
|
|
70
27
|
// This workaround is no longer necessary in React 19,
|
|
71
28
|
// but we currently support React >=17.x
|
|
72
29
|
// https://github.com/facebook/react/pull/26395
|
|
@@ -200,7 +157,7 @@ function useDynamicPositioning(resolution, targetElement, onReposition, onVisibi
|
|
|
200
157
|
React.useEffect(() => {
|
|
201
158
|
if (targetElement != null && resolution != null) {
|
|
202
159
|
const rootElement = editor.getRootElement();
|
|
203
|
-
const rootScrollParent = rootElement != null ? getScrollParent(rootElement) : document.body;
|
|
160
|
+
const rootScrollParent = rootElement != null ? utils.getScrollParent(rootElement, false) : document.body;
|
|
204
161
|
let ticking = false;
|
|
205
162
|
let previousIsInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);
|
|
206
163
|
const handleScroll = function () {
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
10
|
-
import {
|
|
10
|
+
import { CAN_USE_DOM, mergeRegister, COMMAND_PRIORITY_LOW, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, isDOMShadowRoot, getDOMShadowRoots, $getSelection, $isRangeSelection, createCommand, $getNodeByKey } from 'lexical';
|
|
11
11
|
import React, { useLayoutEffect, useEffect, useRef, useCallback, useState, useMemo } from 'react';
|
|
12
|
+
import { getScrollParent } from '@lexical/utils';
|
|
12
13
|
import ReactDOM from 'react-dom';
|
|
13
14
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
14
15
|
|
|
@@ -21,50 +22,6 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
21
22
|
*/
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
// Got from https://stackoverflow.com/a/42543908/2013580
|
|
25
|
-
/**
|
|
26
|
-
* Walks up from `element` and returns the nearest scrollable ancestor (or
|
|
27
|
-
* `ownerDocument.body` if none is found), used to keep the active typeahead
|
|
28
|
-
* option scrolled into view. Set `includeHidden` to also treat
|
|
29
|
-
* `overflow: hidden` ancestors as scroll parents.
|
|
30
|
-
*
|
|
31
|
-
* The walk crosses ShadowRoot→host (via `getParentElement`) so a
|
|
32
|
-
* shadow-mounted editor's scroll parent is found in the enclosing light-DOM
|
|
33
|
-
* ancestor chain, and the styles / body are resolved through the element's
|
|
34
|
-
* own realm so an iframe-mounted editor stays inside its document.
|
|
35
|
-
*/
|
|
36
|
-
function getScrollParent(element, includeHidden) {
|
|
37
|
-
// Resolve through the element's own realm so an iframe-mounted editor's
|
|
38
|
-
// scroll parent and computed styles come from its document, not the top one.
|
|
39
|
-
const ownerDocument = element.ownerDocument;
|
|
40
|
-
const win = ownerDocument.defaultView || window;
|
|
41
|
-
let style = win.getComputedStyle(element);
|
|
42
|
-
const excludeStaticParent = style.position === 'absolute';
|
|
43
|
-
const overflowRegex = /(auto|scroll)/;
|
|
44
|
-
if (style.position === 'fixed') {
|
|
45
|
-
return ownerDocument.body;
|
|
46
|
-
}
|
|
47
|
-
for (let parent = element; parent = getParentElement(parent);) {
|
|
48
|
-
style = win.getComputedStyle(parent);
|
|
49
|
-
if (excludeStaticParent && style.position === 'static') {
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
|
|
53
|
-
return parent;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return ownerDocument.body;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
61
|
-
*
|
|
62
|
-
* This source code is licensed under the MIT license found in the
|
|
63
|
-
* LICENSE file in the root directory of this source tree.
|
|
64
|
-
*
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
|
|
68
25
|
// This workaround is no longer necessary in React 19,
|
|
69
26
|
// but we currently support React >=17.x
|
|
70
27
|
// https://github.com/facebook/react/pull/26395
|
|
@@ -198,7 +155,7 @@ function useDynamicPositioning(resolution, targetElement, onReposition, onVisibi
|
|
|
198
155
|
useEffect(() => {
|
|
199
156
|
if (targetElement != null && resolution != null) {
|
|
200
157
|
const rootElement = editor.getRootElement();
|
|
201
|
-
const rootScrollParent = rootElement != null ? getScrollParent(rootElement) : document.body;
|
|
158
|
+
const rootScrollParent = rootElement != null ? getScrollParent(rootElement, false) : document.body;
|
|
202
159
|
let ticking = false;
|
|
203
160
|
let previousIsInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);
|
|
204
161
|
const handleScroll = function () {
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("lexical"),n=require("react"),o=require("react-dom"),
|
|
9
|
+
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("lexical"),n=require("react"),l=require("@lexical/utils"),o=require("react-dom"),r=require("react/jsx-runtime");const i=t.CAN_USE_DOM?n.useLayoutEffect:n.useEffect;const s=e=>{const t=e.closest("#typeahead-menu");if(!t)return;const n=t.getBoundingClientRect();n.top+n.height>window.innerHeight&&t.scrollIntoView({block:"center"}),n.top<0&&t.scrollIntoView({block:"center"}),e.scrollIntoView({block:"nearest"})};function u(e,t){const n=e.getBoundingClientRect(),l=t.getBoundingClientRect();return n.top>=l.top-6&&n.top<=l.bottom+6}const c=/* @__PURE__ */t.createCommand("SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND");function a({index:e,isSelected:t,onClick:n,onMouseEnter:l,option:o}){let i="item";return t&&(i+=" selected"),/*#__PURE__*/r.jsxs("li",{tabIndex:-1,className:i,ref:o.setRefElement,role:"option","aria-selected":t,id:"typeahead-item-"+e,onMouseEnter:l,onClick:n,children:[o.icon,/*#__PURE__*/r.jsx("span",{className:"text",children:o.title})]},o.key)}function d({close:e,editor:l,anchorElementRef:u,resolution:d,options:m,menuRenderFn:p,onSelectOption:f,shouldSplitNodeWithQuery:g=!1,commandPriority:h=t.COMMAND_PRIORITY_LOW,preselectFirstItem:C=!0}){const[E,R]=n.useState(null),x=null!==E?Math.min(m.length-1,E):null,y=d.match&&d.match.matchingString;n.useEffect(()=>{C&&R(0)},[y,C]);const b=n.useCallback(n=>{l.update(()=>{const l=null!=d.match&&g?function(e){const n=t.$getSelection();if(!t.$isRangeSelection(n)||!n.isCollapsed())return null;const l=n.anchor;if("text"!==l.type)return null;const o=l.getNode();if(!o.isSimpleText())return null;const r=l.offset,i=o.getTextContent().slice(0,r),s=e.replaceableString.length,u=r-function(e,t,n){let l=n;for(let n=l;n<=t.length;n++)e.slice(-n)===t.substring(0,n)&&(l=n);return l}(i,e.matchingString,s);if(u<0)return null;let c;return 0===u?[c]=o.splitText(r):[,c]=o.splitText(u,r),c}(d.match):null;f(n,l,e,d.match?d.match.matchingString:"")})},[l,g,d.match,f,e]),O=n.useCallback(e=>{const t=l.getRootElement();null!==t&&(t.setAttribute("aria-activedescendant","typeahead-item-"+e),R(e))},[l]),v=n.useCallback(()=>u.current&&m.length?/*#__PURE__*/o.createPortal(/*#__PURE__*/r.jsx("div",{className:"typeahead-popover mentions-menu",children:/*#__PURE__*/r.jsx("ul",{children:m.map((e,t)=>/*#__PURE__*/r.jsx(a,{index:t,isSelected:x===t,onClick:()=>{R(t),b(e)},onMouseEnter:()=>{R(t)},option:e},e.key))})}),u.current):null,[u,m,x,b,R]);n.useEffect(()=>()=>{const e=l.getRootElement();null!==e&&e.removeAttribute("aria-activedescendant")},[l]),i(()=>{null===m?R(null):null===x&&C&&O(0)},[m,x,O,C]),n.useEffect(()=>t.mergeRegister(l.registerCommand(c,({option:e})=>!(!e.ref||null==e.ref.current)&&(s(e.ref.current),!0),h)),[l,O,h]),n.useEffect(()=>t.mergeRegister(l.registerCommand(t.KEY_ARROW_DOWN_COMMAND,e=>{const t=e;if(null!==m&&m.length){const e=null===x?0:x!==m.length-1?x+1:0;O(e);const n=m[e];if(!n)return O(-1),t.preventDefault(),t.stopImmediatePropagation(),!0;n.ref&&n.ref.current&&l.dispatchCommand(c,{index:e,option:n}),t.preventDefault(),t.stopImmediatePropagation()}return!0},h),l.registerCommand(t.KEY_ARROW_UP_COMMAND,e=>{const t=e;if(null!==m&&m.length){const e=null===x?m.length-1:0!==x?x-1:m.length-1;O(e);const n=m[e];if(!n)return O(-1),t.preventDefault(),t.stopImmediatePropagation(),!0;n.ref&&n.ref.current&&s(n.ref.current),t.preventDefault(),t.stopImmediatePropagation()}return!0},h),l.registerCommand(t.KEY_ESCAPE_COMMAND,t=>{const n=t;return n.preventDefault(),n.stopImmediatePropagation(),e(),!0},h),l.registerCommand(t.KEY_TAB_COMMAND,e=>{const t=e;return null!==m&&null!==x&&null!=m[x]&&(t.preventDefault(),t.stopImmediatePropagation(),b(m[x]),!0)},h),l.registerCommand(t.KEY_ENTER_COMMAND,e=>!(null===m||null===x||null==m[x]||e&&e.shiftKey)&&(null!==e&&(e.preventDefault(),e.stopImmediatePropagation()),b(m[x]),!0),h)),[b,e,l,m,x,O,h]);const M=n.useMemo(()=>({options:m,selectOptionAndCleanUp:b,selectedIndex:x,setHighlightedIndex:R}),[b,x,m]);return null!=p?p(u,M,d.match?d.match.matchingString:""):v()}function m(e,t){null!=t&&(e.className=t),e.setAttribute("aria-label","Typeahead menu"),e.setAttribute("role","listbox"),e.style.display="block",e.style.position="absolute"}function p(o,r,i,s,c=!0){const[a]=e.useLexicalComposerContext(),d=s??function(e){if(!t.CAN_USE_DOM)return;const n=e.getRootElement();if(null!==n){const e=n.getRootNode();if(t.isDOMShadowRoot(e))return e}return document.body}(a),p=t.CAN_USE_DOM?document.createElement("div"):null,f=n.useRef(p),g=n.useCallback(()=>{if(null===f.current||void 0===d)return;f.current.style.top=f.current.style.bottom;const e=a.getRootElement(),t=f.current,n=t.firstChild;if(null!==e&&null!==o){const{left:l,top:r,width:s,height:u}=o.getRect(),a=f.current.offsetHeight;if(t.style.top=`${r+a+3+(c?window.pageYOffset:0)}px`,t.style.left=`${l+window.pageXOffset}px`,t.style.height=`${u}px`,t.style.width=`${s}px`,null!==n){n.style.top=`${r}`;const o=n.getBoundingClientRect(),i=o.height,s=o.width,a=e.getBoundingClientRect();l+s>a.right&&(t.style.left=`${a.right-s+window.pageXOffset}px`),(r+i>window.innerHeight||r+i>a.bottom)&&r-a.top>i+u&&(t.style.top=`${r-i-u+(c?window.pageYOffset:0)}px`)}t.isConnected||(m(t,i),d.append(t)),t.setAttribute("id","typeahead-menu"),e.setAttribute("aria-controls","typeahead-menu")}},[a,o,c,i,d]);n.useEffect(()=>{const e=a.getRootElement();return null!==o&&g(),()=>{null!==e&&e.removeAttribute("aria-controls");const t=f.current;null!==t&&t.isConnected&&(t.remove(),t.removeAttribute("id"))}},[a,g,o]);const h=n.useCallback(e=>{null!==o&&(e||r(null))},[o,r]);return function(o,r,i,s){const[c]=e.useLexicalComposerContext();n.useEffect(()=>{if(null!=r&&null!=o){const e=c.getRootElement(),n=null!=e?l.getScrollParent(e,!1):document.body;let o=!1,a=u(r,n);const d=function(){o||(window.requestAnimationFrame(function(){i(),o=!1}),o=!0);const e=u(r,n);e!==a&&(a=e,null!=s&&s(e))},m=new ResizeObserver(i);window.addEventListener("resize",i),document.addEventListener("scroll",d,{capture:!0,passive:!0});const p=e??r,f=t.getDOMShadowRoots(p);for(const e of f)e.addEventListener("scroll",d,{capture:!0,passive:!0});return m.observe(r),()=>{m.unobserve(r),window.removeEventListener("resize",i),document.removeEventListener("scroll",d,!0);for(const e of f)e.removeEventListener("scroll",d,!0)}}},[r,c,s,i,o])}(o,f.current,g,h),null!=p&&p===f.current&&(m(p,i),null!=d&&d.append(p)),f}const f="startTransition";exports.LexicalNodeMenuPlugin=function({options:l,nodeKey:o,onClose:i,onOpen:s,onSelectOption:u,menuRenderFn:c,anchorClassName:a,commandPriority:m=t.COMMAND_PRIORITY_LOW,parent:g}){const[h]=e.useLexicalComposerContext(),[C,E]=n.useState(null),R=p(C,E,a,g),x=n.useCallback(()=>{E(null),null!=i&&null!==C&&i()},[i,C]),y=n.useCallback(e=>{E(e),null!=s&&null===C&&s(e)},[s,C]),b=n.useCallback(()=>{o?h.update(()=>{const e=t.$getNodeByKey(o),l=h.getElementByKey(o);var r;null!=e&&null!=l&&null==C&&(r=()=>y({getRect:()=>l.getBoundingClientRect()}),f in n?n[f](r):r())}):null==o&&null!=C&&x()},[x,h,o,y,C]);return n.useEffect(()=>{b()},[b,o]),n.useEffect(()=>{if(null!=o)return h.registerUpdateListener(({dirtyElements:e})=>{e.get(o)&&b()})},[h,b,o]),null===R.current||null===C||null===h?null:/*#__PURE__*/r.jsx(d,{close:x,resolution:C,editor:h,anchorElementRef:R,options:l,menuRenderFn:c,onSelectOption:u,commandPriority:m})},exports.MenuOption=class{key;ref;icon;title;constructor(e){this.key=e,this.ref={current:null},this.setRefElement=this.setRefElement.bind(this)}setRefElement(e){this.ref={current:e}}};
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import{useLexicalComposerContext as e}from"@lexical/react/LexicalComposerContext";import{
|
|
9
|
+
import{useLexicalComposerContext as e}from"@lexical/react/LexicalComposerContext";import{CAN_USE_DOM as t,mergeRegister as n,COMMAND_PRIORITY_LOW as o,KEY_ARROW_DOWN_COMMAND as l,KEY_ARROW_UP_COMMAND as r,KEY_ESCAPE_COMMAND as i,KEY_TAB_COMMAND as s,KEY_ENTER_COMMAND as c,isDOMShadowRoot as u,getDOMShadowRoots as a,$getSelection as m,$isRangeSelection as d,createCommand as p,$getNodeByKey as f}from"lexical";import g,{useLayoutEffect as h,useEffect as y,useRef as v,useCallback as C,useState as b,useMemo as E}from"react";import{getScrollParent as x}from"@lexical/utils";import R from"react-dom";import{jsx as w,jsxs as I}from"react/jsx-runtime";const O=t?h:y;class A{key;ref;icon;title;constructor(e){this.key=e,this.ref={current:null},this.setRefElement=this.setRefElement.bind(this)}setRefElement(e){this.ref={current:e}}}const P=e=>{const t=e.closest("#typeahead-menu");if(!t)return;const n=t.getBoundingClientRect();n.top+n.height>window.innerHeight&&t.scrollIntoView({block:"center"}),n.top<0&&t.scrollIntoView({block:"center"}),e.scrollIntoView({block:"nearest"})};function S(e,t){const n=e.getBoundingClientRect(),o=t.getBoundingClientRect();return n.top>=o.top-6&&n.top<=o.bottom+6}const k=/* @__PURE__ */p("SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND");function N({index:e,isSelected:t,onClick:n,onMouseEnter:o,option:l}){let r="item";return t&&(r+=" selected"),/*#__PURE__*/I("li",{tabIndex:-1,className:r,ref:l.setRefElement,role:"option","aria-selected":t,id:"typeahead-item-"+e,onMouseEnter:o,onClick:n,children:[l.icon,/*#__PURE__*/w("span",{className:"text",children:l.title})]},l.key)}function L({close:e,editor:t,anchorElementRef:u,resolution:a,options:p,menuRenderFn:f,onSelectOption:g,shouldSplitNodeWithQuery:h=!1,commandPriority:v=o,preselectFirstItem:x=!0}){const[I,A]=b(null),S=null!==I?Math.min(p.length-1,I):null,L=a.match&&a.match.matchingString;y(()=>{x&&A(0)},[L,x]);const D=C(n=>{t.update(()=>{const t=null!=a.match&&h?function(e){const t=m();if(!d(t)||!t.isCollapsed())return null;const n=t.anchor;if("text"!==n.type)return null;const o=n.getNode();if(!o.isSimpleText())return null;const l=n.offset,r=o.getTextContent().slice(0,l),i=e.replaceableString.length,s=l-function(e,t,n){let o=n;for(let n=o;n<=t.length;n++)e.slice(-n)===t.substring(0,n)&&(o=n);return o}(r,e.matchingString,i);if(s<0)return null;let c;return 0===s?[c]=o.splitText(l):[,c]=o.splitText(s,l),c}(a.match):null;g(n,t,e,a.match?a.match.matchingString:"")})},[t,h,a.match,g,e]),T=C(e=>{const n=t.getRootElement();null!==n&&(n.setAttribute("aria-activedescendant","typeahead-item-"+e),A(e))},[t]),B=C(()=>u.current&&p.length?/*#__PURE__*/R.createPortal(/*#__PURE__*/w("div",{className:"typeahead-popover mentions-menu",children:/*#__PURE__*/w("ul",{children:p.map((e,t)=>/*#__PURE__*/w(N,{index:t,isSelected:S===t,onClick:()=>{A(t),D(e)},onMouseEnter:()=>{A(t)},option:e},e.key))})}),u.current):null,[u,p,S,D,A]);y(()=>()=>{const e=t.getRootElement();null!==e&&e.removeAttribute("aria-activedescendant")},[t]),O(()=>{null===p?A(null):null===S&&x&&T(0)},[p,S,T,x]),y(()=>n(t.registerCommand(k,({option:e})=>!(!e.ref||null==e.ref.current)&&(P(e.ref.current),!0),v)),[t,T,v]),y(()=>n(t.registerCommand(l,e=>{const n=e;if(null!==p&&p.length){const e=null===S?0:S!==p.length-1?S+1:0;T(e);const o=p[e];if(!o)return T(-1),n.preventDefault(),n.stopImmediatePropagation(),!0;o.ref&&o.ref.current&&t.dispatchCommand(k,{index:e,option:o}),n.preventDefault(),n.stopImmediatePropagation()}return!0},v),t.registerCommand(r,e=>{const t=e;if(null!==p&&p.length){const e=null===S?p.length-1:0!==S?S-1:p.length-1;T(e);const n=p[e];if(!n)return T(-1),t.preventDefault(),t.stopImmediatePropagation(),!0;n.ref&&n.ref.current&&P(n.ref.current),t.preventDefault(),t.stopImmediatePropagation()}return!0},v),t.registerCommand(i,t=>{const n=t;return n.preventDefault(),n.stopImmediatePropagation(),e(),!0},v),t.registerCommand(s,e=>{const t=e;return null!==p&&null!==S&&null!=p[S]&&(t.preventDefault(),t.stopImmediatePropagation(),D(p[S]),!0)},v),t.registerCommand(c,e=>!(null===p||null===S||null==p[S]||e&&e.shiftKey)&&(null!==e&&(e.preventDefault(),e.stopImmediatePropagation()),D(p[S]),!0),v)),[D,e,t,p,S,T,v]);const $=E(()=>({options:p,selectOptionAndCleanUp:D,selectedIndex:S,setHighlightedIndex:A}),[D,S,p]);return null!=f?f(u,$,a.match?a.match.matchingString:""):B()}function D(e,t){null!=t&&(e.className=t),e.setAttribute("aria-label","Typeahead menu"),e.setAttribute("role","listbox"),e.style.display="block",e.style.position="absolute"}function T(n,o,l,r,i=!0){const[s]=e(),c=r??function(e){if(!t)return;const n=e.getRootElement();if(null!==n){const e=n.getRootNode();if(u(e))return e}return document.body}(s),m=t?document.createElement("div"):null,d=v(m),p=C(()=>{if(null===d.current||void 0===c)return;d.current.style.top=d.current.style.bottom;const e=s.getRootElement(),t=d.current,o=t.firstChild;if(null!==e&&null!==n){const{left:r,top:s,width:u,height:a}=n.getRect(),m=d.current.offsetHeight;if(t.style.top=`${s+m+3+(i?window.pageYOffset:0)}px`,t.style.left=`${r+window.pageXOffset}px`,t.style.height=`${a}px`,t.style.width=`${u}px`,null!==o){o.style.top=`${s}`;const n=o.getBoundingClientRect(),l=n.height,c=n.width,u=e.getBoundingClientRect();r+c>u.right&&(t.style.left=`${u.right-c+window.pageXOffset}px`),(s+l>window.innerHeight||s+l>u.bottom)&&s-u.top>l+a&&(t.style.top=`${s-l-a+(i?window.pageYOffset:0)}px`)}t.isConnected||(D(t,l),c.append(t)),t.setAttribute("id","typeahead-menu"),e.setAttribute("aria-controls","typeahead-menu")}},[s,n,i,l,c]);y(()=>{const e=s.getRootElement();return null!==n&&p(),()=>{null!==e&&e.removeAttribute("aria-controls");const t=d.current;null!==t&&t.isConnected&&(t.remove(),t.removeAttribute("id"))}},[s,p,n]);const f=C(e=>{null!==n&&(e||o(null))},[n,o]);return function(t,n,o,l){const[r]=e();y(()=>{if(null!=n&&null!=t){const e=r.getRootElement(),t=null!=e?x(e,!1):document.body;let i=!1,s=S(n,t);const c=function(){i||(window.requestAnimationFrame(function(){o(),i=!1}),i=!0);const e=S(n,t);e!==s&&(s=e,null!=l&&l(e))},u=new ResizeObserver(o);window.addEventListener("resize",o),document.addEventListener("scroll",c,{capture:!0,passive:!0});const m=a(e??n);for(const e of m)e.addEventListener("scroll",c,{capture:!0,passive:!0});return u.observe(n),()=>{u.unobserve(n),window.removeEventListener("resize",o),document.removeEventListener("scroll",c,!0);for(const e of m)e.removeEventListener("scroll",c,!0)}}},[n,r,l,o,t])}(n,d.current,p,f),null!=m&&m===d.current&&(D(m,l),null!=c&&c.append(m)),d}const B="startTransition";function $({options:t,nodeKey:n,onClose:l,onOpen:r,onSelectOption:i,menuRenderFn:s,anchorClassName:c,commandPriority:u=o,parent:a}){const[m]=e(),[d,p]=b(null),h=T(d,p,c,a),v=C(()=>{p(null),null!=l&&null!==d&&l()},[l,d]),E=C(e=>{p(e),null!=r&&null===d&&r(e)},[r,d]),x=C(()=>{n?m.update(()=>{const e=f(n),t=m.getElementByKey(n);var o;null!=e&&null!=t&&null==d&&(o=()=>E({getRect:()=>t.getBoundingClientRect()}),B in g?g[B](o):o())}):null==n&&null!=d&&v()},[v,m,n,E,d]);return y(()=>{x()},[x,n]),y(()=>{if(null!=n)return m.registerUpdateListener(({dirtyElements:e})=>{e.get(n)&&x()})},[m,x,n]),null===h.current||null===d||null===m?null:/*#__PURE__*/w(L,{close:v,resolution:d,editor:m,anchorElementRef:h,options:t,menuRenderFn:s,onSelectOption:i,commandPriority:u})}export{$ as LexicalNodeMenuPlugin,A as MenuOption};
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { MenuRenderFn, MenuResolution, MenuTextMatch, TriggerFn } from './shared/LexicalMenu';
|
|
9
9
|
import type { JSX } from 'react';
|
|
10
|
+
import { getScrollParent as getScrollParent_ } from '@lexical/utils';
|
|
10
11
|
import { CommandListenerPriority, LexicalCommand, TextNode } from 'lexical';
|
|
11
12
|
import { MenuOption } from './shared/LexicalMenu';
|
|
12
13
|
/**
|
|
@@ -15,8 +16,9 @@ import { MenuOption } from './shared/LexicalMenu';
|
|
|
15
16
|
* {@link useBasicTypeaheadTriggerMatch}.
|
|
16
17
|
*/
|
|
17
18
|
export declare const PUNCTUATION = "\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;";
|
|
18
|
-
export { getScrollParent } from './shared/getScrollParent';
|
|
19
19
|
export { useDynamicPositioning } from './shared/LexicalMenu';
|
|
20
|
+
/** @deprecated Moved to `@lexical/utils`. Import `getScrollParent` from there. */
|
|
21
|
+
export declare const getScrollParent: typeof getScrollParent_;
|
|
20
22
|
/**
|
|
21
23
|
* Command dispatched while the typeahead menu is open to scroll the option at
|
|
22
24
|
* the given `index` into view. The default menu renderer listens for it; custom
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
11
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
12
|
+
var utils = require('@lexical/utils');
|
|
12
13
|
var lexical = require('lexical');
|
|
13
14
|
var React = require('react');
|
|
14
15
|
var ReactDOM = require('react-dom');
|
|
@@ -23,50 +24,6 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
23
24
|
*/
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
// Got from https://stackoverflow.com/a/42543908/2013580
|
|
27
|
-
/**
|
|
28
|
-
* Walks up from `element` and returns the nearest scrollable ancestor (or
|
|
29
|
-
* `ownerDocument.body` if none is found), used to keep the active typeahead
|
|
30
|
-
* option scrolled into view. Set `includeHidden` to also treat
|
|
31
|
-
* `overflow: hidden` ancestors as scroll parents.
|
|
32
|
-
*
|
|
33
|
-
* The walk crosses ShadowRoot→host (via `getParentElement`) so a
|
|
34
|
-
* shadow-mounted editor's scroll parent is found in the enclosing light-DOM
|
|
35
|
-
* ancestor chain, and the styles / body are resolved through the element's
|
|
36
|
-
* own realm so an iframe-mounted editor stays inside its document.
|
|
37
|
-
*/
|
|
38
|
-
function getScrollParent(element, includeHidden) {
|
|
39
|
-
// Resolve through the element's own realm so an iframe-mounted editor's
|
|
40
|
-
// scroll parent and computed styles come from its document, not the top one.
|
|
41
|
-
const ownerDocument = element.ownerDocument;
|
|
42
|
-
const win = ownerDocument.defaultView || window;
|
|
43
|
-
let style = win.getComputedStyle(element);
|
|
44
|
-
const excludeStaticParent = style.position === 'absolute';
|
|
45
|
-
const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
|
|
46
|
-
if (style.position === 'fixed') {
|
|
47
|
-
return ownerDocument.body;
|
|
48
|
-
}
|
|
49
|
-
for (let parent = element; parent = lexical.getParentElement(parent);) {
|
|
50
|
-
style = win.getComputedStyle(parent);
|
|
51
|
-
if (excludeStaticParent && style.position === 'static') {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
|
|
55
|
-
return parent;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return ownerDocument.body;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
63
|
-
*
|
|
64
|
-
* This source code is licensed under the MIT license found in the
|
|
65
|
-
* LICENSE file in the root directory of this source tree.
|
|
66
|
-
*
|
|
67
|
-
*/
|
|
68
|
-
|
|
69
|
-
|
|
70
27
|
// This workaround is no longer necessary in React 19,
|
|
71
28
|
// but we currently support React >=17.x
|
|
72
29
|
// https://github.com/facebook/react/pull/26395
|
|
@@ -200,7 +157,7 @@ function useDynamicPositioning(resolution, targetElement, onReposition, onVisibi
|
|
|
200
157
|
React.useEffect(() => {
|
|
201
158
|
if (targetElement != null && resolution != null) {
|
|
202
159
|
const rootElement = editor.getRootElement();
|
|
203
|
-
const rootScrollParent = rootElement != null ? getScrollParent(rootElement, false) : document.body;
|
|
160
|
+
const rootScrollParent = rootElement != null ? utils.getScrollParent(rootElement, false) : document.body;
|
|
204
161
|
let ticking = false;
|
|
205
162
|
let previousIsInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);
|
|
206
163
|
const handleScroll = function () {
|
|
@@ -641,6 +598,8 @@ function isSelectionOnEntityBoundary(editor, offset) {
|
|
|
641
598
|
return false;
|
|
642
599
|
});
|
|
643
600
|
}
|
|
601
|
+
/** @deprecated Moved to `@lexical/utils`. Import `getScrollParent` from there. */
|
|
602
|
+
const getScrollParent = utils.getScrollParent;
|
|
644
603
|
|
|
645
604
|
/**
|
|
646
605
|
* Command dispatched while the typeahead menu is open to scroll the option at
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
10
|
-
import {
|
|
10
|
+
import { getScrollParent as getScrollParent$1 } from '@lexical/utils';
|
|
11
|
+
import { CAN_USE_DOM, getDOMShadowRoots, mergeRegister, COMMAND_PRIORITY_LOW, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, isDOMShadowRoot, $getSelection, $isRangeSelection, createCommand, $isTextNode, getDOMSelection, getDOMSelectionPoints } from 'lexical';
|
|
11
12
|
import React, { useLayoutEffect, useEffect, useRef, useCallback, useState, useMemo } from 'react';
|
|
12
13
|
import ReactDOM from 'react-dom';
|
|
13
14
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
@@ -21,50 +22,6 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
21
22
|
*/
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
// Got from https://stackoverflow.com/a/42543908/2013580
|
|
25
|
-
/**
|
|
26
|
-
* Walks up from `element` and returns the nearest scrollable ancestor (or
|
|
27
|
-
* `ownerDocument.body` if none is found), used to keep the active typeahead
|
|
28
|
-
* option scrolled into view. Set `includeHidden` to also treat
|
|
29
|
-
* `overflow: hidden` ancestors as scroll parents.
|
|
30
|
-
*
|
|
31
|
-
* The walk crosses ShadowRoot→host (via `getParentElement`) so a
|
|
32
|
-
* shadow-mounted editor's scroll parent is found in the enclosing light-DOM
|
|
33
|
-
* ancestor chain, and the styles / body are resolved through the element's
|
|
34
|
-
* own realm so an iframe-mounted editor stays inside its document.
|
|
35
|
-
*/
|
|
36
|
-
function getScrollParent(element, includeHidden) {
|
|
37
|
-
// Resolve through the element's own realm so an iframe-mounted editor's
|
|
38
|
-
// scroll parent and computed styles come from its document, not the top one.
|
|
39
|
-
const ownerDocument = element.ownerDocument;
|
|
40
|
-
const win = ownerDocument.defaultView || window;
|
|
41
|
-
let style = win.getComputedStyle(element);
|
|
42
|
-
const excludeStaticParent = style.position === 'absolute';
|
|
43
|
-
const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
|
|
44
|
-
if (style.position === 'fixed') {
|
|
45
|
-
return ownerDocument.body;
|
|
46
|
-
}
|
|
47
|
-
for (let parent = element; parent = getParentElement(parent);) {
|
|
48
|
-
style = win.getComputedStyle(parent);
|
|
49
|
-
if (excludeStaticParent && style.position === 'static') {
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
|
|
53
|
-
return parent;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return ownerDocument.body;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
61
|
-
*
|
|
62
|
-
* This source code is licensed under the MIT license found in the
|
|
63
|
-
* LICENSE file in the root directory of this source tree.
|
|
64
|
-
*
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
|
|
68
25
|
// This workaround is no longer necessary in React 19,
|
|
69
26
|
// but we currently support React >=17.x
|
|
70
27
|
// https://github.com/facebook/react/pull/26395
|
|
@@ -198,7 +155,7 @@ function useDynamicPositioning(resolution, targetElement, onReposition, onVisibi
|
|
|
198
155
|
useEffect(() => {
|
|
199
156
|
if (targetElement != null && resolution != null) {
|
|
200
157
|
const rootElement = editor.getRootElement();
|
|
201
|
-
const rootScrollParent = rootElement != null ? getScrollParent(rootElement, false) : document.body;
|
|
158
|
+
const rootScrollParent = rootElement != null ? getScrollParent$1(rootElement, false) : document.body;
|
|
202
159
|
let ticking = false;
|
|
203
160
|
let previousIsInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);
|
|
204
161
|
const handleScroll = function () {
|
|
@@ -639,6 +596,8 @@ function isSelectionOnEntityBoundary(editor, offset) {
|
|
|
639
596
|
return false;
|
|
640
597
|
});
|
|
641
598
|
}
|
|
599
|
+
/** @deprecated Moved to `@lexical/utils`. Import `getScrollParent` from there. */
|
|
600
|
+
const getScrollParent = getScrollParent$1;
|
|
642
601
|
|
|
643
602
|
/**
|
|
644
603
|
* Command dispatched while the typeahead menu is open to scroll the option at
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("lexical"),n=require("
|
|
9
|
+
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("@lexical/utils"),n=require("lexical"),o=require("react"),l=require("react-dom"),r=require("react/jsx-runtime");const i=n.CAN_USE_DOM?o.useLayoutEffect:o.useEffect;const s=e=>{const t=e.closest("#typeahead-menu");if(!t)return;const n=t.getBoundingClientRect();n.top+n.height>window.innerHeight&&t.scrollIntoView({block:"center"}),n.top<0&&t.scrollIntoView({block:"center"}),e.scrollIntoView({block:"nearest"})};function c(e,t){const n=e.getBoundingClientRect(),o=t.getBoundingClientRect();return n.top>=o.top-6&&n.top<=o.bottom+6}function u(l,r,i,s){const[u]=e.useLexicalComposerContext();o.useEffect(()=>{if(null!=r&&null!=l){const e=u.getRootElement(),o=null!=e?t.getScrollParent(e,!1):document.body;let l=!1,a=c(r,o);const d=function(){l||(window.requestAnimationFrame(function(){i(),l=!1}),l=!0);const e=c(r,o);e!==a&&(a=e,null!=s&&s(e))},f=new ResizeObserver(i);window.addEventListener("resize",i),document.addEventListener("scroll",d,{capture:!0,passive:!0});const m=e??r,g=n.getDOMShadowRoots(m);for(const e of g)e.addEventListener("scroll",d,{capture:!0,passive:!0});return f.observe(r),()=>{f.unobserve(r),window.removeEventListener("resize",i),document.removeEventListener("scroll",d,!0);for(const e of g)e.removeEventListener("scroll",d,!0)}}},[r,u,s,i,l])}const a=/* @__PURE__ */n.createCommand("SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND");function d({index:e,isSelected:t,onClick:n,onMouseEnter:o,option:l}){let i="item";return t&&(i+=" selected"),/*#__PURE__*/r.jsxs("li",{tabIndex:-1,className:i,ref:l.setRefElement,role:"option","aria-selected":t,id:"typeahead-item-"+e,onMouseEnter:o,onClick:n,children:[l.icon,/*#__PURE__*/r.jsx("span",{className:"text",children:l.title})]},l.key)}function f({close:e,editor:t,anchorElementRef:c,resolution:u,options:f,menuRenderFn:m,onSelectOption:g,shouldSplitNodeWithQuery:p=!1,commandPriority:h=n.COMMAND_PRIORITY_LOW,preselectFirstItem:C=!0}){const[E,x]=o.useState(null),O=null!==E?Math.min(f.length-1,E):null,R=u.match&&u.match.matchingString;o.useEffect(()=>{C&&x(0)},[R,C]);const y=o.useCallback(o=>{t.update(()=>{const t=null!=u.match&&p?function(e){const t=n.$getSelection();if(!n.$isRangeSelection(t)||!t.isCollapsed())return null;const o=t.anchor;if("text"!==o.type)return null;const l=o.getNode();if(!l.isSimpleText())return null;const r=o.offset,i=l.getTextContent().slice(0,r),s=e.replaceableString.length,c=r-function(e,t,n){let o=n;for(let n=o;n<=t.length;n++)e.slice(-n)===t.substring(0,n)&&(o=n);return o}(i,e.matchingString,s);if(c<0)return null;let u;return 0===c?[u]=l.splitText(r):[,u]=l.splitText(c,r),u}(u.match):null;g(o,t,e,u.match?u.match.matchingString:"")})},[t,p,u.match,g,e]),S=o.useCallback(e=>{const n=t.getRootElement();null!==n&&(n.setAttribute("aria-activedescendant","typeahead-item-"+e),x(e))},[t]),b=o.useCallback(()=>c.current&&f.length?/*#__PURE__*/l.createPortal(/*#__PURE__*/r.jsx("div",{className:"typeahead-popover mentions-menu",children:/*#__PURE__*/r.jsx("ul",{children:f.map((e,t)=>/*#__PURE__*/r.jsx(d,{index:t,isSelected:O===t,onClick:()=>{x(t),y(e)},onMouseEnter:()=>{x(t)},option:e},e.key))})}),c.current):null,[c,f,O,y,x]);o.useEffect(()=>()=>{const e=t.getRootElement();null!==e&&e.removeAttribute("aria-activedescendant")},[t]),i(()=>{null===f?x(null):null===O&&C&&S(0)},[f,O,S,C]),o.useEffect(()=>n.mergeRegister(t.registerCommand(a,({option:e})=>!(!e.ref||null==e.ref.current)&&(s(e.ref.current),!0),h)),[t,S,h]),o.useEffect(()=>n.mergeRegister(t.registerCommand(n.KEY_ARROW_DOWN_COMMAND,e=>{const n=e;if(null!==f&&f.length){const e=null===O?0:O!==f.length-1?O+1:0;S(e);const o=f[e];if(!o)return S(-1),n.preventDefault(),n.stopImmediatePropagation(),!0;o.ref&&o.ref.current&&t.dispatchCommand(a,{index:e,option:o}),n.preventDefault(),n.stopImmediatePropagation()}return!0},h),t.registerCommand(n.KEY_ARROW_UP_COMMAND,e=>{const t=e;if(null!==f&&f.length){const e=null===O?f.length-1:0!==O?O-1:f.length-1;S(e);const n=f[e];if(!n)return S(-1),t.preventDefault(),t.stopImmediatePropagation(),!0;n.ref&&n.ref.current&&s(n.ref.current),t.preventDefault(),t.stopImmediatePropagation()}return!0},h),t.registerCommand(n.KEY_ESCAPE_COMMAND,t=>{const n=t;return n.preventDefault(),n.stopImmediatePropagation(),e(),!0},h),t.registerCommand(n.KEY_TAB_COMMAND,e=>{const t=e;return null!==f&&null!==O&&null!=f[O]&&(t.preventDefault(),t.stopImmediatePropagation(),y(f[O]),!0)},h),t.registerCommand(n.KEY_ENTER_COMMAND,e=>!(null===f||null===O||null==f[O]||e&&e.shiftKey)&&(null!==e&&(e.preventDefault(),e.stopImmediatePropagation()),y(f[O]),!0),h)),[y,e,t,f,O,S,h]);const _=o.useMemo(()=>({options:f,selectOptionAndCleanUp:y,selectedIndex:O,setHighlightedIndex:x}),[y,O,f]);return null!=m?m(c,_,u.match?u.match.matchingString:""):b()}function m(e,t){null!=t&&(e.className=t),e.setAttribute("aria-label","Typeahead menu"),e.setAttribute("role","listbox"),e.style.display="block",e.style.position="absolute"}function g(t,l,r,i,s=!0){const[c]=e.useLexicalComposerContext(),a=i??function(e){if(!n.CAN_USE_DOM)return;const t=e.getRootElement();if(null!==t){const e=t.getRootNode();if(n.isDOMShadowRoot(e))return e}return document.body}(c),d=n.CAN_USE_DOM?document.createElement("div"):null,f=o.useRef(d),g=o.useCallback(()=>{if(null===f.current||void 0===a)return;f.current.style.top=f.current.style.bottom;const e=c.getRootElement(),n=f.current,o=n.firstChild;if(null!==e&&null!==t){const{left:l,top:i,width:c,height:u}=t.getRect(),d=f.current.offsetHeight;if(n.style.top=`${i+d+3+(s?window.pageYOffset:0)}px`,n.style.left=`${l+window.pageXOffset}px`,n.style.height=`${u}px`,n.style.width=`${c}px`,null!==o){o.style.top=`${i}`;const t=o.getBoundingClientRect(),r=t.height,c=t.width,a=e.getBoundingClientRect();l+c>a.right&&(n.style.left=`${a.right-c+window.pageXOffset}px`),(i+r>window.innerHeight||i+r>a.bottom)&&i-a.top>r+u&&(n.style.top=`${i-r-u+(s?window.pageYOffset:0)}px`)}n.isConnected||(m(n,r),a.append(n)),n.setAttribute("id","typeahead-menu"),e.setAttribute("aria-controls","typeahead-menu")}},[c,t,s,r,a]);o.useEffect(()=>{const e=c.getRootElement();return null!==t&&g(),()=>{null!==e&&e.removeAttribute("aria-controls");const t=f.current;null!==t&&t.isConnected&&(t.remove(),t.removeAttribute("id"))}},[c,g,t]);const p=o.useCallback(e=>{null!==t&&(e||l(null))},[t,l]);return u(t,f.current,g,p),null!=d&&d===f.current&&(m(d,r),null!=a&&a.append(d)),f}const p="startTransition";const h="\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;";const C=t.getScrollParent,E=/* @__PURE__ */n.createCommand("SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND");exports.LexicalTypeaheadMenuPlugin=function({options:t,onQueryChange:l,onSelectOption:i,onOpen:s,onClose:c,menuRenderFn:u,triggerFn:a,anchorClassName:d,commandPriority:m=n.COMMAND_PRIORITY_LOW,parent:h,preselectFirstItem:C=!0,ignoreEntityBoundary:E=!1}){const[x]=e.useLexicalComposerContext(),[O,R]=o.useState(null),y=g(O,R,d,h),S=o.useCallback(()=>{if(null===O)return;const e=()=>{R(null)};let t;try{t=c&&c()}finally{t?t.then(e,e):e()}},[c,O]),b=o.useCallback(e=>{R(e),null!=s&&null===O&&s(e)},[s,O]);return o.useEffect(()=>{const e=x.registerUpdateListener(()=>{x.read("latest",()=>{if(!x.isEditable())return void S();if(x.isComposing())return;const e=x._window||window,t=e.document.createRange(),r=n.$getSelection(),i=function(e){let t=null;return e.read("latest",()=>{const e=n.$getSelection();n.$isRangeSelection(e)&&(t=function(e){const t=e.anchor;if("text"!==t.type)return null;const n=t.getNode();if(!n.isSimpleText())return null;const o=t.offset;return n.getTextContent().slice(0,o)}(e))}),t}(x);if(!n.$isRangeSelection(r)||!r.isCollapsed()||null===i||null===t)return void S();const s=a(i,x);if(l(s?s.matchingString:null),null!==s&&(E||!function(e,t){return 0===t&&e.read("latest",()=>{const e=n.$getSelection();if(n.$isRangeSelection(e)){const t=e.anchor.getNode().getPreviousSibling();return n.$isTextNode(t)&&t.isTextEntity()}return!1})}(x,s.leadOffset))){const l=function(e,t,o,l){const r=n.getDOMSelection(o);if(null===r||!r.isCollapsed)return!1;const i=n.getDOMSelectionPoints(r,l),s=i.anchorNode,c=e,u=i.anchorOffset;if(null==s||null==u)return!1;try{t.setStart(s,c),t.setEnd(s,u)}catch(e){return!1}return!0}(s.leadOffset,t,e,x.getRootElement());if(null!==l)return c=()=>b({getRect:()=>t.getBoundingClientRect(),match:s}),void(p in o?o[p](c):c())}var c;S()})});return()=>{e()}},[x,a,l,O,S,b,E]),o.useEffect(()=>x.registerEditableListener(e=>{e||S()}),[x,S]),null===O||null===x||null===y.current?null:/*#__PURE__*/r.jsx(f,{close:S,resolution:O,editor:x,anchorElementRef:y,options:t,menuRenderFn:u,shouldSplitNodeWithQuery:!0,onSelectOption:i,commandPriority:m,preselectFirstItem:C})},exports.MenuOption=class{key;ref;icon;title;constructor(e){this.key=e,this.ref={current:null},this.setRefElement=this.setRefElement.bind(this)}setRefElement(e){this.ref={current:e}}},exports.PUNCTUATION=h,exports.SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND=E,exports.getScrollParent=C,exports.useBasicTypeaheadTriggerMatch=function(e,{minLength:t=1,maxLength:n=75,punctuation:l=h,allowWhitespace:r=!1}){return o.useCallback(o=>{const i=new RegExp("(^|\\s|\\()(["+e+"]((?:"+("[^"+e+l+(r?"":"\\s")+"]")+"){0,"+n+"}))$").exec(o);if(null!==i){const e=i[1],n=i[3];if(n.length>=t)return{leadOffset:i.index+e.length,matchingString:n,replaceableString:i[2]}}return null},[r,e,l,n,t])},exports.useDynamicPositioning=u;
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import{useLexicalComposerContext as t}from"@lexical/react/LexicalComposerContext";import{
|
|
9
|
+
import{useLexicalComposerContext as t}from"@lexical/react/LexicalComposerContext";import{getScrollParent as e}from"@lexical/utils";import{CAN_USE_DOM as n,getDOMShadowRoots as o,mergeRegister as r,COMMAND_PRIORITY_LOW as l,KEY_ARROW_DOWN_COMMAND as i,KEY_ARROW_UP_COMMAND as s,KEY_ESCAPE_COMMAND as c,KEY_TAB_COMMAND as u,KEY_ENTER_COMMAND as a,isDOMShadowRoot as d,$getSelection as m,$isRangeSelection as f,createCommand as p,$isTextNode as g,getDOMSelection as h,getDOMSelectionPoints as y}from"lexical";import v,{useLayoutEffect as C,useEffect as E,useRef as x,useCallback as b,useState as w,useMemo as R}from"react";import O from"react-dom";import{jsx as I,jsxs as S}from"react/jsx-runtime";const N=n?C:E;class P{key;ref;icon;title;constructor(t){this.key=t,this.ref={current:null},this.setRefElement=this.setRefElement.bind(this)}setRefElement(t){this.ref={current:t}}}const A=t=>{const e=t.closest("#typeahead-menu");if(!e)return;const n=e.getBoundingClientRect();n.top+n.height>window.innerHeight&&e.scrollIntoView({block:"center"}),n.top<0&&e.scrollIntoView({block:"center"}),t.scrollIntoView({block:"nearest"})};function L(t,e){const n=t.getBoundingClientRect(),o=e.getBoundingClientRect();return n.top>=o.top-6&&n.top<=o.bottom+6}function T(n,r,l,i){const[s]=t();E(()=>{if(null!=r&&null!=n){const t=s.getRootElement(),n=null!=t?e(t,!1):document.body;let c=!1,u=L(r,n);const a=function(){c||(window.requestAnimationFrame(function(){l(),c=!1}),c=!0);const t=L(r,n);t!==u&&(u=t,null!=i&&i(t))},d=new ResizeObserver(l);window.addEventListener("resize",l),document.addEventListener("scroll",a,{capture:!0,passive:!0});const m=o(t??r);for(const t of m)t.addEventListener("scroll",a,{capture:!0,passive:!0});return d.observe(r),()=>{d.unobserve(r),window.removeEventListener("resize",l),document.removeEventListener("scroll",a,!0);for(const t of m)t.removeEventListener("scroll",a,!0)}}},[r,s,i,l,n])}const _=/* @__PURE__ */p("SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND");function k({index:t,isSelected:e,onClick:n,onMouseEnter:o,option:r}){let l="item";return e&&(l+=" selected"),/*#__PURE__*/S("li",{tabIndex:-1,className:l,ref:r.setRefElement,role:"option","aria-selected":e,id:"typeahead-item-"+t,onMouseEnter:o,onClick:n,children:[r.icon,/*#__PURE__*/I("span",{className:"text",children:r.title})]},r.key)}function D({close:t,editor:e,anchorElementRef:n,resolution:o,options:d,menuRenderFn:p,onSelectOption:g,shouldSplitNodeWithQuery:h=!1,commandPriority:y=l,preselectFirstItem:v=!0}){const[C,x]=w(null),S=null!==C?Math.min(d.length-1,C):null,P=o.match&&o.match.matchingString;E(()=>{v&&x(0)},[P,v]);const L=b(n=>{e.update(()=>{const e=null!=o.match&&h?function(t){const e=m();if(!f(e)||!e.isCollapsed())return null;const n=e.anchor;if("text"!==n.type)return null;const o=n.getNode();if(!o.isSimpleText())return null;const r=n.offset,l=o.getTextContent().slice(0,r),i=t.replaceableString.length,s=r-function(t,e,n){let o=n;for(let n=o;n<=e.length;n++)t.slice(-n)===e.substring(0,n)&&(o=n);return o}(l,t.matchingString,i);if(s<0)return null;let c;return 0===s?[c]=o.splitText(r):[,c]=o.splitText(s,r),c}(o.match):null;g(n,e,t,o.match?o.match.matchingString:"")})},[e,h,o.match,g,t]),T=b(t=>{const n=e.getRootElement();null!==n&&(n.setAttribute("aria-activedescendant","typeahead-item-"+t),x(t))},[e]),D=b(()=>n.current&&d.length?/*#__PURE__*/O.createPortal(/*#__PURE__*/I("div",{className:"typeahead-popover mentions-menu",children:/*#__PURE__*/I("ul",{children:d.map((t,e)=>/*#__PURE__*/I(k,{index:e,isSelected:S===e,onClick:()=>{x(e),L(t)},onMouseEnter:()=>{x(e)},option:t},t.key))})}),n.current):null,[n,d,S,L,x]);E(()=>()=>{const t=e.getRootElement();null!==t&&t.removeAttribute("aria-activedescendant")},[e]),N(()=>{null===d?x(null):null===S&&v&&T(0)},[d,S,T,v]),E(()=>r(e.registerCommand(_,({option:t})=>!(!t.ref||null==t.ref.current)&&(A(t.ref.current),!0),y)),[e,T,y]),E(()=>r(e.registerCommand(i,t=>{const n=t;if(null!==d&&d.length){const t=null===S?0:S!==d.length-1?S+1:0;T(t);const o=d[t];if(!o)return T(-1),n.preventDefault(),n.stopImmediatePropagation(),!0;o.ref&&o.ref.current&&e.dispatchCommand(_,{index:t,option:o}),n.preventDefault(),n.stopImmediatePropagation()}return!0},y),e.registerCommand(s,t=>{const e=t;if(null!==d&&d.length){const t=null===S?d.length-1:0!==S?S-1:d.length-1;T(t);const n=d[t];if(!n)return T(-1),e.preventDefault(),e.stopImmediatePropagation(),!0;n.ref&&n.ref.current&&A(n.ref.current),e.preventDefault(),e.stopImmediatePropagation()}return!0},y),e.registerCommand(c,e=>{const n=e;return n.preventDefault(),n.stopImmediatePropagation(),t(),!0},y),e.registerCommand(u,t=>{const e=t;return null!==d&&null!==S&&null!=d[S]&&(e.preventDefault(),e.stopImmediatePropagation(),L(d[S]),!0)},y),e.registerCommand(a,t=>!(null===d||null===S||null==d[S]||t&&t.shiftKey)&&(null!==t&&(t.preventDefault(),t.stopImmediatePropagation()),L(d[S]),!0),y)),[L,t,e,d,S,T,y]);const $=R(()=>({options:d,selectOptionAndCleanUp:L,selectedIndex:S,setHighlightedIndex:x}),[L,S,d]);return null!=p?p(n,$,o.match?o.match.matchingString:""):D()}function $(t,e){null!=e&&(t.className=e),t.setAttribute("aria-label","Typeahead menu"),t.setAttribute("role","listbox"),t.style.display="block",t.style.position="absolute"}function F(e,o,r,l,i=!0){const[s]=t(),c=l??function(t){if(!n)return;const e=t.getRootElement();if(null!==e){const t=e.getRootNode();if(d(t))return t}return document.body}(s),u=n?document.createElement("div"):null,a=x(u),m=b(()=>{if(null===a.current||void 0===c)return;a.current.style.top=a.current.style.bottom;const t=s.getRootElement(),n=a.current,o=n.firstChild;if(null!==t&&null!==e){const{left:l,top:s,width:u,height:d}=e.getRect(),m=a.current.offsetHeight;if(n.style.top=`${s+m+3+(i?window.pageYOffset:0)}px`,n.style.left=`${l+window.pageXOffset}px`,n.style.height=`${d}px`,n.style.width=`${u}px`,null!==o){o.style.top=`${s}`;const e=o.getBoundingClientRect(),r=e.height,c=e.width,u=t.getBoundingClientRect();l+c>u.right&&(n.style.left=`${u.right-c+window.pageXOffset}px`),(s+r>window.innerHeight||s+r>u.bottom)&&s-u.top>r+d&&(n.style.top=`${s-r-d+(i?window.pageYOffset:0)}px`)}n.isConnected||($(n,r),c.append(n)),n.setAttribute("id","typeahead-menu"),t.setAttribute("aria-controls","typeahead-menu")}},[s,e,i,r,c]);E(()=>{const t=s.getRootElement();return null!==e&&m(),()=>{null!==t&&t.removeAttribute("aria-controls");const e=a.current;null!==e&&e.isConnected&&(e.remove(),e.removeAttribute("id"))}},[s,m,e]);const f=b(t=>{null!==e&&(t||o(null))},[e,o]);return T(e,a.current,m,f),null!=u&&u===a.current&&($(u,r),null!=c&&c.append(u)),a}const M="startTransition";const B="\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;";const H=e,V=/* @__PURE__ */p("SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND");function W(t,{minLength:e=1,maxLength:n=75,punctuation:o=B,allowWhitespace:r=!1}){return b(l=>{const i=new RegExp("(^|\\s|\\()(["+t+"]((?:"+("[^"+t+o+(r?"":"\\s")+"]")+"){0,"+n+"}))$").exec(l);if(null!==i){const t=i[1],n=i[3];if(n.length>=e)return{leadOffset:i.index+t.length,matchingString:n,replaceableString:i[2]}}return null},[r,t,o,n,e])}function Y({options:e,onQueryChange:n,onSelectOption:o,onOpen:r,onClose:i,menuRenderFn:s,triggerFn:c,anchorClassName:u,commandPriority:a=l,parent:d,preselectFirstItem:p=!0,ignoreEntityBoundary:C=!1}){const[x]=t(),[R,O]=w(null),S=F(R,O,u,d),N=b(()=>{if(null===R)return;const t=()=>{O(null)};let e;try{e=i&&i()}finally{e?e.then(t,t):t()}},[i,R]),P=b(t=>{O(t),null!=r&&null===R&&r(t)},[r,R]);return E(()=>{const t=x.registerUpdateListener(()=>{x.read("latest",()=>{if(!x.isEditable())return void N();if(x.isComposing())return;const t=x._window||window,e=t.document.createRange(),o=m(),r=function(t){let e=null;return t.read("latest",()=>{const t=m();f(t)&&(e=function(t){const e=t.anchor;if("text"!==e.type)return null;const n=e.getNode();if(!n.isSimpleText())return null;const o=e.offset;return n.getTextContent().slice(0,o)}(t))}),e}(x);if(!f(o)||!o.isCollapsed()||null===r||null===e)return void N();const l=c(r,x);if(n(l?l.matchingString:null),null!==l&&(C||!function(t,e){return 0===e&&t.read("latest",()=>{const t=m();if(f(t)){const e=t.anchor.getNode().getPreviousSibling();return g(e)&&e.isTextEntity()}return!1})}(x,l.leadOffset))){const n=function(t,e,n,o){const r=h(n);if(null===r||!r.isCollapsed)return!1;const l=y(r,o),i=l.anchorNode,s=t,c=l.anchorOffset;if(null==i||null==c)return!1;try{e.setStart(i,s),e.setEnd(i,c)}catch(t){return!1}return!0}(l.leadOffset,e,t,x.getRootElement());if(null!==n)return i=()=>P({getRect:()=>e.getBoundingClientRect(),match:l}),void(M in v?v[M](i):i())}var i;N()})});return()=>{t()}},[x,c,n,R,N,P,C]),E(()=>x.registerEditableListener(t=>{t||N()}),[x,N]),null===R||null===x||null===S.current?null:/*#__PURE__*/I(D,{close:N,resolution:R,editor:x,anchorElementRef:S,options:e,menuRenderFn:s,shouldSplitNodeWithQuery:!0,onSelectOption:o,commandPriority:a,preselectFirstItem:p})}export{Y as LexicalTypeaheadMenuPlugin,P as MenuOption,B as PUNCTUATION,V as SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND,H as getScrollParent,W as useBasicTypeaheadTriggerMatch,T as useDynamicPositioning};
|
package/package.json
CHANGED
|
@@ -8,27 +8,27 @@
|
|
|
8
8
|
"rich-text"
|
|
9
9
|
],
|
|
10
10
|
"license": "MIT",
|
|
11
|
-
"version": "0.45.1-nightly.
|
|
11
|
+
"version": "0.45.1-nightly.20260623.0",
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@floating-ui/react": "^0.27.19",
|
|
14
|
-
"@lexical/
|
|
15
|
-
"@lexical/
|
|
16
|
-
"@lexical/
|
|
17
|
-
"@lexical/history": "0.45.1-nightly.
|
|
18
|
-
"@lexical/
|
|
19
|
-
"@lexical/internal": "0.45.1-nightly.
|
|
20
|
-
"@lexical/
|
|
21
|
-
"@lexical/
|
|
22
|
-
"@lexical/mark": "0.45.1-nightly.
|
|
23
|
-
"@lexical/markdown": "0.45.1-nightly.
|
|
24
|
-
"@lexical/
|
|
25
|
-
"@lexical/
|
|
26
|
-
"@lexical/
|
|
27
|
-
"@lexical/
|
|
28
|
-
"@lexical/utils": "0.45.1-nightly.
|
|
29
|
-
"@lexical/
|
|
30
|
-
"lexical": "0.45.1-nightly.
|
|
31
|
-
"
|
|
14
|
+
"@lexical/extension": "0.45.1-nightly.20260623.0",
|
|
15
|
+
"@lexical/devtools-core": "0.45.1-nightly.20260623.0",
|
|
16
|
+
"@lexical/dragon": "0.45.1-nightly.20260623.0",
|
|
17
|
+
"@lexical/history": "0.45.1-nightly.20260623.0",
|
|
18
|
+
"@lexical/hashtag": "0.45.1-nightly.20260623.0",
|
|
19
|
+
"@lexical/internal": "0.45.1-nightly.20260623.0",
|
|
20
|
+
"@lexical/list": "0.45.1-nightly.20260623.0",
|
|
21
|
+
"@lexical/link": "0.45.1-nightly.20260623.0",
|
|
22
|
+
"@lexical/mark": "0.45.1-nightly.20260623.0",
|
|
23
|
+
"@lexical/markdown": "0.45.1-nightly.20260623.0",
|
|
24
|
+
"@lexical/overflow": "0.45.1-nightly.20260623.0",
|
|
25
|
+
"@lexical/plain-text": "0.45.1-nightly.20260623.0",
|
|
26
|
+
"@lexical/table": "0.45.1-nightly.20260623.0",
|
|
27
|
+
"@lexical/text": "0.45.1-nightly.20260623.0",
|
|
28
|
+
"@lexical/utils": "0.45.1-nightly.20260623.0",
|
|
29
|
+
"@lexical/yjs": "0.45.1-nightly.20260623.0",
|
|
30
|
+
"@lexical/rich-text": "0.45.1-nightly.20260623.0",
|
|
31
|
+
"lexical": "0.45.1-nightly.20260623.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": ">=17.x",
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
import type {JSX} from 'react';
|
|
16
16
|
|
|
17
17
|
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
|
18
|
+
import {getScrollParent as getScrollParent_} from '@lexical/utils';
|
|
18
19
|
import {
|
|
19
20
|
$getSelection,
|
|
20
21
|
$isRangeSelection,
|
|
@@ -115,8 +116,9 @@ function isSelectionOnEntityBoundary(
|
|
|
115
116
|
});
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
export {getScrollParent} from './shared/getScrollParent';
|
|
119
119
|
export {useDynamicPositioning} from './shared/LexicalMenu';
|
|
120
|
+
/** @deprecated Moved to `@lexical/utils`. Import `getScrollParent` from there. */
|
|
121
|
+
export const getScrollParent = getScrollParent_;
|
|
120
122
|
|
|
121
123
|
/**
|
|
122
124
|
* Command dispatched while the typeahead menu is open to scroll the option at
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import type {JSX} from 'react';
|
|
10
10
|
|
|
11
11
|
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
|
12
|
+
import {getScrollParent} from '@lexical/utils';
|
|
12
13
|
import {
|
|
13
14
|
$getSelection,
|
|
14
15
|
$isRangeSelection,
|
|
@@ -39,7 +40,6 @@ import {
|
|
|
39
40
|
} from 'react';
|
|
40
41
|
import ReactDOM from 'react-dom';
|
|
41
42
|
|
|
42
|
-
import {getScrollParent} from './getScrollParent';
|
|
43
43
|
import useLayoutEffect from './useLayoutEffect';
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Walks up from `element` and returns the nearest scrollable ancestor (or
|
|
10
|
-
* `ownerDocument.body` if none is found), used to keep the active typeahead
|
|
11
|
-
* option scrolled into view. Set `includeHidden` to also treat
|
|
12
|
-
* `overflow: hidden` ancestors as scroll parents.
|
|
13
|
-
*
|
|
14
|
-
* The walk crosses ShadowRoot→host (via `getParentElement`) so a
|
|
15
|
-
* shadow-mounted editor's scroll parent is found in the enclosing light-DOM
|
|
16
|
-
* ancestor chain, and the styles / body are resolved through the element's
|
|
17
|
-
* own realm so an iframe-mounted editor stays inside its document.
|
|
18
|
-
*/
|
|
19
|
-
export declare function getScrollParent(element: HTMLElement, includeHidden: boolean): HTMLElement | HTMLBodyElement;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import {getParentElement} from 'lexical';
|
|
10
|
-
|
|
11
|
-
// Got from https://stackoverflow.com/a/42543908/2013580
|
|
12
|
-
/**
|
|
13
|
-
* Walks up from `element` and returns the nearest scrollable ancestor (or
|
|
14
|
-
* `ownerDocument.body` if none is found), used to keep the active typeahead
|
|
15
|
-
* option scrolled into view. Set `includeHidden` to also treat
|
|
16
|
-
* `overflow: hidden` ancestors as scroll parents.
|
|
17
|
-
*
|
|
18
|
-
* The walk crosses ShadowRoot→host (via `getParentElement`) so a
|
|
19
|
-
* shadow-mounted editor's scroll parent is found in the enclosing light-DOM
|
|
20
|
-
* ancestor chain, and the styles / body are resolved through the element's
|
|
21
|
-
* own realm so an iframe-mounted editor stays inside its document.
|
|
22
|
-
*/
|
|
23
|
-
export function getScrollParent(
|
|
24
|
-
element: HTMLElement,
|
|
25
|
-
includeHidden: boolean,
|
|
26
|
-
): HTMLElement | HTMLBodyElement {
|
|
27
|
-
// Resolve through the element's own realm so an iframe-mounted editor's
|
|
28
|
-
// scroll parent and computed styles come from its document, not the top one.
|
|
29
|
-
const ownerDocument = element.ownerDocument;
|
|
30
|
-
const win = ownerDocument.defaultView || window;
|
|
31
|
-
let style = win.getComputedStyle(element);
|
|
32
|
-
const excludeStaticParent = style.position === 'absolute';
|
|
33
|
-
const overflowRegex = includeHidden
|
|
34
|
-
? /(auto|scroll|hidden)/
|
|
35
|
-
: /(auto|scroll)/;
|
|
36
|
-
if (style.position === 'fixed') {
|
|
37
|
-
return ownerDocument.body;
|
|
38
|
-
}
|
|
39
|
-
for (
|
|
40
|
-
let parent: HTMLElement | null = element;
|
|
41
|
-
(parent = getParentElement(parent));
|
|
42
|
-
) {
|
|
43
|
-
style = win.getComputedStyle(parent);
|
|
44
|
-
if (excludeStaticParent && style.position === 'static') {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (
|
|
48
|
-
overflowRegex.test(style.overflow + style.overflowY + style.overflowX)
|
|
49
|
-
) {
|
|
50
|
-
return parent;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return ownerDocument.body;
|
|
54
|
-
}
|