You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
752 lines
23 KiB
752 lines
23 KiB
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tiptap/core'), require('prosemirror-state'), require('tippy.js')) :
|
|
typeof define === 'function' && define.amd ? define(['exports', '@tiptap/core', 'prosemirror-state', 'tippy.js'], factory) :
|
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@tiptap/extension-bubble-menu"] = {}, global.core, global.prosemirrorState, global.tippy));
|
|
})(this, (function (exports, core, prosemirrorState, tippy) { 'use strict';
|
|
|
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
|
|
var tippy__default = /*#__PURE__*/_interopDefaultLegacy(tippy);
|
|
|
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
|
|
/**
|
|
* Checks if `value` is the
|
|
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
|
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 0.1.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
|
* @example
|
|
*
|
|
* _.isObject({});
|
|
* // => true
|
|
*
|
|
* _.isObject([1, 2, 3]);
|
|
* // => true
|
|
*
|
|
* _.isObject(_.noop);
|
|
* // => true
|
|
*
|
|
* _.isObject(null);
|
|
* // => false
|
|
*/
|
|
|
|
function isObject$2(value) {
|
|
var type = typeof value;
|
|
return value != null && (type == 'object' || type == 'function');
|
|
}
|
|
|
|
var isObject_1 = isObject$2;
|
|
|
|
/** Detect free variable `global` from Node.js. */
|
|
|
|
var freeGlobal$1 = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
|
|
|
|
var _freeGlobal = freeGlobal$1;
|
|
|
|
var freeGlobal = _freeGlobal;
|
|
|
|
/** Detect free variable `self`. */
|
|
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
|
|
|
|
/** Used as a reference to the global object. */
|
|
var root$2 = freeGlobal || freeSelf || Function('return this')();
|
|
|
|
var _root = root$2;
|
|
|
|
var root$1 = _root;
|
|
|
|
/**
|
|
* Gets the timestamp of the number of milliseconds that have elapsed since
|
|
* the Unix epoch (1 January 1970 00:00:00 UTC).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 2.4.0
|
|
* @category Date
|
|
* @returns {number} Returns the timestamp.
|
|
* @example
|
|
*
|
|
* _.defer(function(stamp) {
|
|
* console.log(_.now() - stamp);
|
|
* }, _.now());
|
|
* // => Logs the number of milliseconds it took for the deferred invocation.
|
|
*/
|
|
var now$1 = function() {
|
|
return root$1.Date.now();
|
|
};
|
|
|
|
var now_1 = now$1;
|
|
|
|
/** Used to match a single whitespace character. */
|
|
|
|
var reWhitespace = /\s/;
|
|
|
|
/**
|
|
* Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
|
|
* character of `string`.
|
|
*
|
|
* @private
|
|
* @param {string} string The string to inspect.
|
|
* @returns {number} Returns the index of the last non-whitespace character.
|
|
*/
|
|
function trimmedEndIndex$1(string) {
|
|
var index = string.length;
|
|
|
|
while (index-- && reWhitespace.test(string.charAt(index))) {}
|
|
return index;
|
|
}
|
|
|
|
var _trimmedEndIndex = trimmedEndIndex$1;
|
|
|
|
var trimmedEndIndex = _trimmedEndIndex;
|
|
|
|
/** Used to match leading whitespace. */
|
|
var reTrimStart = /^\s+/;
|
|
|
|
/**
|
|
* The base implementation of `_.trim`.
|
|
*
|
|
* @private
|
|
* @param {string} string The string to trim.
|
|
* @returns {string} Returns the trimmed string.
|
|
*/
|
|
function baseTrim$1(string) {
|
|
return string
|
|
? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
|
|
: string;
|
|
}
|
|
|
|
var _baseTrim = baseTrim$1;
|
|
|
|
var root = _root;
|
|
|
|
/** Built-in value references. */
|
|
var Symbol$2 = root.Symbol;
|
|
|
|
var _Symbol = Symbol$2;
|
|
|
|
var Symbol$1 = _Symbol;
|
|
|
|
/** Used for built-in method references. */
|
|
var objectProto$1 = Object.prototype;
|
|
|
|
/** Used to check objects for own properties. */
|
|
var hasOwnProperty = objectProto$1.hasOwnProperty;
|
|
|
|
/**
|
|
* Used to resolve the
|
|
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
|
* of values.
|
|
*/
|
|
var nativeObjectToString$1 = objectProto$1.toString;
|
|
|
|
/** Built-in value references. */
|
|
var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined;
|
|
|
|
/**
|
|
* A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to query.
|
|
* @returns {string} Returns the raw `toStringTag`.
|
|
*/
|
|
function getRawTag$1(value) {
|
|
var isOwn = hasOwnProperty.call(value, symToStringTag$1),
|
|
tag = value[symToStringTag$1];
|
|
|
|
try {
|
|
value[symToStringTag$1] = undefined;
|
|
var unmasked = true;
|
|
} catch (e) {}
|
|
|
|
var result = nativeObjectToString$1.call(value);
|
|
if (unmasked) {
|
|
if (isOwn) {
|
|
value[symToStringTag$1] = tag;
|
|
} else {
|
|
delete value[symToStringTag$1];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
var _getRawTag = getRawTag$1;
|
|
|
|
/** Used for built-in method references. */
|
|
|
|
var objectProto = Object.prototype;
|
|
|
|
/**
|
|
* Used to resolve the
|
|
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
|
* of values.
|
|
*/
|
|
var nativeObjectToString = objectProto.toString;
|
|
|
|
/**
|
|
* Converts `value` to a string using `Object.prototype.toString`.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to convert.
|
|
* @returns {string} Returns the converted string.
|
|
*/
|
|
function objectToString$1(value) {
|
|
return nativeObjectToString.call(value);
|
|
}
|
|
|
|
var _objectToString = objectToString$1;
|
|
|
|
var Symbol = _Symbol,
|
|
getRawTag = _getRawTag,
|
|
objectToString = _objectToString;
|
|
|
|
/** `Object#toString` result references. */
|
|
var nullTag = '[object Null]',
|
|
undefinedTag = '[object Undefined]';
|
|
|
|
/** Built-in value references. */
|
|
var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
|
|
|
|
/**
|
|
* The base implementation of `getTag` without fallbacks for buggy environments.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to query.
|
|
* @returns {string} Returns the `toStringTag`.
|
|
*/
|
|
function baseGetTag$1(value) {
|
|
if (value == null) {
|
|
return value === undefined ? undefinedTag : nullTag;
|
|
}
|
|
return (symToStringTag && symToStringTag in Object(value))
|
|
? getRawTag(value)
|
|
: objectToString(value);
|
|
}
|
|
|
|
var _baseGetTag = baseGetTag$1;
|
|
|
|
/**
|
|
* Checks if `value` is object-like. A value is object-like if it's not `null`
|
|
* and has a `typeof` result of "object".
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
|
|
* @example
|
|
*
|
|
* _.isObjectLike({});
|
|
* // => true
|
|
*
|
|
* _.isObjectLike([1, 2, 3]);
|
|
* // => true
|
|
*
|
|
* _.isObjectLike(_.noop);
|
|
* // => false
|
|
*
|
|
* _.isObjectLike(null);
|
|
* // => false
|
|
*/
|
|
|
|
function isObjectLike$1(value) {
|
|
return value != null && typeof value == 'object';
|
|
}
|
|
|
|
var isObjectLike_1 = isObjectLike$1;
|
|
|
|
var baseGetTag = _baseGetTag,
|
|
isObjectLike = isObjectLike_1;
|
|
|
|
/** `Object#toString` result references. */
|
|
var symbolTag = '[object Symbol]';
|
|
|
|
/**
|
|
* Checks if `value` is classified as a `Symbol` primitive or object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
|
|
* @example
|
|
*
|
|
* _.isSymbol(Symbol.iterator);
|
|
* // => true
|
|
*
|
|
* _.isSymbol('abc');
|
|
* // => false
|
|
*/
|
|
function isSymbol$1(value) {
|
|
return typeof value == 'symbol' ||
|
|
(isObjectLike(value) && baseGetTag(value) == symbolTag);
|
|
}
|
|
|
|
var isSymbol_1 = isSymbol$1;
|
|
|
|
var baseTrim = _baseTrim,
|
|
isObject$1 = isObject_1,
|
|
isSymbol = isSymbol_1;
|
|
|
|
/** Used as references for various `Number` constants. */
|
|
var NAN = 0 / 0;
|
|
|
|
/** Used to detect bad signed hexadecimal string values. */
|
|
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
|
|
|
|
/** Used to detect binary string values. */
|
|
var reIsBinary = /^0b[01]+$/i;
|
|
|
|
/** Used to detect octal string values. */
|
|
var reIsOctal = /^0o[0-7]+$/i;
|
|
|
|
/** Built-in method references without a dependency on `root`. */
|
|
var freeParseInt = parseInt;
|
|
|
|
/**
|
|
* Converts `value` to a number.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to process.
|
|
* @returns {number} Returns the number.
|
|
* @example
|
|
*
|
|
* _.toNumber(3.2);
|
|
* // => 3.2
|
|
*
|
|
* _.toNumber(Number.MIN_VALUE);
|
|
* // => 5e-324
|
|
*
|
|
* _.toNumber(Infinity);
|
|
* // => Infinity
|
|
*
|
|
* _.toNumber('3.2');
|
|
* // => 3.2
|
|
*/
|
|
function toNumber$1(value) {
|
|
if (typeof value == 'number') {
|
|
return value;
|
|
}
|
|
if (isSymbol(value)) {
|
|
return NAN;
|
|
}
|
|
if (isObject$1(value)) {
|
|
var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
|
|
value = isObject$1(other) ? (other + '') : other;
|
|
}
|
|
if (typeof value != 'string') {
|
|
return value === 0 ? value : +value;
|
|
}
|
|
value = baseTrim(value);
|
|
var isBinary = reIsBinary.test(value);
|
|
return (isBinary || reIsOctal.test(value))
|
|
? freeParseInt(value.slice(2), isBinary ? 2 : 8)
|
|
: (reIsBadHex.test(value) ? NAN : +value);
|
|
}
|
|
|
|
var toNumber_1 = toNumber$1;
|
|
|
|
var isObject = isObject_1,
|
|
now = now_1,
|
|
toNumber = toNumber_1;
|
|
|
|
/** Error message constants. */
|
|
var FUNC_ERROR_TEXT = 'Expected a function';
|
|
|
|
/* Built-in method references for those with the same name as other `lodash` methods. */
|
|
var nativeMax = Math.max,
|
|
nativeMin = Math.min;
|
|
|
|
/**
|
|
* Creates a debounced function that delays invoking `func` until after `wait`
|
|
* milliseconds have elapsed since the last time the debounced function was
|
|
* invoked. The debounced function comes with a `cancel` method to cancel
|
|
* delayed `func` invocations and a `flush` method to immediately invoke them.
|
|
* Provide `options` to indicate whether `func` should be invoked on the
|
|
* leading and/or trailing edge of the `wait` timeout. The `func` is invoked
|
|
* with the last arguments provided to the debounced function. Subsequent
|
|
* calls to the debounced function return the result of the last `func`
|
|
* invocation.
|
|
*
|
|
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
* invoked on the trailing edge of the timeout only if the debounced function
|
|
* is invoked more than once during the `wait` timeout.
|
|
*
|
|
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
*
|
|
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
|
* for details over the differences between `_.debounce` and `_.throttle`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 0.1.0
|
|
* @category Function
|
|
* @param {Function} func The function to debounce.
|
|
* @param {number} [wait=0] The number of milliseconds to delay.
|
|
* @param {Object} [options={}] The options object.
|
|
* @param {boolean} [options.leading=false]
|
|
* Specify invoking on the leading edge of the timeout.
|
|
* @param {number} [options.maxWait]
|
|
* The maximum time `func` is allowed to be delayed before it's invoked.
|
|
* @param {boolean} [options.trailing=true]
|
|
* Specify invoking on the trailing edge of the timeout.
|
|
* @returns {Function} Returns the new debounced function.
|
|
* @example
|
|
*
|
|
* // Avoid costly calculations while the window size is in flux.
|
|
* jQuery(window).on('resize', _.debounce(calculateLayout, 150));
|
|
*
|
|
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
|
* jQuery(element).on('click', _.debounce(sendMail, 300, {
|
|
* 'leading': true,
|
|
* 'trailing': false
|
|
* }));
|
|
*
|
|
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
|
* var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
|
|
* var source = new EventSource('/stream');
|
|
* jQuery(source).on('message', debounced);
|
|
*
|
|
* // Cancel the trailing debounced invocation.
|
|
* jQuery(window).on('popstate', debounced.cancel);
|
|
*/
|
|
function debounce(func, wait, options) {
|
|
var lastArgs,
|
|
lastThis,
|
|
maxWait,
|
|
result,
|
|
timerId,
|
|
lastCallTime,
|
|
lastInvokeTime = 0,
|
|
leading = false,
|
|
maxing = false,
|
|
trailing = true;
|
|
|
|
if (typeof func != 'function') {
|
|
throw new TypeError(FUNC_ERROR_TEXT);
|
|
}
|
|
wait = toNumber(wait) || 0;
|
|
if (isObject(options)) {
|
|
leading = !!options.leading;
|
|
maxing = 'maxWait' in options;
|
|
maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
|
|
trailing = 'trailing' in options ? !!options.trailing : trailing;
|
|
}
|
|
|
|
function invokeFunc(time) {
|
|
var args = lastArgs,
|
|
thisArg = lastThis;
|
|
|
|
lastArgs = lastThis = undefined;
|
|
lastInvokeTime = time;
|
|
result = func.apply(thisArg, args);
|
|
return result;
|
|
}
|
|
|
|
function leadingEdge(time) {
|
|
// Reset any `maxWait` timer.
|
|
lastInvokeTime = time;
|
|
// Start the timer for the trailing edge.
|
|
timerId = setTimeout(timerExpired, wait);
|
|
// Invoke the leading edge.
|
|
return leading ? invokeFunc(time) : result;
|
|
}
|
|
|
|
function remainingWait(time) {
|
|
var timeSinceLastCall = time - lastCallTime,
|
|
timeSinceLastInvoke = time - lastInvokeTime,
|
|
timeWaiting = wait - timeSinceLastCall;
|
|
|
|
return maxing
|
|
? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
|
|
: timeWaiting;
|
|
}
|
|
|
|
function shouldInvoke(time) {
|
|
var timeSinceLastCall = time - lastCallTime,
|
|
timeSinceLastInvoke = time - lastInvokeTime;
|
|
|
|
// Either this is the first call, activity has stopped and we're at the
|
|
// trailing edge, the system time has gone backwards and we're treating
|
|
// it as the trailing edge, or we've hit the `maxWait` limit.
|
|
return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
|
|
(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
|
|
}
|
|
|
|
function timerExpired() {
|
|
var time = now();
|
|
if (shouldInvoke(time)) {
|
|
return trailingEdge(time);
|
|
}
|
|
// Restart the timer.
|
|
timerId = setTimeout(timerExpired, remainingWait(time));
|
|
}
|
|
|
|
function trailingEdge(time) {
|
|
timerId = undefined;
|
|
|
|
// Only invoke if we have `lastArgs` which means `func` has been
|
|
// debounced at least once.
|
|
if (trailing && lastArgs) {
|
|
return invokeFunc(time);
|
|
}
|
|
lastArgs = lastThis = undefined;
|
|
return result;
|
|
}
|
|
|
|
function cancel() {
|
|
if (timerId !== undefined) {
|
|
clearTimeout(timerId);
|
|
}
|
|
lastInvokeTime = 0;
|
|
lastArgs = lastCallTime = lastThis = timerId = undefined;
|
|
}
|
|
|
|
function flush() {
|
|
return timerId === undefined ? result : trailingEdge(now());
|
|
}
|
|
|
|
function debounced() {
|
|
var time = now(),
|
|
isInvoking = shouldInvoke(time);
|
|
|
|
lastArgs = arguments;
|
|
lastThis = this;
|
|
lastCallTime = time;
|
|
|
|
if (isInvoking) {
|
|
if (timerId === undefined) {
|
|
return leadingEdge(lastCallTime);
|
|
}
|
|
if (maxing) {
|
|
// Handle invocations in a tight loop.
|
|
clearTimeout(timerId);
|
|
timerId = setTimeout(timerExpired, wait);
|
|
return invokeFunc(lastCallTime);
|
|
}
|
|
}
|
|
if (timerId === undefined) {
|
|
timerId = setTimeout(timerExpired, wait);
|
|
}
|
|
return result;
|
|
}
|
|
debounced.cancel = cancel;
|
|
debounced.flush = flush;
|
|
return debounced;
|
|
}
|
|
|
|
var debounce_1 = debounce;
|
|
|
|
class BubbleMenuView {
|
|
constructor({ editor, element, view, tippyOptions = {}, updateDelay = 250, shouldShow, }) {
|
|
this.preventHide = false;
|
|
this.shouldShow = ({ view, state, from, to, }) => {
|
|
const { doc, selection } = state;
|
|
const { empty } = selection;
|
|
// Sometime check for `empty` is not enough.
|
|
// Doubleclick an empty paragraph returns a node size of 2.
|
|
// So we check also for an empty text size.
|
|
const isEmptyTextBlock = !doc.textBetween(from, to).length
|
|
&& core.isTextSelection(state.selection);
|
|
// When clicking on a element inside the bubble menu the editor "blur" event
|
|
// is called and the bubble menu item is focussed. In this case we should
|
|
// consider the menu as part of the editor and keep showing the menu
|
|
const isChildOfMenu = this.element.contains(document.activeElement);
|
|
const hasEditorFocus = view.hasFocus() || isChildOfMenu;
|
|
if (!hasEditorFocus
|
|
|| empty
|
|
|| isEmptyTextBlock
|
|
|| !this.editor.isEditable) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
this.mousedownHandler = () => {
|
|
this.preventHide = true;
|
|
};
|
|
this.dragstartHandler = () => {
|
|
this.hide();
|
|
};
|
|
this.focusHandler = () => {
|
|
// we use `setTimeout` to make sure `selection` is already updated
|
|
setTimeout(() => this.update(this.editor.view));
|
|
};
|
|
this.blurHandler = ({ event }) => {
|
|
var _a;
|
|
if (this.preventHide) {
|
|
this.preventHide = false;
|
|
return;
|
|
}
|
|
if ((event === null || event === void 0 ? void 0 : event.relatedTarget)
|
|
&& ((_a = this.element.parentNode) === null || _a === void 0 ? void 0 : _a.contains(event.relatedTarget))) {
|
|
return;
|
|
}
|
|
this.hide();
|
|
};
|
|
this.tippyBlurHandler = (event) => {
|
|
this.blurHandler({ event });
|
|
};
|
|
this.updateHandler = (view, oldState) => {
|
|
var _a, _b, _c;
|
|
const { state, composing } = view;
|
|
const { doc, selection } = state;
|
|
const isSame = oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection);
|
|
if (composing || isSame) {
|
|
return;
|
|
}
|
|
this.createTooltip();
|
|
// support for CellSelections
|
|
const { ranges } = selection;
|
|
const from = Math.min(...ranges.map(range => range.$from.pos));
|
|
const to = Math.max(...ranges.map(range => range.$to.pos));
|
|
const shouldShow = (_a = this.shouldShow) === null || _a === void 0 ? void 0 : _a.call(this, {
|
|
editor: this.editor,
|
|
view,
|
|
state,
|
|
oldState,
|
|
from,
|
|
to,
|
|
});
|
|
if (!shouldShow) {
|
|
this.hide();
|
|
return;
|
|
}
|
|
(_b = this.tippy) === null || _b === void 0 ? void 0 : _b.setProps({
|
|
getReferenceClientRect: ((_c = this.tippyOptions) === null || _c === void 0 ? void 0 : _c.getReferenceClientRect) || (() => {
|
|
if (core.isNodeSelection(state.selection)) {
|
|
const node = view.nodeDOM(from);
|
|
if (node) {
|
|
return node.getBoundingClientRect();
|
|
}
|
|
}
|
|
return core.posToDOMRect(view, from, to);
|
|
}),
|
|
});
|
|
this.show();
|
|
};
|
|
this.editor = editor;
|
|
this.element = element;
|
|
this.view = view;
|
|
this.updateDelay = updateDelay;
|
|
if (shouldShow) {
|
|
this.shouldShow = shouldShow;
|
|
}
|
|
this.element.addEventListener('mousedown', this.mousedownHandler, { capture: true });
|
|
this.view.dom.addEventListener('dragstart', this.dragstartHandler);
|
|
this.editor.on('focus', this.focusHandler);
|
|
this.editor.on('blur', this.blurHandler);
|
|
this.tippyOptions = tippyOptions;
|
|
// Detaches menu content from its current parent
|
|
this.element.remove();
|
|
this.element.style.visibility = 'visible';
|
|
}
|
|
createTooltip() {
|
|
const { element: editorElement } = this.editor.options;
|
|
const editorIsAttached = !!editorElement.parentElement;
|
|
if (this.tippy || !editorIsAttached) {
|
|
return;
|
|
}
|
|
this.tippy = tippy__default["default"](editorElement, {
|
|
duration: 0,
|
|
getReferenceClientRect: null,
|
|
content: this.element,
|
|
interactive: true,
|
|
trigger: 'manual',
|
|
placement: 'top',
|
|
hideOnClick: 'toggle',
|
|
...this.tippyOptions,
|
|
});
|
|
// maybe we have to hide tippy on its own blur event as well
|
|
if (this.tippy.popper.firstChild) {
|
|
this.tippy.popper.firstChild.addEventListener('blur', this.tippyBlurHandler);
|
|
}
|
|
}
|
|
update(view, oldState) {
|
|
const { state } = view;
|
|
const hasValidSelection = state.selection.$from.pos !== state.selection.$to.pos;
|
|
if (this.updateDelay > 0 && hasValidSelection) {
|
|
debounce_1(this.updateHandler, this.updateDelay)(view, oldState);
|
|
}
|
|
else {
|
|
this.updateHandler(view, oldState);
|
|
}
|
|
}
|
|
show() {
|
|
var _a;
|
|
(_a = this.tippy) === null || _a === void 0 ? void 0 : _a.show();
|
|
}
|
|
hide() {
|
|
var _a;
|
|
(_a = this.tippy) === null || _a === void 0 ? void 0 : _a.hide();
|
|
}
|
|
destroy() {
|
|
var _a, _b;
|
|
if ((_a = this.tippy) === null || _a === void 0 ? void 0 : _a.popper.firstChild) {
|
|
this.tippy.popper.firstChild.removeEventListener('blur', this.tippyBlurHandler);
|
|
}
|
|
(_b = this.tippy) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
this.element.removeEventListener('mousedown', this.mousedownHandler, { capture: true });
|
|
this.view.dom.removeEventListener('dragstart', this.dragstartHandler);
|
|
this.editor.off('focus', this.focusHandler);
|
|
this.editor.off('blur', this.blurHandler);
|
|
}
|
|
}
|
|
const BubbleMenuPlugin = (options) => {
|
|
return new prosemirrorState.Plugin({
|
|
key: typeof options.pluginKey === 'string'
|
|
? new prosemirrorState.PluginKey(options.pluginKey)
|
|
: options.pluginKey,
|
|
view: view => new BubbleMenuView({ view, ...options }),
|
|
});
|
|
};
|
|
|
|
const BubbleMenu = core.Extension.create({
|
|
name: 'bubbleMenu',
|
|
addOptions() {
|
|
return {
|
|
element: null,
|
|
tippyOptions: {},
|
|
pluginKey: 'bubbleMenu',
|
|
updateDelay: undefined,
|
|
shouldShow: null,
|
|
};
|
|
},
|
|
addProseMirrorPlugins() {
|
|
if (!this.options.element) {
|
|
return [];
|
|
}
|
|
return [
|
|
BubbleMenuPlugin({
|
|
pluginKey: this.options.pluginKey,
|
|
editor: this.editor,
|
|
element: this.options.element,
|
|
tippyOptions: this.options.tippyOptions,
|
|
updateDelay: this.options.updateDelay,
|
|
shouldShow: this.options.shouldShow,
|
|
}),
|
|
];
|
|
},
|
|
});
|
|
|
|
exports.BubbleMenu = BubbleMenu;
|
|
exports.BubbleMenuPlugin = BubbleMenuPlugin;
|
|
exports.BubbleMenuView = BubbleMenuView;
|
|
exports["default"] = BubbleMenu;
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
}));
|
|
//# sourceMappingURL=tiptap-extension-bubble-menu.umd.js.map
|