UNPKG

slate-react

Version:

Tools for building completely customizable richtext editors with React.

1,535 lines (1,291 loc) • 1.14 MB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('slate')) : typeof define === 'function' && define.amd ? define(['exports', 'react', 'slate'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.SlateReact = {}, global.React, global.Slate)); }(this, (function (exports, React, slate) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var defineProperty = createCommonjsModule(function (module) { function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } module.exports = _defineProperty; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _defineProperty = unwrapExports(defineProperty); var arrayWithHoles = createCommonjsModule(function (module) { function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } module.exports = _arrayWithHoles; module.exports["default"] = module.exports, module.exports.__esModule = true; }); unwrapExports(arrayWithHoles); var iterableToArrayLimit = createCommonjsModule(function (module) { function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } module.exports = _iterableToArrayLimit; module.exports["default"] = module.exports, module.exports.__esModule = true; }); unwrapExports(iterableToArrayLimit); var arrayLikeToArray = createCommonjsModule(function (module) { function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } module.exports = _arrayLikeToArray; module.exports["default"] = module.exports, module.exports.__esModule = true; }); unwrapExports(arrayLikeToArray); var unsupportedIterableToArray = createCommonjsModule(function (module) { function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen); } module.exports = _unsupportedIterableToArray; module.exports["default"] = module.exports, module.exports.__esModule = true; }); unwrapExports(unsupportedIterableToArray); var nonIterableRest = createCommonjsModule(function (module) { function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } module.exports = _nonIterableRest; module.exports["default"] = module.exports, module.exports.__esModule = true; }); unwrapExports(nonIterableRest); var slicedToArray = createCommonjsModule(function (module) { function _slicedToArray(arr, i) { return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || unsupportedIterableToArray(arr, i) || nonIterableRest(); } module.exports = _slicedToArray; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _slicedToArray = unwrapExports(slicedToArray); var objectWithoutPropertiesLoose = createCommonjsModule(function (module) { function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } module.exports = _objectWithoutPropertiesLoose; module.exports["default"] = module.exports, module.exports.__esModule = true; }); unwrapExports(objectWithoutPropertiesLoose); var objectWithoutProperties = createCommonjsModule(function (module) { function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } module.exports = _objectWithoutProperties; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _objectWithoutProperties = unwrapExports(objectWithoutProperties); var direction_1 = direction; var RTL = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC'; var LTR = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6' + '\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF\u200E\u2C00-\uFB1C' + '\uFE00-\uFE6F\uFEFD-\uFFFF'; var rtl = new RegExp('^[^' + LTR + ']*[' + RTL + ']'); var ltr = new RegExp('^[^' + RTL + ']*[' + LTR + ']'); function direction(value) { value = String(value || ''); if (rtl.test(value)) { return 'rtl' } if (ltr.test(value)) { return 'ltr' } return 'neutral' } /** * 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(value) { var type = typeof value; return value != null && (type == 'object' || type == 'function'); } var isObject_1 = isObject; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal; 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 = _freeGlobal || freeSelf || Function('return this')(); var _root = 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 = function() { return _root.Date.now(); }; var now_1 = now; /** 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(string) { var index = string.length; while (index-- && reWhitespace.test(string.charAt(index))) {} return index; } 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(string) { return string ? string.slice(0, _trimmedEndIndex(string) + 1).replace(reTrimStart, '') : string; } var _baseTrim = baseTrim; /** Built-in value references. */ var Symbol$1 = _root.Symbol; var _Symbol = Symbol$1; /** Used for built-in method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var nativeObjectToString = objectProto.toString; /** Built-in value references. */ var symToStringTag = _Symbol ? _Symbol.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(value) { var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag]; try { value[symToStringTag] = undefined; var unmasked = true; } catch (e) {} var result = nativeObjectToString.call(value); if (unmasked) { if (isOwn) { value[symToStringTag] = tag; } else { delete value[symToStringTag]; } } return result; } var _getRawTag = getRawTag; /** Used for built-in method references. */ var objectProto$1 = Object.prototype; /** * 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; /** * Converts `value` to a string using `Object.prototype.toString`. * * @private * @param {*} value The value to convert. * @returns {string} Returns the converted string. */ function objectToString(value) { return nativeObjectToString$1.call(value); } var _objectToString = objectToString; /** `Object#toString` result references. */ var nullTag = '[object Null]', undefinedTag = '[object Undefined]'; /** Built-in value references. */ var symToStringTag$1 = _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(value) { if (value == null) { return value === undefined ? undefinedTag : nullTag; } return (symToStringTag$1 && symToStringTag$1 in Object(value)) ? _getRawTag(value) : _objectToString(value); } var _baseGetTag = baseGetTag; /** * 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(value) { return value != null && typeof value == 'object'; } var isObjectLike_1 = isObjectLike; /** `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(value) { return typeof value == 'symbol' || (isObjectLike_1(value) && _baseGetTag(value) == symbolTag); } var isSymbol_1 = isSymbol; /** 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(value) { if (typeof value == 'number') { return value; } if (isSymbol_1(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; /** 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_1(wait) || 0; if (isObject_1(options)) { leading = !!options.leading; maxing = 'maxWait' in options; maxWait = maxing ? nativeMax(toNumber_1(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_1(); 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_1()); } function debounced() { var time = now_1(), 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; /** Error message constants. */ var FUNC_ERROR_TEXT$1 = 'Expected a function'; /** * Creates a throttled function that only invokes `func` at most once per * every `wait` milliseconds. The throttled 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 * throttled function. Subsequent calls to the throttled 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 throttled 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 `_.throttle` and `_.debounce`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to throttle. * @param {number} [wait=0] The number of milliseconds to throttle invocations to. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=true] * Specify invoking on the leading edge of the timeout. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @returns {Function} Returns the new throttled function. * @example * * // Avoid excessively updating the position while scrolling. * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); * * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); * jQuery(element).on('click', throttled); * * // Cancel the trailing throttled invocation. * jQuery(window).on('popstate', throttled.cancel); */ function throttle(func, wait, options) { var leading = true, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT$1); } if (isObject_1(options)) { leading = 'leading' in options ? !!options.leading : leading; trailing = 'trailing' in options ? !!options.trailing : trailing; } return debounce_1(func, wait, { 'leading': leading, 'maxWait': wait, 'trailing': trailing }); } var throttle_1 = throttle; function isElement(el) { return el != null && typeof el === 'object' && el.nodeType === 1; } function canOverflow(overflow, skipOverflowHiddenElements) { if (skipOverflowHiddenElements && overflow === 'hidden') { return false; } return overflow !== 'visible' && overflow !== 'clip'; } function getFrameElement(el) { if (!el.ownerDocument || !el.ownerDocument.defaultView) { return null; } try { return el.ownerDocument.defaultView.frameElement; } catch (e) { return null; } } function isHiddenByFrame(el) { var frame = getFrameElement(el); if (!frame) { return false; } return frame.clientHeight < el.scrollHeight || frame.clientWidth < el.scrollWidth; } function isScrollable(el, skipOverflowHiddenElements) { if (el.clientHeight < el.scrollHeight || el.clientWidth < el.scrollWidth) { var style = getComputedStyle(el, null); return canOverflow(style.overflowY, skipOverflowHiddenElements) || canOverflow(style.overflowX, skipOverflowHiddenElements) || isHiddenByFrame(el); } return false; } function alignNearest(scrollingEdgeStart, scrollingEdgeEnd, scrollingSize, scrollingBorderStart, scrollingBorderEnd, elementEdgeStart, elementEdgeEnd, elementSize) { if (elementEdgeStart < scrollingEdgeStart && elementEdgeEnd > scrollingEdgeEnd || elementEdgeStart > scrollingEdgeStart && elementEdgeEnd < scrollingEdgeEnd) { return 0; } if (elementEdgeStart <= scrollingEdgeStart && elementSize <= scrollingSize || elementEdgeEnd >= scrollingEdgeEnd && elementSize >= scrollingSize) { return elementEdgeStart - scrollingEdgeStart - scrollingBorderStart; } if (elementEdgeEnd > scrollingEdgeEnd && elementSize < scrollingSize || elementEdgeStart < scrollingEdgeStart && elementSize > scrollingSize) { return elementEdgeEnd - scrollingEdgeEnd + scrollingBorderEnd; } return 0; } var compute = (function (target, options) { var scrollMode = options.scrollMode, block = options.block, inline = options.inline, boundary = options.boundary, skipOverflowHiddenElements = options.skipOverflowHiddenElements; var checkBoundary = typeof boundary === 'function' ? boundary : function (node) { return node !== boundary; }; if (!isElement(target)) { throw new TypeError('Invalid target'); } var scrollingElement = document.scrollingElement || document.documentElement; var frames = []; var cursor = target; while (isElement(cursor) && checkBoundary(cursor)) { cursor = cursor.parentNode; if (cursor === scrollingElement) { frames.push(cursor); break; } if (cursor === document.body && isScrollable(cursor) && !isScrollable(document.documentElement)) { continue; } if (isScrollable(cursor, skipOverflowHiddenElements)) { frames.push(cursor); } } var viewportWidth = window.visualViewport ? visualViewport.width : innerWidth; var viewportHeight = window.visualViewport ? visualViewport.height : innerHeight; var viewportX = window.scrollX || pageXOffset; var viewportY = window.scrollY || pageYOffset; var _target$getBoundingCl = target.getBoundingClientRect(), targetHeight = _target$getBoundingCl.height, targetWidth = _target$getBoundingCl.width, targetTop = _target$getBoundingCl.top, targetRight = _target$getBoundingCl.right, targetBottom = _target$getBoundingCl.bottom, targetLeft = _target$getBoundingCl.left; var targetBlock = block === 'start' || block === 'nearest' ? targetTop : block === 'end' ? targetBottom : targetTop + targetHeight / 2; var targetInline = inline === 'center' ? targetLeft + targetWidth / 2 : inline === 'end' ? targetRight : targetLeft; var computations = []; for (var index = 0; index < frames.length; index++) { var frame = frames[index]; var _frame$getBoundingCli = frame.getBoundingClientRect(), height = _frame$getBoundingCli.height, width = _frame$getBoundingCli.width, top = _frame$getBoundingCli.top, right = _frame$getBoundingCli.right, bottom = _frame$getBoundingCli.bottom, left = _frame$getBoundingCli.left; if (scrollMode === 'if-needed' && targetTop >= 0 && targetLeft >= 0 && targetBottom <= viewportHeight && targetRight <= viewportWidth && targetTop >= top && targetBottom <= bottom && targetLeft >= left && targetRight <= right) { return computations; } var frameStyle = getComputedStyle(frame); var borderLeft = parseInt(frameStyle.borderLeftWidth, 10); var borderTop = parseInt(frameStyle.borderTopWidth, 10); var borderRight = parseInt(frameStyle.borderRightWidth, 10); var borderBottom = parseInt(frameStyle.borderBottomWidth, 10); var blockScroll = 0; var inlineScroll = 0; var scrollbarWidth = 'offsetWidth' in frame ? frame.offsetWidth - frame.clientWidth - borderLeft - borderRight : 0; var scrollbarHeight = 'offsetHeight' in frame ? frame.offsetHeight - frame.clientHeight - borderTop - borderBottom : 0; if (scrollingElement === frame) { if (block === 'start') { blockScroll = targetBlock; } else if (block === 'end') { blockScroll = targetBlock - viewportHeight; } else if (block === 'nearest') { blockScroll = alignNearest(viewportY, viewportY + viewportHeight, viewportHeight, borderTop, borderBottom, viewportY + targetBlock, viewportY + targetBlock + targetHeight, targetHeight); } else { blockScroll = targetBlock - viewportHeight / 2; } if (inline === 'start') { inlineScroll = targetInline; } else if (inline === 'center') { inlineScroll = targetInline - viewportWidth / 2; } else if (inline === 'end') { inlineScroll = targetInline - viewportWidth; } else { inlineScroll = alignNearest(viewportX, viewportX + viewportWidth, viewportWidth, borderLeft, borderRight, viewportX + targetInline, viewportX + targetInline + targetWidth, targetWidth); } blockScroll = Math.max(0, blockScroll + viewportY); inlineScroll = Math.max(0, inlineScroll + viewportX); } else { if (block === 'start') { blockScroll = targetBlock - top - borderTop; } else if (block === 'end') { blockScroll = targetBlock - bottom + borderBottom + scrollbarHeight; } else if (block === 'nearest') { blockScroll = alignNearest(top, bottom, height, borderTop, borderBottom + scrollbarHeight, targetBlock, targetBlock + targetHeight, targetHeight); } else { blockScroll = targetBlock - (top + height / 2) + scrollbarHeight / 2; } if (inline === 'start') { inlineScroll = targetInline - left - borderLeft; } else if (inline === 'center') { inlineScroll = targetInline - (left + width / 2) + scrollbarWidth / 2; } else if (inline === 'end') { inlineScroll = targetInline - right + borderRight + scrollbarWidth; } else { inlineScroll = alignNearest(left, right, width, borderLeft, borderRight + scrollbarWidth, targetInline, targetInline + targetWidth, targetWidth); } var scrollLeft = frame.scrollLeft, scrollTop = frame.scrollTop; blockScroll = Math.max(0, Math.min(scrollTop + blockScroll, frame.scrollHeight - height + scrollbarHeight)); inlineScroll = Math.max(0, Math.min(scrollLeft + inlineScroll, frame.scrollWidth - width + scrollbarWidth)); targetBlock += scrollTop - blockScroll; targetInline += scrollLeft - inlineScroll; } computations.push({ el: frame, top: blockScroll, left: inlineScroll }); } return computations; }); function isOptionsObject(options) { return options === Object(options) && Object.keys(options).length !== 0; } function defaultBehavior(actions, behavior) { if (behavior === void 0) { behavior = 'auto'; } var canSmoothScroll = ('scrollBehavior' in document.body.style); actions.forEach(function (_ref) { var el = _ref.el, top = _ref.top, left = _ref.left; if (el.scroll && canSmoothScroll) { el.scroll({ top: top, left: left, behavior: behavior }); } else { el.scrollTop = top; el.scrollLeft = left; } }); } function getOptions(options) { if (options === false) { return { block: 'end', inline: 'nearest' }; } if (isOptionsObject(options)) { return options; } return { block: 'start', inline: 'nearest' }; } function scrollIntoView(target, options) { var targetIsDetached = !target.ownerDocument.documentElement.contains(target); if (isOptionsObject(options) && typeof options.behavior === 'function') { return options.behavior(targetIsDetached ? [] : compute(target, options)); } if (targetIsDetached) { return; } var computeOptions = getOptions(options); return defaultBehavior(compute(target, computeOptions), computeOptions.behavior); } /** * Leaf content strings. */ var String$1 = function String(props) { var isLast = props.isLast, leaf = props.leaf, parent = props.parent, text = props.text; var editor = useSlateStatic(); var path = ReactEditor.findPath(editor, text); var parentPath = slate.Path.parent(path); // COMPAT: Render text inside void nodes with a zero-width space. // So the node can contain selection but the text is not visible. if (editor.isVoid(parent)) { return /*#__PURE__*/React__default['default'].createElement(ZeroWidthString, { length: slate.Node.string(parent).length }); } // COMPAT: If this is the last text node in an empty block, render a zero- // width space that will convert into a line break when copying and pasting // to support expected plain text. if (leaf.text === '' && parent.children[parent.children.length - 1] === text && !editor.isInline(parent) && slate.Editor.string(editor, parentPath) === '') { return /*#__PURE__*/React__default['default'].createElement(ZeroWidthString, { isLineBreak: true }); } // COMPAT: If the text is empty, it's because it's on the edge of an inline // node, so we render a zero-width space so that the selection can be // inserted next to it still. if (leaf.text === '') { return /*#__PURE__*/React__default['default'].createElement(ZeroWidthString, null); } // COMPAT: Browsers will collapse trailing new lines at the end of blocks, // so we need to add an extra trailing new lines to prevent that. if (isLast && leaf.text.slice(-1) === '\n') { return /*#__PURE__*/React__default['default'].createElement(TextString, { isTrailing: true, text: leaf.text }); } return /*#__PURE__*/React__default['default'].createElement(TextString, { text: leaf.text }); }; /** * Leaf strings with text in them. */ var TextString = function TextString(props) { var text = props.text, _props$isTrailing = props.isTrailing, isTrailing = _props$isTrailing === void 0 ? false : _props$isTrailing; return /*#__PURE__*/React__default['default'].createElement("span", { "data-slate-string": true }, text, isTrailing ? '\n' : null); }; /** * Leaf strings without text, render as zero-width strings. */ var ZeroWidthString = function ZeroWidthString(props) { var _props$length = props.length, length = _props$length === void 0 ? 0 : _props$length, _props$isLineBreak = props.isLineBreak, isLineBreak = _props$isLineBreak === void 0 ? false : _props$isLineBreak; return /*#__PURE__*/React__default['default'].createElement("span", { "data-slate-zero-width": isLineBreak ? 'n' : 'z', "data-slate-length": length }, "\uFEFF", isLineBreak ? /*#__PURE__*/React__default['default'].createElement("br", null) : null); }; /** * Two weak maps that allow us rebuild a path given a node. They are populated * at render time such that after a render occurs we can always backtrack. */ var NODE_TO_INDEX = new WeakMap(); var NODE_TO_PARENT = new WeakMap(); /** * Weak maps that allow us to go between Slate nodes and DOM nodes. These * are used to resolve DOM event-related logic into Slate actions. */ var EDITOR_TO_WINDOW = new WeakMap(); var EDITOR_TO_ELEMENT = new WeakMap(); var ELEMENT_TO_NODE = new WeakMap(); var KEY_TO_ELEMENT = new WeakMap(); var NODE_TO_ELEMENT = new WeakMap(); var NODE_TO_KEY = new WeakMap(); /** * Weak maps for storing editor-related state. */ var IS_READ_ONLY = new WeakMap(); var IS_FOCUSED = new WeakMap(); /** * Weak map for associating the context `onChange` context with the plugin. */ var EDITOR_TO_ON_CHANGE = new WeakMap(); var EDITOR_TO_RESTORE_DOM = new WeakMap(); /** * Symbols. */ var PLACEHOLDER_SYMBOL = Symbol('placeholder'); // prevent inconsistent rendering by React with IME input var keyForString = 0; /** * Individual leaves in a text node with unique formatting. */ var Leaf = function Leaf(props) { var leaf = props.leaf, isLast = props.isLast, text = props.text, parent = props.parent, renderPlaceholder = props.renderPlaceholder, _props$renderLeaf = props.renderLeaf, renderLeaf = _props$renderLeaf === void 0 ? function (props) { return /*#__PURE__*/React__default['default'].createElement(DefaultLeaf, Object.assign({}, props)); } : _props$renderLeaf; var placeholderRef = React.useRef(null); React.useEffect(function () { var placeholderEl = placeholderRef === null || placeholderRef === void 0 ? void 0 : placeholderRef.current; var editorEl = document.querySelector('[data-slate-editor="true"]'); if (!placeholderEl || !editorEl) { return; } editorEl.style.minHeight = "".concat(placeholderEl.clientHeight, "px"); return function () { editorEl.style.minHeight = 'auto'; }; }, [placeholderRef, leaf]); var children = /*#__PURE__*/React__default['default'].createElement(String$1, { key: keyForString++, isLast: isLast, leaf: leaf, parent: parent, text: text }); if (leaf[PLACEHOLDER_SYMBOL]) { var placeholderProps = { children: leaf.placeholder, attributes: { 'data-slate-placeholder': true, style: { position: 'absolute', pointerEvents: 'none', width: '100%', maxWidth: '100%', display: 'block', opacity: '0.333', userSelect: 'none', textDecoration: 'none' }, contentEditable: false, ref: placeholderRef } }; children = /*#__PURE__*/React__default['default'].createElement(React__default['default'].Fragment, null, renderPlaceholder(placeholderProps), children); } // COMPAT: Having the `data-` attributes on these leaf elements ensures that // in certain misbehaving browsers they aren't weirdly cloned/destroyed by // contenteditable behaviors. (2019/05/08) var attributes = { 'data-slate-leaf': true }; return renderLeaf({ attributes: attributes, children: children, leaf: leaf, text: text }); }; var MemoizedLeaf = /*#__PURE__*/React__default['default'].memo(Leaf, function (prev, next) { return next.parent === prev.parent && next.isLast === prev.isLast && next.renderLeaf === prev.renderLeaf && next.renderPlaceholder === prev.renderPlaceholder && next.text === prev.text && next.leaf.text === prev.leaf.text && slate.Text.matches(next.leaf, prev.leaf) && next.leaf[PLACEHOLDER_SYMBOL] === prev.leaf[PLACEHOLDER_SYMBOL]; }); var DefaultLeaf = function DefaultLeaf(props) { var attributes = props.attributes, children = props.children; return /*#__PURE__*/React__default['default'].createElement("span", Object.assign({}, attributes), children); }; var IS_IOS = typeof navigator !== 'undefined' && typeof window !== 'undefined' && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; var IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent); var IS_ANDROID = typeof navigator !== 'undefined' && /Android/.test(navigator.userAgent); var IS_FIREFOX = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent); var IS_SAFARI = typeof navigator !== 'undefined' && /Version\/[\d\.]+.*Safari/.test(navigator.userAgent); // "modern" Edge was released at 79.x var IS_EDGE_LEGACY = typeof navigator !== 'undefined' && /Edge?\/(?:[0-6][0-9]|[0-7][0-8])/i.test(navigator.userAgent); var IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.userAgent); // Native `beforeInput` events don't work well with react on Chrome 75 // and older, Chrome 76+ can use `beforeInput` though. var IS_CHROME_LEGACY = typeof navigator !== 'undefined' && /Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent); // Firefox did not support `beforeInput` until `v87`. var IS_FIREFOX_LEGACY = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])).*/i.test(navigator.userAgent); // Check if DOM is available as React does internally. // https://github.com/facebook/react/blob/master/packages/shared/ExecutionEnvironment.js var CAN_USE_DOM = !!(typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined'); // COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event // Chrome Legacy doesn't support `beforeinput` correctly var HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY && !IS_EDGE_LEGACY && // globalThis is undefined in older browsers typeof globalThis !== 'undefined' && globalThis.InputEvent && // @ts-ignore The `getTargetRanges` property isn't recognized. typeof globalThis.InputEvent.prototype.getTargetRanges === 'function'; /** * Prevent warning on SSR by falling back to useEffect when DOM isn't available */ var useIsomorphicLayoutEffect = CAN_USE_DOM ? React.useLayoutEffect : React.useEffect; var shallowCompare = function shallowCompare(obj1, obj2) { return Object.keys(obj1).length === Object.keys(obj2).length && Object.keys(obj1).every(function (key) { return obj2.hasOwnProperty(key) && obj1[key] === obj2[key]; }); }; /** * Check if a list of decorator ranges are equal to another. * * PERF: this requires the two lists to also have the ranges inside them in the * same order, but this is an okay constraint for us since decorations are * kept in order, and the odd case where they aren't is okay to re-render for. */ var isDecoratorRangeListEqual = function isDecoratorRangeListEqual(list, another) { if (list.length !== another.length) { return false; } for (var i = 0; i < list.length; i++) { var range = list[i]; var other = another[i]; var rangeAnchor = range.anchor, rangeFocus = range.focus, rangeOwnProps = _objectWithoutProperties(range, ["anchor", "focus"]); var otherAnchor = other.anchor, otherFocus = other.focus, otherOwnProps = _objectWithoutProperties(other, ["anchor", "focus"]); if (!slate.Range.equals(range, other) || range[PLACEHOLDER_SYMBOL] !== other[PLACEHOLDER_SYMBOL] || !shallowCompare(rangeOwnProps, otherOwnProps)) { return false; } } return true; }; /** * Text. */ var Text = function Text(props) { var decorations = props.decorations, isLast = props.isLast, parent = props.parent, renderPlaceholder = props.renderPlaceholder, renderLeaf = props.renderLeaf, text = props.text; var editor = useSlateStatic(); var ref = React.useRef(null); var leaves = slate.Text.decorations(text, decorations); var key = ReactEditor.findKey(editor, text); var children = []; for (var i = 0; i < leaves.length; i++) { var leaf = leaves[i]; children.push( /*#__PURE__*/React__default['default'].createElement(MemoizedLeaf, { isLast: isLast && i === leaves.length - 1, key: "".concat(key.id, "-").concat(i), renderPlaceholder: renderPlaceholder, leaf: leaf, text: text, parent: parent, renderLeaf: renderLeaf })); } // Update element-related weak maps with the DOM element ref. useIsomorphicLayoutEffect(function () { if (ref.current) { KEY_TO_ELEMENT.set(key, ref.current); NODE_TO_ELEMENT.set(text, ref.current); ELEMENT_TO_NODE.set(ref.current, text); } else { KEY_TO_ELEMENT["delete"](key); NODE_TO_ELEMENT["delete"](text); } }); return /*#__PURE__*/React__default['default'].createElement("span", { "data-slate-node": "text", ref: ref }, children); }; var MemoizedText = /*#__PURE__*/React__default['default'].memo(Text, function (prev, next) { return next.parent === prev.parent && next.isLast === prev.isLast && next.renderLeaf === prev.renderLeaf && next.text === prev.text && isDecoratorRangeListEqual(next.decorations, prev.decorations); }); /** * A React context for sharing the `selected` state of an element. */ var SelectedContext = /*#__PURE__*/React.createContext(false); /** * Get the current `selected` state of an element. */ var useSelected = function useSelected() { return React.useContext(SelectedContext); }; /** * Element. */ var Element = function Element(props) { var decorations = props.decorations, element = props.element, _props$renderElement = props.renderElement, renderElement = _props$renderElement === void 0 ? function (p) { return /*#__PURE__*/React__default['default'].createElement(DefaultElement, Object.assign({}, p)); } : _props$renderElement, renderPlaceholder = props.renderPlaceholder, renderLeaf = props.renderLeaf, selection = props.selection; var ref = React.useRef(null); var editor = useSlateStatic(); var readOnly = useReadOnly(); var isInline = editor.isInline(element); var key = ReactEditor.findKey(editor, element); var children = useChildren({ decorations: decorations, node: element, renderElement: renderElement, renderPlaceholder: renderPlaceholder, renderLeaf: renderLeaf, selection: selection }); // Attributes that the developer must mix into the element in their // custom node renderer component. var attributes = { 'data-slate-node': 'element', ref: ref }; if (isInline) { attributes['data-slate-inline'] = true; } // If it's a block node with inline children, add the proper `dir` attribute // for text direction. if (!isInline && slate.Editor.hasInlines(editor, element)) { var text = slate.Node.string(element); var dir = direction_1(text); if (dir === 'rtl') { attributes.dir = dir; } } // If it's a void node, wrap the children in extra void-specific elements. if (slate.Editor.isVoid(editor, element)) { attributes['data-slate-void'] = true; if (!readOnly && isInline) { attributes.contentEditable = false; } var Tag = isInline ? 'span' : 'div'; var _Node$texts = slate.Node.texts(element), _Node$texts2 = _slicedToArray(_Node$texts, 1), _Node$texts2$ = _slicedToArray(_Node$texts2[0], 1), _text = _Node$texts2$[0]; children = readOnly ? null : /*#__PURE__*/React__default['default'].createElement(Tag, { "data-slate-spacer": true, style: { height: '0', color: 'transparent', outline: 'none', position: 'absolute' } }, /*#__PURE__*/React__default['default'].createElement(MemoizedText, { renderPlaceholder: renderPlaceholder, decorations: [], isLast: false, parent: element, text: _text })); NODE_TO_INDEX.set(_text, 0); NODE_TO_PARENT.set(_text, element); } // Update element-related weak maps with the DOM element ref. useIsomorphicLayoutEffect(function () { if (ref.current) { KEY_TO_ELEMENT.set(key, ref.current); NODE_TO_ELEMENT.set(element, ref.current); ELEMENT_TO_NODE.set(ref.current, element); } else { KEY_TO_ELEMENT["delete"](key); NODE_TO_ELEMENT["delete"](element); } }); return /*#__PURE__*/React__default['default'].createElement(SelectedContext.Provider, { value: !!selection }, renderElement({ attributes: attributes, children: children, element: element })); }; var MemoizedElement = /*#__PURE__*/React__default['default'].memo(Element, function (prev, next) { return prev.element === next.element && prev.renderElement === next.renderElement && prev.renderLeaf === next.renderLeaf && isDecoratorRangeListEqual(prev.decorations, next.decorations) && (prev.selection === next.selection || !!prev.selection && !!next.selection && slate.Range.equals(prev.selection, next.selection)); }); /** * The default element renderer. */ var DefaultElement = function DefaultElement(props) { var attributes = props.attributes, children = props.children, element = props.element; var editor = useSlateStatic(); var Tag = editor.isInline(element) ? 'span' : 'div'; return /*#__PURE__*/React__default['default'].createElement(Tag, Object.assign({}, attributes, { style: { position: 'relative' } }), children); }; /** * A React context for sharing the editor object. */ var EditorContext = /*#__PURE__*/React.createContext(null); /** * Get the current editor object from the React context. */ var useSlateStatic = function useSlateStatic() { var editor = React.useContext(EditorContext); if (!editor) { throw new Error("The `useSlateStatic` hook must be used inside the <Slate> component's context."); } return editor; }; /** * A React context for sharing the `decorate` prop of the editable. */ var DecorateContext = /*#__PURE__*/React.createContext(function () { return []; }); /** * Get the current `decorate` prop of the editable. */ var useDecorate = function useDecorate() { return React.useContext(DecorateContext); }; function _createForOfIteratorHelper(o, allowArrayLike) { var it;