prosemirror-suggest
Advanced tools
Comparing version 1.0.0-next.34 to 1.0.0-next.35
# prosemirror-suggest | ||
## 1.0.0-next.35 | ||
> 2020-09-13 | ||
### Major Changes | ||
- [`175c9461`](https://github.com/remirror/remirror/commit/175c946130c3de366f2946f6a2e5be5ee9b9234c) [#676](https://github.com/remirror/remirror/pull/676) Thanks [@ifiokjr](https://github.com/ifiokjr)! - 💥`checkNextValidSelection` method is now run in the `appendTransaction` plugin hook and should only update the provided transaction. It receives the `Transaction` now instead of `EditorState` and another parameter for `matches` provides the name of the changed suggester and the exited suggester. Both can be undefined. | ||
**`Suggester` Options** | ||
- Add `caseInsensitive` option for case insensitive matches. | ||
- Add `multiline` options for matches that can span multiple lines`. | ||
- Add `appendTransaction` option which when true will run the `onChange` handler in the `appendTransaction` plugin hook and expect the transaction to be synchronously updated. | ||
- Add `transaction` parameter to the `onChange` handler for when `appendTransaction` is true. | ||
**`SuggestState`** | ||
- Add new method `findNextTextSelection` which can be used to find the next text selection. | ||
- Add new method `findMatchAtPosition` which finds the match for the provided suggester name at the given `ResolvedPos`. If no suggester name is provided then it looks through all `Suggester`s. | ||
**Other** | ||
- Now supports matches with only the matching regex active. | ||
- Fixes a bug where changes were determined by the query and not the full text match. | ||
### Patch Changes | ||
- [`725df02b`](https://github.com/remirror/remirror/commit/725df02b53fa16b9c7a3768b0c9464e739e35813) [#672](https://github.com/remirror/remirror/pull/672) Thanks [@ifiokjr](https://github.com/ifiokjr)! - Reduce bundle size by updating babel configuration thanks to help from [preconstruct/preconstruct/297](https://github.com/preconstruct/preconstruct/issues/297#issuecomment-690964802). [Fixes #358](https://github.com/remirror/remirror/issues/358). | ||
- Updated dependencies [[`725df02b`](https://github.com/remirror/remirror/commit/725df02b53fa16b9c7a3768b0c9464e739e35813)]: | ||
- @remirror/core-constants@1.0.0-next.35 | ||
- @remirror/core-helpers@1.0.0-next.35 | ||
## 1.0.0-next.34 | ||
@@ -4,0 +37,0 @@ |
@@ -11,3 +11,3 @@ /** | ||
export { ChangeReason, ExitReason } from './suggest-types'; | ||
export { isChange, isChangeReason, isEntry, isExit, isExitReason, isInvalidSplitReason, isJump, isJumpReason, isMove, isRemovedReason, isSelectionExitReason, isSplitReason, isValidMatch, selectionOutsideMatch, } from './suggest-predicates'; | ||
export { createRegexFromSuggester, getSuggesterWithDefaults, DEFAULT_SUGGESTER, markActiveInRange, rangeHasMarks, positionHasMarks, } from './suggest-utils'; | ||
export { isChange, isChangeReason, isEntry, isExit, isExitReason, isInvalidSplitReason, isJump, isJumpReason, isMove, isRemovedReason, isSelectionChangeReason, isSelectionExitReason, isSplitReason, isValidMatch, selectionOutsideMatch, } from './suggest-predicates'; | ||
export { findFromSuggesters, createRegexFromSuggester, getSuggesterWithDefaults, DEFAULT_SUGGESTER, markActiveInRange, rangeHasMarks, positionHasMarks, } from './suggest-utils'; |
@@ -39,2 +39,4 @@ import { TextSelection } from 'prosemirror-state'; | ||
export declare function isSelectionExitReason(value: unknown): value is typeof selectionExitReasons[number]; | ||
declare const selectionChangeReasons: readonly [ChangeReason.JumpBackward, ChangeReason.JumpForward, ChangeReason.Move, ChangeReason.SelectionInside]; | ||
export declare function isSelectionChangeReason(value: unknown): value is typeof selectionChangeReasons[number]; | ||
/** | ||
@@ -41,0 +43,0 @@ * Checks that the reason passed is a split reason. This typically means that we |
@@ -1,4 +0,4 @@ | ||
import { PluginKey } from 'prosemirror-state'; | ||
import { PluginKey, Selection, TextSelection } from 'prosemirror-state'; | ||
import { DecorationSet } from 'prosemirror-view'; | ||
import type { AddIgnoredParameter, EditorSchema, EditorState, EditorStateParameter, EditorView, RemoveIgnoredParameter, Suggester, SuggestMatch, TransactionParameter } from './suggest-types'; | ||
import type { AddIgnoredParameter, EditorSchema, EditorState, EditorStateParameter, EditorView, RemoveIgnoredParameter, ResolvedPos, Suggester, SuggestMatch, Transaction, TransactionParameter } from './suggest-types'; | ||
/** | ||
@@ -68,8 +68,21 @@ * The `prosemirror-suggest` state which manages the list of suggesters. | ||
private shouldRunExit; | ||
private updateWithNextSelection; | ||
/** | ||
* Manages the view updates. | ||
* Find the next text selection from the current selection. | ||
*/ | ||
private onViewUpdate; | ||
readonly findNextTextSelection: (selection: Selection<Schema>) => TextSelection<Schema> | void; | ||
/** | ||
* Update all the suggesters with the next valid selection. This is called | ||
* within the `appendTransaction` ProseMirror method before any of the change | ||
* handlers are called. | ||
* | ||
* @internal | ||
*/ | ||
updateWithNextSelection(tr: Transaction<Schema>): void; | ||
/** | ||
* Call the `onChange` handlers. | ||
* | ||
* @internal | ||
*/ | ||
changeHandler(tr: Transaction<Schema>, appendTransaction: boolean): void; | ||
/** | ||
* Update the current ignored decorations based on the latest changes to the | ||
@@ -128,2 +141,7 @@ * prosemirror document. | ||
/** | ||
* A helper method to check is a match exists for the provided suggester name | ||
* at the provided position. | ||
*/ | ||
readonly findMatchAtPosition: ($pos: ResolvedPos<Schema>, name?: string | undefined) => SuggestMatch<Schema> | undefined; | ||
/** | ||
* Add a new suggest or replace it if it already exists. | ||
@@ -136,8 +154,2 @@ */ | ||
removeSuggester(suggester: Suggester | string): void; | ||
/** | ||
* Used to handle the view property of the plugin spec. | ||
*/ | ||
viewHandler(): { | ||
update: () => void; | ||
}; | ||
toJSON(): SuggestMatch<Schema> | undefined; | ||
@@ -155,2 +167,8 @@ /** | ||
createDecorations(state: EditorState<Schema>): DecorationSet<Schema>; | ||
/** | ||
* Set that the last change was caused by an appended transaction. | ||
* | ||
* @internal | ||
*/ | ||
setLastChangeFromAppend(): void; | ||
} | ||
@@ -157,0 +175,0 @@ /** |
@@ -47,2 +47,13 @@ /** | ||
/** | ||
* Set this to true so that the onChange handler is called in the | ||
* `appendTransaction` prosemirror update handler rather than in the view | ||
* update handler. | ||
* | ||
* This tends to work better with updates that are run multiple times while | ||
* preserving the redo/undo history stack. | ||
* | ||
* @default false | ||
*/ | ||
appendTransaction?: boolean; | ||
/** | ||
* Called whenever a suggester becomes active or changes in any way. | ||
@@ -197,3 +208,3 @@ * | ||
* suggestions problem. It check backwards from the current cursor position to | ||
* see if any text matches any of the configured selections. For the majority | ||
* see if any text matches any of the configured suggesters. For the majority | ||
* of use cases this is perfectly acceptable behaviour. | ||
@@ -208,8 +219,10 @@ * | ||
* This method hopefully makes it easier to do this. You can add a function | ||
* here which is run every time the view updates and provides you with the | ||
* next valid match. | ||
* here which is run every time the view updates and has a valid `next` text | ||
* position and provides you with the next valid match. | ||
* | ||
* This is called after the `onChange` handler calls. | ||
* | ||
* @default null | ||
*/ | ||
checkNextValidSelection?: CheckNextValidSelection | null; | ||
checkNextValidSelection?: CheckNextValidSelection<Schema> | null; | ||
/** | ||
@@ -221,2 +234,15 @@ * Whether this suggester should only be valid for empty selections. | ||
emptySelectionsOnly?: boolean; | ||
/** | ||
* Whether the match should be case insensitive and ignore the case. This adds | ||
* the `i` flag to the regex used. | ||
* | ||
* @default false | ||
*/ | ||
caseInsensitive?: boolean; | ||
/** | ||
* When true support matches across multiple lines. | ||
* | ||
* @default false | ||
*/ | ||
multiline?: boolean; | ||
} | ||
@@ -228,4 +254,13 @@ /** | ||
* handlers are fired. | ||
* | ||
* @param $pos - the next valid position that supports text selections. | ||
* @param tr - the transaction that can be mutated when `appendTransaction` is | ||
* set to true. | ||
* @param matches - the possibly undefined exit and change matcher names. These | ||
* can be used to check if the name matches the current suggester. | ||
*/ | ||
export declare type CheckNextValidSelection<Schema extends EditorSchema = EditorSchema> = ($pos: ResolvedPos<Schema>, state: EditorState<Schema>) => void; | ||
export declare type CheckNextValidSelection<Schema extends EditorSchema = EditorSchema> = ($pos: ResolvedPos<Schema>, tr: Transaction<Schema>, matches: { | ||
change?: string; | ||
exit?: string; | ||
}) => void; | ||
/** | ||
@@ -599,8 +634,13 @@ * A function that can be used to determine whether the decoration should be set | ||
*/ | ||
export interface SuggestChangeHandlerParameter<Schema extends EditorSchema = EditorSchema> extends SuggestMatch<Schema>, EditorViewParameter<Schema>, SuggestIgnoreParameter, ReasonParameter, SuggestMarkParameter, Pick<Suggester<Schema>, 'name' | 'char'> { | ||
export interface SuggestChangeHandlerParameter<Schema extends EditorSchema = EditorSchema> extends SuggestMatchWithReason<Schema>, EditorViewParameter<Schema>, SuggestIgnoreParameter, SuggestMarkParameter, Pick<Suggester<Schema>, 'name' | 'char'> { | ||
} | ||
/** | ||
* The type signature of the `onChange` handler method. | ||
* | ||
* @param changeDetails - all the information related to the change that caused | ||
* this to be called. | ||
* @param tr - the transaction that can be updated when `appendTransaction` is | ||
* set to true. | ||
*/ | ||
export declare type SuggestChangeHandler<Schema extends EditorSchema = EditorSchema> = (parameter: SuggestChangeHandlerParameter<Schema>) => void; | ||
export declare type SuggestChangeHandler<Schema extends EditorSchema = EditorSchema> = (changeDetails: SuggestChangeHandlerParameter<Schema>, tr: Transaction<Schema>) => void; | ||
export interface SuggesterParameter<Schema extends EditorSchema = EditorSchema> { | ||
@@ -607,0 +647,0 @@ /** |
@@ -50,10 +50,4 @@ import type { CompareMatchParameter, DocChangedParameter, EditorSchema, EditorStateParameter, PickPartial, ResolvedPos, ResolvedPosParameter, ResolvedRangeWithCursor, Suggester, SuggestMatch, SuggestReasonMap } from './suggest-types'; | ||
export declare function getCharAsRegex(char: RegExp | string): RegExp; | ||
interface CreateRegexFromSuggesterParameter extends Pick<Required<Suggester>, 'startOfLine' | 'char' | 'supportedCharacters' | 'matchOffset'> { | ||
interface CreateRegexFromSuggesterParameter extends Pick<Required<Suggester>, 'startOfLine' | 'char' | 'supportedCharacters' | 'matchOffset'>, Pick<Suggester, 'multiline' | 'caseInsensitive'> { | ||
/** | ||
* Flags applied to the regex matcher. | ||
* | ||
* @default 'gm' | ||
*/ | ||
flags?: string; | ||
/** | ||
* Whether to capture the `char character as the first capture group. | ||
@@ -60,0 +54,0 @@ * |
@@ -6,2 +6,4 @@ 'use strict'; | ||
var prosemirrorState = require('prosemirror-state'); | ||
var _createForOfIteratorHelper = require('@babel/runtime/helpers/createForOfIteratorHelper'); | ||
var _objectSpread = require('@babel/runtime/helpers/objectSpread2'); | ||
var _defineProperty = require('@babel/runtime/helpers/defineProperty'); | ||
@@ -17,2 +19,4 @@ var _classPrivateFieldSet = require('@babel/runtime/helpers/classPrivateFieldSet'); | ||
var _createForOfIteratorHelper__default = /*#__PURE__*/_interopDefault(_createForOfIteratorHelper); | ||
var _objectSpread__default = /*#__PURE__*/_interopDefault(_objectSpread); | ||
var _defineProperty__default = /*#__PURE__*/_interopDefault(_defineProperty); | ||
@@ -70,3 +74,3 @@ var _classPrivateFieldSet__default = /*#__PURE__*/_interopDefault(_classPrivateFieldSet); | ||
function isChange(compare) { | ||
return !!(compare.prev && compare.next && compare.prev.query.full !== compare.next.query.full); | ||
return !!(compare.prev && compare.next && compare.prev.text.full !== compare.next.text.full); | ||
} | ||
@@ -125,2 +129,6 @@ /** | ||
} | ||
var selectionChangeReasons = [exports.ChangeReason.JumpBackward, exports.ChangeReason.JumpForward, exports.ChangeReason.Move, exports.ChangeReason.SelectionInside]; | ||
function isSelectionChangeReason(value) { | ||
return coreHelpers.includes(selectionChangeReasons, value); | ||
} | ||
/** | ||
@@ -187,12 +195,2 @@ * Checks that the reason passed is a split reason. This typically means that we | ||
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
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); } | ||
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; } | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
/** | ||
@@ -205,3 +203,3 @@ * Small utility method for creating a match with the reason property available. | ||
exitReason = parameter.exitReason; | ||
return _objectSpread(_objectSpread({}, match), {}, { | ||
return _objectSpread__default['default'](_objectSpread__default['default']({}, match), {}, { | ||
changeReason, | ||
@@ -302,3 +300,5 @@ exitReason | ||
supportedCharacters = suggester.supportedCharacters, | ||
matchOffset = suggester.matchOffset; // Create the regular expression to match the text against | ||
matchOffset = suggester.matchOffset, | ||
multiline = suggester.multiline, | ||
caseInsensitive = suggester.caseInsensitive; // Create the regular expression to match the text against | ||
@@ -309,3 +309,5 @@ var regexp = createRegexFromSuggester({ | ||
startOfLine, | ||
supportedCharacters | ||
supportedCharacters, | ||
multiline, | ||
caseInsensitive | ||
}); // All the text in the current node | ||
@@ -468,3 +470,3 @@ | ||
if (!updatedPrevious || updatedPrevious.query.full !== match.query.full) { | ||
if (!updatedPrevious || updatedPrevious.text.full !== match.text.full) { | ||
return createInsertReason({ | ||
@@ -688,3 +690,3 @@ prev: match, | ||
var _iterator = _createForOfIteratorHelper(suggesters), | ||
var _iterator = _createForOfIteratorHelper__default['default'](suggesters), | ||
_step; | ||
@@ -722,7 +724,4 @@ | ||
} catch (_unused2) { | ||
// This log is kept here even though it should probably be removed. It | ||
// should not happen, so if it does, please open an issue and a use case | ||
// for replication. | ||
console.error('If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened.'); | ||
} catch (_unused2) {// Captures any errors which can pop up when all the content in the editor | ||
// is deleted or an invalid position was provided. | ||
} | ||
@@ -784,6 +783,9 @@ } | ||
supportedCharacters = parameter.supportedCharacters, | ||
_parameter$flags = parameter.flags, | ||
flags = _parameter$flags === void 0 ? 'gm' : _parameter$flags, | ||
_parameter$captureCha = parameter.captureChar, | ||
captureChar = _parameter$captureCha === void 0 ? true : _parameter$captureCha; | ||
captureChar = _parameter$captureCha === void 0 ? true : _parameter$captureCha, | ||
_parameter$caseInsens = parameter.caseInsensitive, | ||
caseInsensitive = _parameter$caseInsens === void 0 ? false : _parameter$caseInsens, | ||
_parameter$multiline = parameter.multiline, | ||
multiline = _parameter$multiline === void 0 ? false : _parameter$multiline; | ||
var flags = "g".concat(multiline ? 'm' : '').concat(caseInsensitive ? 'i' : ''); | ||
var charRegex = getCharAsRegex(char).source; | ||
@@ -802,2 +804,3 @@ | ||
var DEFAULT_SUGGESTER = { | ||
appendTransaction: false, | ||
priority: 50, | ||
@@ -820,3 +823,5 @@ ignoredTag: 'span', | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: false | ||
emptySelectionsOnly: false, | ||
caseInsensitive: false, | ||
multiline: false | ||
}; | ||
@@ -828,14 +833,5 @@ /** | ||
function getSuggesterWithDefaults(suggester) { | ||
return _objectSpread(_objectSpread({}, DEFAULT_SUGGESTER), suggester); | ||
return _objectSpread__default['default'](_objectSpread__default['default']({}, DEFAULT_SUGGESTER), suggester); | ||
} | ||
function _createForOfIteratorHelper$1(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(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$1(o, minLen); } | ||
function _arrayLikeToArray$1(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; } | ||
function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
/** | ||
@@ -861,2 +857,4 @@ * The `prosemirror-suggest` state which manages the list of suggesters. | ||
var _lastChangeFromAppend = /*#__PURE__*/new WeakMap(); | ||
class SuggestState { | ||
@@ -918,3 +916,3 @@ /** | ||
constructor(suggesters) { | ||
constructor(_suggesters2) { | ||
_docChanged.set(this, { | ||
@@ -960,2 +958,7 @@ writable: true, | ||
_lastChangeFromAppend.set(this, { | ||
writable: true, | ||
value: false | ||
}); | ||
_defineProperty__default['default'](this, "setMarkRemoved", () => { | ||
@@ -965,2 +968,20 @@ _classPrivateFieldSet__default['default'](this, _removed, true); | ||
_defineProperty__default['default'](this, "findNextTextSelection", selection => { | ||
var doc = selection.$from.doc; // Make sure the position doesn't exceed the bounds of the document. | ||
var pos = Math.min(doc.nodeSize - 2, selection.to + 1); | ||
var $pos = doc.resolve(pos); // Get the position furthest along in the editor to pass back to suggesters | ||
// which have the handler. | ||
var nextSelection = prosemirrorState.Selection.findFrom($pos, 1, true); // Ignore non-text selections and null / undefined values. This is needed | ||
// for TS mainly, since the `true` in the `Selection.findFrom` method means | ||
// only `TextSelection` instances will be returned. | ||
if (!isTextSelection(nextSelection)) { | ||
return; | ||
} | ||
return nextSelection; | ||
}); | ||
_defineProperty__default['default'](this, "ignoreNextExit", () => { | ||
@@ -987,3 +1008,3 @@ _classPrivateFieldSet__default['default'](this, _ignoreNextExit, true); | ||
} : {}; | ||
var decoration = prosemirrorView.Decoration.inline(from, to, _objectSpread$1({ | ||
var decoration = prosemirrorView.Decoration.inline(from, to, _objectSpread__default['default']({ | ||
nodeName: suggester.ignoredTag | ||
@@ -1037,5 +1058,15 @@ }, attributes), { | ||
_defineProperty__default['default'](this, "findMatchAtPosition", ($pos, name) => { | ||
var suggesters = name ? _classPrivateFieldGet__default['default'](this, _suggesters).filter(suggester => suggester.name === name) : _classPrivateFieldGet__default['default'](this, _suggesters); | ||
return findFromSuggesters({ | ||
suggesters, | ||
$pos, | ||
docChanged: false, | ||
selectionEmpty: true | ||
}); | ||
}); | ||
var mapper = createSuggesterMapper(); | ||
_classPrivateFieldSet__default['default'](this, _suggesters, suggesters.map(mapper)); | ||
_classPrivateFieldSet__default['default'](this, _suggesters, _suggesters2.map(mapper)); | ||
@@ -1067,3 +1098,3 @@ _classPrivateFieldSet__default['default'](this, _suggesters, coreHelpers.sort(_classPrivateFieldGet__default['default'](this, _suggesters), (a, b) => b.priority - a.priority)); | ||
char = _match$suggester.char; | ||
return _objectSpread$1({ | ||
return _objectSpread__default['default']({ | ||
view: this.view, | ||
@@ -1092,17 +1123,20 @@ addIgnored: this.addIgnored, | ||
} | ||
/** | ||
* Find the next text selection from the current selection. | ||
*/ | ||
updateWithNextSelection() { | ||
var _this$view$state = this.view.state, | ||
doc = _this$view$state.doc, | ||
selection = _this$view$state.selection; // Make sure the position doesn't exceed the bounds of the document. | ||
var pos = Math.min(doc.nodeSize - 2, selection.to + 1); | ||
var $pos = doc.resolve(pos); // Get the position furthest along in the editor to pass back to suggesters | ||
/** | ||
* Update all the suggesters with the next valid selection. This is called | ||
* within the `appendTransaction` ProseMirror method before any of the change | ||
* handlers are called. | ||
* | ||
* @internal | ||
*/ | ||
updateWithNextSelection(tr) { | ||
// Get the position furthest along in the editor to pass back to suggesters | ||
// which have the handler. | ||
var nextSelection = this.findNextTextSelection(tr.selection); | ||
var nextSelection = prosemirrorState.Selection.findFrom($pos, 1, true); // Ignore non-text selections and null / undefined values. This is needed | ||
// for TS mainly, since the `true` in the `Selection.findFrom` method means | ||
// only `TextSelection` instances will be returned. | ||
if (!isTextSelection(nextSelection)) { | ||
if (!nextSelection) { | ||
return; | ||
@@ -1112,3 +1146,3 @@ } // Update every suggester with a method attached. | ||
var _iterator = _createForOfIteratorHelper$1(_classPrivateFieldGet__default['default'](this, _suggesters)), | ||
var _iterator = _createForOfIteratorHelper__default['default'](_classPrivateFieldGet__default['default'](this, _suggesters)), | ||
_step; | ||
@@ -1118,6 +1152,11 @@ | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var _suggester$checkNextV; | ||
var _classPrivateFieldGet2, _classPrivateFieldGet3, _suggester$checkNextV; | ||
var suggester = _step.value; | ||
(_suggester$checkNextV = suggester.checkNextValidSelection) === null || _suggester$checkNextV === void 0 ? void 0 : _suggester$checkNextV.call(suggester, nextSelection.$from, this.view.state); | ||
var change = (_classPrivateFieldGet2 = _classPrivateFieldGet__default['default'](this, _handlerMatches).change) === null || _classPrivateFieldGet2 === void 0 ? void 0 : _classPrivateFieldGet2.suggester.name; | ||
var exit = (_classPrivateFieldGet3 = _classPrivateFieldGet__default['default'](this, _handlerMatches).exit) === null || _classPrivateFieldGet3 === void 0 ? void 0 : _classPrivateFieldGet3.suggester.name; | ||
(_suggester$checkNextV = suggester.checkNextValidSelection) === null || _suggester$checkNextV === void 0 ? void 0 : _suggester$checkNextV.call(suggester, nextSelection.$from, tr, { | ||
change, | ||
exit | ||
}); | ||
} | ||
@@ -1131,19 +1170,24 @@ } catch (err) { | ||
/** | ||
* Manages the view updates. | ||
* Call the `onChange` handlers. | ||
* | ||
* @internal | ||
*/ | ||
onViewUpdate() { | ||
var _classPrivateFieldGet2 = _classPrivateFieldGet__default['default'](this, _handlerMatches), | ||
change = _classPrivateFieldGet2.change, | ||
exit = _classPrivateFieldGet2.exit; | ||
changeHandler(tr, appendTransaction) { | ||
var _classPrivateFieldGet4 = _classPrivateFieldGet__default['default'](this, _handlerMatches), | ||
change = _classPrivateFieldGet4.change, | ||
exit = _classPrivateFieldGet4.exit; | ||
var match = this.match; // Notify all suggesters of the next valid text selection. | ||
var match = this.match; // Cancel update when a suggester isn't active | ||
this.updateWithNextSelection(); // Cancel update when a suggester isn't active | ||
if (!change && !exit || !isValidMatch(match)) { | ||
// TODO - when not active do a look forward to check the next position and | ||
// call the handler with the position. This will be used to | ||
return; | ||
} | ||
var shouldRunExit = appendTransaction === (exit === null || exit === void 0 ? void 0 : exit.suggester.appendTransaction) && this.shouldRunExit(); | ||
var shouldRunChange = appendTransaction === (change === null || change === void 0 ? void 0 : change.suggester.appendTransaction); | ||
if (!shouldRunExit && !shouldRunChange) { | ||
return; | ||
} // When a jump happens run the action that involves the position that occurs | ||
@@ -1158,4 +1202,4 @@ // later in the document. This is so that changes don't affect previous | ||
})) { | ||
var exitParameters = this.createParameter(exit); | ||
var changeParameters = this.createParameter(change); // Whether the jump was forwards or backwards. A forwards jump means that | ||
var exitDetails = this.createParameter(exit); | ||
var changeDetails = this.createParameter(change); // Whether the jump was forwards or backwards. A forwards jump means that | ||
// the user was within a suggester nearer the beginning of the document, | ||
@@ -1169,10 +1213,12 @@ // before jumping forward to a point later on in the document. | ||
// change so call the handler before the change handler. | ||
this.shouldRunExit() && exit.suggester.onChange(exitParameters); | ||
change.suggester.onChange(changeParameters); | ||
shouldRunExit && exit.suggester.onChange(exitDetails, tr); | ||
shouldRunChange && change.suggester.onChange(changeDetails, tr); | ||
} else { | ||
this.shouldRunExit() && exit.suggester.onChange(exitParameters); | ||
change.suggester.onChange(changeParameters); | ||
shouldRunExit && exit.suggester.onChange(exitDetails, tr); | ||
shouldRunChange && change.suggester.onChange(changeDetails, tr); | ||
} | ||
_classPrivateFieldSet__default['default'](this, _removed, false); | ||
if (shouldRunExit) { | ||
_classPrivateFieldSet__default['default'](this, _removed, false); | ||
} | ||
@@ -1182,8 +1228,8 @@ return; | ||
if (change) { | ||
change.suggester.onChange(this.createParameter(change)); | ||
if (change && shouldRunChange) { | ||
change.suggester.onChange(this.createParameter(change), tr); | ||
} | ||
if (exit && this.shouldRunExit()) { | ||
exit.suggester.onChange(this.createParameter(exit)); | ||
if (exit && shouldRunExit) { | ||
exit.suggester.onChange(this.createParameter(exit), tr); | ||
@@ -1198,2 +1244,4 @@ _classPrivateFieldSet__default['default'](this, _removed, false); | ||
} | ||
return; | ||
} | ||
@@ -1274,2 +1322,4 @@ /** | ||
_classPrivateFieldSet__default['default'](this, _removed, false); | ||
_classPrivateFieldSet__default['default'](this, _lastChangeFromAppend, false); | ||
} | ||
@@ -1308,6 +1358,10 @@ /** | ||
/** | ||
* Add a new suggest or replace it if it already exists. | ||
* A helper method to check is a match exists for the provided suggester name | ||
* at the provided position. | ||
*/ | ||
/** | ||
* Add a new suggest or replace it if it already exists. | ||
*/ | ||
addSuggester(suggester) { | ||
@@ -1341,13 +1395,3 @@ var previous = _classPrivateFieldGet__default['default'](this, _suggesters).find(item => item.name === suggester.name); | ||
} | ||
/** | ||
* Used to handle the view property of the plugin spec. | ||
*/ | ||
viewHandler() { | ||
return { | ||
update: this.onViewUpdate.bind(this) | ||
}; | ||
} | ||
toJSON() { | ||
@@ -1364,7 +1408,13 @@ return this.match; | ||
apply(parameter) { | ||
if (_classPrivateFieldGet__default['default'](this, _lastChangeFromAppend)) { | ||
_classPrivateFieldSet__default['default'](this, _lastChangeFromAppend, false); | ||
return this; | ||
} | ||
var tr = parameter.tr, | ||
state = parameter.state; | ||
var _classPrivateFieldGet3 = _classPrivateFieldGet__default['default'](this, _handlerMatches), | ||
exit = _classPrivateFieldGet3.exit; | ||
var _classPrivateFieldGet5 = _classPrivateFieldGet__default['default'](this, _handlerMatches), | ||
exit = _classPrivateFieldGet5.exit; | ||
@@ -1424,3 +1474,3 @@ var transactionHasChanged = tr.docChanged || tr.selectionSet; | ||
nodeName: suggestTag, | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
class: name ? "".concat(suggestClassName, " suggest-").concat(name) : suggestClassName | ||
}, { | ||
@@ -1430,3 +1480,13 @@ name | ||
} | ||
/** | ||
* Set that the last change was caused by an appended transaction. | ||
* | ||
* @internal | ||
*/ | ||
setLastChangeFromAppend() { | ||
_classPrivateFieldSet__default['default'](this, _lastChangeFromAppend, true); | ||
} | ||
} | ||
@@ -1446,3 +1506,3 @@ | ||
var suggesterWithDefaults = _objectSpread$1(_objectSpread$1({}, DEFAULT_SUGGESTER), suggester); | ||
var suggesterWithDefaults = _objectSpread__default['default'](_objectSpread__default['default']({}, DEFAULT_SUGGESTER), suggester); | ||
@@ -1513,3 +1573,10 @@ names.add(suggester.name); | ||
view: _view => { | ||
return pluginState.init(_view).viewHandler(); | ||
// Initialize the state with the required view before it is used. | ||
pluginState.init(_view); | ||
return { | ||
update: view => { | ||
// console.log('VIEW_UPDATE', { content: view.state.doc.textContent }); | ||
return pluginState.changeHandler(view.state.tr, false); | ||
} | ||
}; | ||
}, | ||
@@ -1523,2 +1590,3 @@ state: { | ||
apply: (tr, _pluginState, _oldState, state) => { | ||
// console.log('APPLY', { content: tr.doc.textContent }); | ||
return pluginState.apply({ | ||
@@ -1530,2 +1598,19 @@ tr, | ||
}, | ||
/** Append a transaction via the onChange handlers */ | ||
appendTransaction: (_, __, state) => { | ||
var tr = state.tr; // console.log('APPEND_TRANSACTION', { content: tr.doc.textContent }); | ||
// Run the transaction updater for the next selection. | ||
pluginState.updateWithNextSelection(tr); // Run the change handler. | ||
pluginState.changeHandler(tr, true); // Check if the transaction has been amended in any way. | ||
if (tr.docChanged || tr.steps.length > 0 || tr.selectionSet || tr.storedMarksSet) { | ||
pluginState.setLastChangeFromAppend(); | ||
return tr; | ||
} | ||
return null; | ||
}, | ||
props: { | ||
@@ -1544,2 +1629,3 @@ // Sets up a decoration (styling options) on the currently active | ||
exports.createRegexFromSuggester = createRegexFromSuggester; | ||
exports.findFromSuggesters = findFromSuggesters; | ||
exports.getSuggestPluginState = getSuggestPluginState; | ||
@@ -1557,2 +1643,3 @@ exports.getSuggesterWithDefaults = getSuggesterWithDefaults; | ||
exports.isRemovedReason = isRemovedReason; | ||
exports.isSelectionChangeReason = isSelectionChangeReason; | ||
exports.isSelectionExitReason = isSelectionExitReason; | ||
@@ -1559,0 +1646,0 @@ exports.isSplitReason = isSplitReason; |
import { TextSelection, Selection, PluginKey, Plugin } from 'prosemirror-state'; | ||
import _createForOfIteratorHelper from '@babel/runtime/helpers/esm/createForOfIteratorHelper'; | ||
import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2'; | ||
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty'; | ||
@@ -6,3 +8,3 @@ import _classPrivateFieldSet from '@babel/runtime/helpers/esm/classPrivateFieldSet'; | ||
import { DecorationSet, Decoration } from 'prosemirror-view'; | ||
import { isString, includes, isObject, range, isRegExp, object, findMatches, isEmptyArray, bool, sort, isFunction } from '@remirror/core-helpers'; | ||
import { isString, includes, isObject, range, isRegExp, findMatches, isEmptyArray, object, bool, sort, isFunction } from '@remirror/core-helpers'; | ||
import escapeStringRegex from 'escape-string-regexp'; | ||
@@ -25,2 +27,8 @@ import { NULL_CHARACTER } from '@remirror/core-constants'; | ||
* handlers are fired. | ||
* | ||
* @param $pos - the next valid position that supports text selections. | ||
* @param tr - the transaction that can be mutated when `appendTransaction` is | ||
* set to true. | ||
* @param matches - the possibly undefined exit and change matcher names. These | ||
* can be used to check if the name matches the current suggester. | ||
*/ | ||
@@ -81,3 +89,3 @@ | ||
function isChange(compare) { | ||
return !!(compare.prev && compare.next && compare.prev.query.full !== compare.next.query.full); | ||
return !!(compare.prev && compare.next && compare.prev.text.full !== compare.next.text.full); | ||
} | ||
@@ -136,2 +144,6 @@ /** | ||
} | ||
var selectionChangeReasons = [ChangeReason.JumpBackward, ChangeReason.JumpForward, ChangeReason.Move, ChangeReason.SelectionInside]; | ||
function isSelectionChangeReason(value) { | ||
return includes(selectionChangeReasons, value); | ||
} | ||
/** | ||
@@ -198,12 +210,2 @@ * Checks that the reason passed is a split reason. This typically means that we | ||
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
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); } | ||
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; } | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
/** | ||
@@ -312,3 +314,5 @@ * Small utility method for creating a match with the reason property available. | ||
supportedCharacters = suggester.supportedCharacters, | ||
matchOffset = suggester.matchOffset; // Create the regular expression to match the text against | ||
matchOffset = suggester.matchOffset, | ||
multiline = suggester.multiline, | ||
caseInsensitive = suggester.caseInsensitive; // Create the regular expression to match the text against | ||
@@ -319,3 +323,5 @@ var regexp = createRegexFromSuggester({ | ||
startOfLine, | ||
supportedCharacters | ||
supportedCharacters, | ||
multiline, | ||
caseInsensitive | ||
}); // All the text in the current node | ||
@@ -478,3 +484,3 @@ | ||
if (!updatedPrevious || updatedPrevious.query.full !== match.query.full) { | ||
if (!updatedPrevious || updatedPrevious.text.full !== match.text.full) { | ||
return createInsertReason({ | ||
@@ -731,7 +737,4 @@ prev: match, | ||
} catch (_unused2) { | ||
// This log is kept here even though it should probably be removed. It | ||
// should not happen, so if it does, please open an issue and a use case | ||
// for replication. | ||
console.error('If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened.'); | ||
} catch (_unused2) {// Captures any errors which can pop up when all the content in the editor | ||
// is deleted or an invalid position was provided. | ||
} | ||
@@ -793,6 +796,9 @@ } | ||
supportedCharacters = parameter.supportedCharacters, | ||
_parameter$flags = parameter.flags, | ||
flags = _parameter$flags === void 0 ? 'gm' : _parameter$flags, | ||
_parameter$captureCha = parameter.captureChar, | ||
captureChar = _parameter$captureCha === void 0 ? true : _parameter$captureCha; | ||
captureChar = _parameter$captureCha === void 0 ? true : _parameter$captureCha, | ||
_parameter$caseInsens = parameter.caseInsensitive, | ||
caseInsensitive = _parameter$caseInsens === void 0 ? false : _parameter$caseInsens, | ||
_parameter$multiline = parameter.multiline, | ||
multiline = _parameter$multiline === void 0 ? false : _parameter$multiline; | ||
var flags = "g".concat(multiline ? 'm' : '').concat(caseInsensitive ? 'i' : ''); | ||
var charRegex = getCharAsRegex(char).source; | ||
@@ -811,2 +817,3 @@ | ||
var DEFAULT_SUGGESTER = { | ||
appendTransaction: false, | ||
priority: 50, | ||
@@ -829,3 +836,5 @@ ignoredTag: 'span', | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: false | ||
emptySelectionsOnly: false, | ||
caseInsensitive: false, | ||
multiline: false | ||
}; | ||
@@ -840,11 +849,2 @@ /** | ||
function _createForOfIteratorHelper$1(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(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$1(o, minLen); } | ||
function _arrayLikeToArray$1(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; } | ||
function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
/** | ||
@@ -870,2 +870,4 @@ * The `prosemirror-suggest` state which manages the list of suggesters. | ||
var _lastChangeFromAppend = /*#__PURE__*/new WeakMap(); | ||
class SuggestState { | ||
@@ -927,3 +929,3 @@ /** | ||
constructor(suggesters) { | ||
constructor(_suggesters2) { | ||
_docChanged.set(this, { | ||
@@ -969,2 +971,7 @@ writable: true, | ||
_lastChangeFromAppend.set(this, { | ||
writable: true, | ||
value: false | ||
}); | ||
_defineProperty(this, "setMarkRemoved", () => { | ||
@@ -974,2 +981,20 @@ _classPrivateFieldSet(this, _removed, true); | ||
_defineProperty(this, "findNextTextSelection", selection => { | ||
var doc = selection.$from.doc; // Make sure the position doesn't exceed the bounds of the document. | ||
var pos = Math.min(doc.nodeSize - 2, selection.to + 1); | ||
var $pos = doc.resolve(pos); // Get the position furthest along in the editor to pass back to suggesters | ||
// which have the handler. | ||
var nextSelection = Selection.findFrom($pos, 1, true); // Ignore non-text selections and null / undefined values. This is needed | ||
// for TS mainly, since the `true` in the `Selection.findFrom` method means | ||
// only `TextSelection` instances will be returned. | ||
if (!isTextSelection(nextSelection)) { | ||
return; | ||
} | ||
return nextSelection; | ||
}); | ||
_defineProperty(this, "ignoreNextExit", () => { | ||
@@ -996,3 +1021,3 @@ _classPrivateFieldSet(this, _ignoreNextExit, true); | ||
} : {}; | ||
var decoration = Decoration.inline(from, to, _objectSpread$1({ | ||
var decoration = Decoration.inline(from, to, _objectSpread({ | ||
nodeName: suggester.ignoredTag | ||
@@ -1046,5 +1071,15 @@ }, attributes), { | ||
_defineProperty(this, "findMatchAtPosition", ($pos, name) => { | ||
var suggesters = name ? _classPrivateFieldGet(this, _suggesters).filter(suggester => suggester.name === name) : _classPrivateFieldGet(this, _suggesters); | ||
return findFromSuggesters({ | ||
suggesters, | ||
$pos, | ||
docChanged: false, | ||
selectionEmpty: true | ||
}); | ||
}); | ||
var mapper = createSuggesterMapper(); | ||
_classPrivateFieldSet(this, _suggesters, suggesters.map(mapper)); | ||
_classPrivateFieldSet(this, _suggesters, _suggesters2.map(mapper)); | ||
@@ -1076,3 +1111,3 @@ _classPrivateFieldSet(this, _suggesters, sort(_classPrivateFieldGet(this, _suggesters), (a, b) => b.priority - a.priority)); | ||
char = _match$suggester.char; | ||
return _objectSpread$1({ | ||
return _objectSpread({ | ||
view: this.view, | ||
@@ -1101,17 +1136,20 @@ addIgnored: this.addIgnored, | ||
} | ||
/** | ||
* Find the next text selection from the current selection. | ||
*/ | ||
updateWithNextSelection() { | ||
var _this$view$state = this.view.state, | ||
doc = _this$view$state.doc, | ||
selection = _this$view$state.selection; // Make sure the position doesn't exceed the bounds of the document. | ||
var pos = Math.min(doc.nodeSize - 2, selection.to + 1); | ||
var $pos = doc.resolve(pos); // Get the position furthest along in the editor to pass back to suggesters | ||
/** | ||
* Update all the suggesters with the next valid selection. This is called | ||
* within the `appendTransaction` ProseMirror method before any of the change | ||
* handlers are called. | ||
* | ||
* @internal | ||
*/ | ||
updateWithNextSelection(tr) { | ||
// Get the position furthest along in the editor to pass back to suggesters | ||
// which have the handler. | ||
var nextSelection = this.findNextTextSelection(tr.selection); | ||
var nextSelection = Selection.findFrom($pos, 1, true); // Ignore non-text selections and null / undefined values. This is needed | ||
// for TS mainly, since the `true` in the `Selection.findFrom` method means | ||
// only `TextSelection` instances will be returned. | ||
if (!isTextSelection(nextSelection)) { | ||
if (!nextSelection) { | ||
return; | ||
@@ -1121,3 +1159,3 @@ } // Update every suggester with a method attached. | ||
var _iterator = _createForOfIteratorHelper$1(_classPrivateFieldGet(this, _suggesters)), | ||
var _iterator = _createForOfIteratorHelper(_classPrivateFieldGet(this, _suggesters)), | ||
_step; | ||
@@ -1127,6 +1165,11 @@ | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var _suggester$checkNextV; | ||
var _classPrivateFieldGet2, _classPrivateFieldGet3, _suggester$checkNextV; | ||
var suggester = _step.value; | ||
(_suggester$checkNextV = suggester.checkNextValidSelection) === null || _suggester$checkNextV === void 0 ? void 0 : _suggester$checkNextV.call(suggester, nextSelection.$from, this.view.state); | ||
var change = (_classPrivateFieldGet2 = _classPrivateFieldGet(this, _handlerMatches).change) === null || _classPrivateFieldGet2 === void 0 ? void 0 : _classPrivateFieldGet2.suggester.name; | ||
var exit = (_classPrivateFieldGet3 = _classPrivateFieldGet(this, _handlerMatches).exit) === null || _classPrivateFieldGet3 === void 0 ? void 0 : _classPrivateFieldGet3.suggester.name; | ||
(_suggester$checkNextV = suggester.checkNextValidSelection) === null || _suggester$checkNextV === void 0 ? void 0 : _suggester$checkNextV.call(suggester, nextSelection.$from, tr, { | ||
change, | ||
exit | ||
}); | ||
} | ||
@@ -1140,19 +1183,24 @@ } catch (err) { | ||
/** | ||
* Manages the view updates. | ||
* Call the `onChange` handlers. | ||
* | ||
* @internal | ||
*/ | ||
onViewUpdate() { | ||
var _classPrivateFieldGet2 = _classPrivateFieldGet(this, _handlerMatches), | ||
change = _classPrivateFieldGet2.change, | ||
exit = _classPrivateFieldGet2.exit; | ||
changeHandler(tr, appendTransaction) { | ||
var _classPrivateFieldGet4 = _classPrivateFieldGet(this, _handlerMatches), | ||
change = _classPrivateFieldGet4.change, | ||
exit = _classPrivateFieldGet4.exit; | ||
var match = this.match; // Notify all suggesters of the next valid text selection. | ||
var match = this.match; // Cancel update when a suggester isn't active | ||
this.updateWithNextSelection(); // Cancel update when a suggester isn't active | ||
if (!change && !exit || !isValidMatch(match)) { | ||
// TODO - when not active do a look forward to check the next position and | ||
// call the handler with the position. This will be used to | ||
return; | ||
} | ||
var shouldRunExit = appendTransaction === (exit === null || exit === void 0 ? void 0 : exit.suggester.appendTransaction) && this.shouldRunExit(); | ||
var shouldRunChange = appendTransaction === (change === null || change === void 0 ? void 0 : change.suggester.appendTransaction); | ||
if (!shouldRunExit && !shouldRunChange) { | ||
return; | ||
} // When a jump happens run the action that involves the position that occurs | ||
@@ -1167,4 +1215,4 @@ // later in the document. This is so that changes don't affect previous | ||
})) { | ||
var exitParameters = this.createParameter(exit); | ||
var changeParameters = this.createParameter(change); // Whether the jump was forwards or backwards. A forwards jump means that | ||
var exitDetails = this.createParameter(exit); | ||
var changeDetails = this.createParameter(change); // Whether the jump was forwards or backwards. A forwards jump means that | ||
// the user was within a suggester nearer the beginning of the document, | ||
@@ -1178,10 +1226,12 @@ // before jumping forward to a point later on in the document. | ||
// change so call the handler before the change handler. | ||
this.shouldRunExit() && exit.suggester.onChange(exitParameters); | ||
change.suggester.onChange(changeParameters); | ||
shouldRunExit && exit.suggester.onChange(exitDetails, tr); | ||
shouldRunChange && change.suggester.onChange(changeDetails, tr); | ||
} else { | ||
this.shouldRunExit() && exit.suggester.onChange(exitParameters); | ||
change.suggester.onChange(changeParameters); | ||
shouldRunExit && exit.suggester.onChange(exitDetails, tr); | ||
shouldRunChange && change.suggester.onChange(changeDetails, tr); | ||
} | ||
_classPrivateFieldSet(this, _removed, false); | ||
if (shouldRunExit) { | ||
_classPrivateFieldSet(this, _removed, false); | ||
} | ||
@@ -1191,8 +1241,8 @@ return; | ||
if (change) { | ||
change.suggester.onChange(this.createParameter(change)); | ||
if (change && shouldRunChange) { | ||
change.suggester.onChange(this.createParameter(change), tr); | ||
} | ||
if (exit && this.shouldRunExit()) { | ||
exit.suggester.onChange(this.createParameter(exit)); | ||
if (exit && shouldRunExit) { | ||
exit.suggester.onChange(this.createParameter(exit), tr); | ||
@@ -1207,2 +1257,4 @@ _classPrivateFieldSet(this, _removed, false); | ||
} | ||
return; | ||
} | ||
@@ -1283,2 +1335,4 @@ /** | ||
_classPrivateFieldSet(this, _removed, false); | ||
_classPrivateFieldSet(this, _lastChangeFromAppend, false); | ||
} | ||
@@ -1317,6 +1371,10 @@ /** | ||
/** | ||
* Add a new suggest or replace it if it already exists. | ||
* A helper method to check is a match exists for the provided suggester name | ||
* at the provided position. | ||
*/ | ||
/** | ||
* Add a new suggest or replace it if it already exists. | ||
*/ | ||
addSuggester(suggester) { | ||
@@ -1350,13 +1408,3 @@ var previous = _classPrivateFieldGet(this, _suggesters).find(item => item.name === suggester.name); | ||
} | ||
/** | ||
* Used to handle the view property of the plugin spec. | ||
*/ | ||
viewHandler() { | ||
return { | ||
update: this.onViewUpdate.bind(this) | ||
}; | ||
} | ||
toJSON() { | ||
@@ -1373,7 +1421,13 @@ return this.match; | ||
apply(parameter) { | ||
if (_classPrivateFieldGet(this, _lastChangeFromAppend)) { | ||
_classPrivateFieldSet(this, _lastChangeFromAppend, false); | ||
return this; | ||
} | ||
var tr = parameter.tr, | ||
state = parameter.state; | ||
var _classPrivateFieldGet3 = _classPrivateFieldGet(this, _handlerMatches), | ||
exit = _classPrivateFieldGet3.exit; | ||
var _classPrivateFieldGet5 = _classPrivateFieldGet(this, _handlerMatches), | ||
exit = _classPrivateFieldGet5.exit; | ||
@@ -1433,3 +1487,3 @@ var transactionHasChanged = tr.docChanged || tr.selectionSet; | ||
nodeName: suggestTag, | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
class: name ? "".concat(suggestClassName, " suggest-").concat(name) : suggestClassName | ||
}, { | ||
@@ -1439,3 +1493,13 @@ name | ||
} | ||
/** | ||
* Set that the last change was caused by an appended transaction. | ||
* | ||
* @internal | ||
*/ | ||
setLastChangeFromAppend() { | ||
_classPrivateFieldSet(this, _lastChangeFromAppend, true); | ||
} | ||
} | ||
@@ -1455,3 +1519,3 @@ | ||
var suggesterWithDefaults = _objectSpread$1(_objectSpread$1({}, DEFAULT_SUGGESTER), suggester); | ||
var suggesterWithDefaults = _objectSpread(_objectSpread({}, DEFAULT_SUGGESTER), suggester); | ||
@@ -1522,3 +1586,10 @@ names.add(suggester.name); | ||
view: _view => { | ||
return pluginState.init(_view).viewHandler(); | ||
// Initialize the state with the required view before it is used. | ||
pluginState.init(_view); | ||
return { | ||
update: view => { | ||
// console.log('VIEW_UPDATE', { content: view.state.doc.textContent }); | ||
return pluginState.changeHandler(view.state.tr, false); | ||
} | ||
}; | ||
}, | ||
@@ -1532,2 +1603,3 @@ state: { | ||
apply: (tr, _pluginState, _oldState, state) => { | ||
// console.log('APPLY', { content: tr.doc.textContent }); | ||
return pluginState.apply({ | ||
@@ -1539,2 +1611,19 @@ tr, | ||
}, | ||
/** Append a transaction via the onChange handlers */ | ||
appendTransaction: (_, __, state) => { | ||
var tr = state.tr; // console.log('APPEND_TRANSACTION', { content: tr.doc.textContent }); | ||
// Run the transaction updater for the next selection. | ||
pluginState.updateWithNextSelection(tr); // Run the change handler. | ||
pluginState.changeHandler(tr, true); // Check if the transaction has been amended in any way. | ||
if (tr.docChanged || tr.steps.length > 0 || tr.selectionSet || tr.storedMarksSet) { | ||
pluginState.setLastChangeFromAppend(); | ||
return tr; | ||
} | ||
return null; | ||
}, | ||
props: { | ||
@@ -1550,2 +1639,2 @@ // Sets up a decoration (styling options) on the currently active | ||
export { ChangeReason, DEFAULT_SUGGESTER, ExitReason, addSuggester, createRegexFromSuggester, getSuggestPluginState, getSuggesterWithDefaults, isChange, isChangeReason, isEntry, isExit, isExitReason, isInvalidSplitReason, isJump, isJumpReason, isMove, isRemovedReason, isSelectionExitReason, isSplitReason, isValidMatch, markActiveInRange, positionHasMarks, rangeHasMarks, removeSuggester, selectionOutsideMatch, suggest }; | ||
export { ChangeReason, DEFAULT_SUGGESTER, ExitReason, addSuggester, createRegexFromSuggester, findFromSuggesters, getSuggestPluginState, getSuggesterWithDefaults, isChange, isChangeReason, isEntry, isExit, isExitReason, isInvalidSplitReason, isJump, isJumpReason, isMove, isRemovedReason, isSelectionChangeReason, isSelectionExitReason, isSplitReason, isValidMatch, markActiveInRange, positionHasMarks, rangeHasMarks, removeSuggester, selectionOutsideMatch, suggest }; |
@@ -6,2 +6,4 @@ 'use strict'; | ||
var prosemirrorState = require('prosemirror-state'); | ||
var _createForOfIteratorHelper = require('@babel/runtime/helpers/createForOfIteratorHelper'); | ||
var _objectSpread = require('@babel/runtime/helpers/objectSpread2'); | ||
var _defineProperty = require('@babel/runtime/helpers/defineProperty'); | ||
@@ -17,2 +19,4 @@ var _classPrivateFieldSet = require('@babel/runtime/helpers/classPrivateFieldSet'); | ||
var _createForOfIteratorHelper__default = /*#__PURE__*/_interopDefault(_createForOfIteratorHelper); | ||
var _objectSpread__default = /*#__PURE__*/_interopDefault(_objectSpread); | ||
var _defineProperty__default = /*#__PURE__*/_interopDefault(_defineProperty); | ||
@@ -70,3 +74,3 @@ var _classPrivateFieldSet__default = /*#__PURE__*/_interopDefault(_classPrivateFieldSet); | ||
function isChange(compare) { | ||
return !!(compare.prev && compare.next && compare.prev.query.full !== compare.next.query.full); | ||
return !!(compare.prev && compare.next && compare.prev.text.full !== compare.next.text.full); | ||
} | ||
@@ -125,2 +129,6 @@ /** | ||
} | ||
var selectionChangeReasons = [exports.ChangeReason.JumpBackward, exports.ChangeReason.JumpForward, exports.ChangeReason.Move, exports.ChangeReason.SelectionInside]; | ||
function isSelectionChangeReason(value) { | ||
return coreHelpers.includes(selectionChangeReasons, value); | ||
} | ||
/** | ||
@@ -187,12 +195,2 @@ * Checks that the reason passed is a split reason. This typically means that we | ||
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
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); } | ||
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; } | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
/** | ||
@@ -205,3 +203,3 @@ * Small utility method for creating a match with the reason property available. | ||
exitReason = parameter.exitReason; | ||
return _objectSpread(_objectSpread({}, match), {}, { | ||
return _objectSpread__default['default'](_objectSpread__default['default']({}, match), {}, { | ||
changeReason, | ||
@@ -302,3 +300,5 @@ exitReason | ||
supportedCharacters = suggester.supportedCharacters, | ||
matchOffset = suggester.matchOffset; // Create the regular expression to match the text against | ||
matchOffset = suggester.matchOffset, | ||
multiline = suggester.multiline, | ||
caseInsensitive = suggester.caseInsensitive; // Create the regular expression to match the text against | ||
@@ -309,3 +309,5 @@ var regexp = createRegexFromSuggester({ | ||
startOfLine, | ||
supportedCharacters | ||
supportedCharacters, | ||
multiline, | ||
caseInsensitive | ||
}); // All the text in the current node | ||
@@ -468,3 +470,3 @@ | ||
if (!updatedPrevious || updatedPrevious.query.full !== match.query.full) { | ||
if (!updatedPrevious || updatedPrevious.text.full !== match.text.full) { | ||
return createInsertReason({ | ||
@@ -688,3 +690,3 @@ prev: match, | ||
var _iterator = _createForOfIteratorHelper(suggesters), | ||
var _iterator = _createForOfIteratorHelper__default['default'](suggesters), | ||
_step; | ||
@@ -722,7 +724,4 @@ | ||
} catch (_unused2) { | ||
// This log is kept here even though it should probably be removed. It | ||
// should not happen, so if it does, please open an issue and a use case | ||
// for replication. | ||
console.error('If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened.'); | ||
} catch (_unused2) {// Captures any errors which can pop up when all the content in the editor | ||
// is deleted or an invalid position was provided. | ||
} | ||
@@ -784,6 +783,9 @@ } | ||
supportedCharacters = parameter.supportedCharacters, | ||
_parameter$flags = parameter.flags, | ||
flags = _parameter$flags === void 0 ? 'gm' : _parameter$flags, | ||
_parameter$captureCha = parameter.captureChar, | ||
captureChar = _parameter$captureCha === void 0 ? true : _parameter$captureCha; | ||
captureChar = _parameter$captureCha === void 0 ? true : _parameter$captureCha, | ||
_parameter$caseInsens = parameter.caseInsensitive, | ||
caseInsensitive = _parameter$caseInsens === void 0 ? false : _parameter$caseInsens, | ||
_parameter$multiline = parameter.multiline, | ||
multiline = _parameter$multiline === void 0 ? false : _parameter$multiline; | ||
var flags = "g".concat(multiline ? 'm' : '').concat(caseInsensitive ? 'i' : ''); | ||
var charRegex = getCharAsRegex(char).source; | ||
@@ -802,2 +804,3 @@ | ||
var DEFAULT_SUGGESTER = { | ||
appendTransaction: false, | ||
priority: 50, | ||
@@ -820,3 +823,5 @@ ignoredTag: 'span', | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: false | ||
emptySelectionsOnly: false, | ||
caseInsensitive: false, | ||
multiline: false | ||
}; | ||
@@ -828,14 +833,5 @@ /** | ||
function getSuggesterWithDefaults(suggester) { | ||
return _objectSpread(_objectSpread({}, DEFAULT_SUGGESTER), suggester); | ||
return _objectSpread__default['default'](_objectSpread__default['default']({}, DEFAULT_SUGGESTER), suggester); | ||
} | ||
function _createForOfIteratorHelper$1(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(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$1(o, minLen); } | ||
function _arrayLikeToArray$1(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; } | ||
function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
/** | ||
@@ -861,2 +857,4 @@ * The `prosemirror-suggest` state which manages the list of suggesters. | ||
var _lastChangeFromAppend = /*#__PURE__*/new WeakMap(); | ||
class SuggestState { | ||
@@ -918,3 +916,3 @@ /** | ||
constructor(suggesters) { | ||
constructor(_suggesters2) { | ||
_docChanged.set(this, { | ||
@@ -960,2 +958,7 @@ writable: true, | ||
_lastChangeFromAppend.set(this, { | ||
writable: true, | ||
value: false | ||
}); | ||
_defineProperty__default['default'](this, "setMarkRemoved", () => { | ||
@@ -965,2 +968,20 @@ _classPrivateFieldSet__default['default'](this, _removed, true); | ||
_defineProperty__default['default'](this, "findNextTextSelection", selection => { | ||
var doc = selection.$from.doc; // Make sure the position doesn't exceed the bounds of the document. | ||
var pos = Math.min(doc.nodeSize - 2, selection.to + 1); | ||
var $pos = doc.resolve(pos); // Get the position furthest along in the editor to pass back to suggesters | ||
// which have the handler. | ||
var nextSelection = prosemirrorState.Selection.findFrom($pos, 1, true); // Ignore non-text selections and null / undefined values. This is needed | ||
// for TS mainly, since the `true` in the `Selection.findFrom` method means | ||
// only `TextSelection` instances will be returned. | ||
if (!isTextSelection(nextSelection)) { | ||
return; | ||
} | ||
return nextSelection; | ||
}); | ||
_defineProperty__default['default'](this, "ignoreNextExit", () => { | ||
@@ -987,3 +1008,3 @@ _classPrivateFieldSet__default['default'](this, _ignoreNextExit, true); | ||
} : {}; | ||
var decoration = prosemirrorView.Decoration.inline(from, to, _objectSpread$1({ | ||
var decoration = prosemirrorView.Decoration.inline(from, to, _objectSpread__default['default']({ | ||
nodeName: suggester.ignoredTag | ||
@@ -1037,5 +1058,15 @@ }, attributes), { | ||
_defineProperty__default['default'](this, "findMatchAtPosition", ($pos, name) => { | ||
var suggesters = name ? _classPrivateFieldGet__default['default'](this, _suggesters).filter(suggester => suggester.name === name) : _classPrivateFieldGet__default['default'](this, _suggesters); | ||
return findFromSuggesters({ | ||
suggesters, | ||
$pos, | ||
docChanged: false, | ||
selectionEmpty: true | ||
}); | ||
}); | ||
var mapper = createSuggesterMapper(); | ||
_classPrivateFieldSet__default['default'](this, _suggesters, suggesters.map(mapper)); | ||
_classPrivateFieldSet__default['default'](this, _suggesters, _suggesters2.map(mapper)); | ||
@@ -1067,3 +1098,3 @@ _classPrivateFieldSet__default['default'](this, _suggesters, coreHelpers.sort(_classPrivateFieldGet__default['default'](this, _suggesters), (a, b) => b.priority - a.priority)); | ||
char = _match$suggester.char; | ||
return _objectSpread$1({ | ||
return _objectSpread__default['default']({ | ||
view: this.view, | ||
@@ -1092,17 +1123,20 @@ addIgnored: this.addIgnored, | ||
} | ||
/** | ||
* Find the next text selection from the current selection. | ||
*/ | ||
updateWithNextSelection() { | ||
var _this$view$state = this.view.state, | ||
doc = _this$view$state.doc, | ||
selection = _this$view$state.selection; // Make sure the position doesn't exceed the bounds of the document. | ||
var pos = Math.min(doc.nodeSize - 2, selection.to + 1); | ||
var $pos = doc.resolve(pos); // Get the position furthest along in the editor to pass back to suggesters | ||
/** | ||
* Update all the suggesters with the next valid selection. This is called | ||
* within the `appendTransaction` ProseMirror method before any of the change | ||
* handlers are called. | ||
* | ||
* @internal | ||
*/ | ||
updateWithNextSelection(tr) { | ||
// Get the position furthest along in the editor to pass back to suggesters | ||
// which have the handler. | ||
var nextSelection = this.findNextTextSelection(tr.selection); | ||
var nextSelection = prosemirrorState.Selection.findFrom($pos, 1, true); // Ignore non-text selections and null / undefined values. This is needed | ||
// for TS mainly, since the `true` in the `Selection.findFrom` method means | ||
// only `TextSelection` instances will be returned. | ||
if (!isTextSelection(nextSelection)) { | ||
if (!nextSelection) { | ||
return; | ||
@@ -1112,3 +1146,3 @@ } // Update every suggester with a method attached. | ||
var _iterator = _createForOfIteratorHelper$1(_classPrivateFieldGet__default['default'](this, _suggesters)), | ||
var _iterator = _createForOfIteratorHelper__default['default'](_classPrivateFieldGet__default['default'](this, _suggesters)), | ||
_step; | ||
@@ -1118,6 +1152,11 @@ | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var _suggester$checkNextV; | ||
var _classPrivateFieldGet2, _classPrivateFieldGet3, _suggester$checkNextV; | ||
var suggester = _step.value; | ||
(_suggester$checkNextV = suggester.checkNextValidSelection) === null || _suggester$checkNextV === void 0 ? void 0 : _suggester$checkNextV.call(suggester, nextSelection.$from, this.view.state); | ||
var change = (_classPrivateFieldGet2 = _classPrivateFieldGet__default['default'](this, _handlerMatches).change) === null || _classPrivateFieldGet2 === void 0 ? void 0 : _classPrivateFieldGet2.suggester.name; | ||
var exit = (_classPrivateFieldGet3 = _classPrivateFieldGet__default['default'](this, _handlerMatches).exit) === null || _classPrivateFieldGet3 === void 0 ? void 0 : _classPrivateFieldGet3.suggester.name; | ||
(_suggester$checkNextV = suggester.checkNextValidSelection) === null || _suggester$checkNextV === void 0 ? void 0 : _suggester$checkNextV.call(suggester, nextSelection.$from, tr, { | ||
change, | ||
exit | ||
}); | ||
} | ||
@@ -1131,19 +1170,24 @@ } catch (err) { | ||
/** | ||
* Manages the view updates. | ||
* Call the `onChange` handlers. | ||
* | ||
* @internal | ||
*/ | ||
onViewUpdate() { | ||
var _classPrivateFieldGet2 = _classPrivateFieldGet__default['default'](this, _handlerMatches), | ||
change = _classPrivateFieldGet2.change, | ||
exit = _classPrivateFieldGet2.exit; | ||
changeHandler(tr, appendTransaction) { | ||
var _classPrivateFieldGet4 = _classPrivateFieldGet__default['default'](this, _handlerMatches), | ||
change = _classPrivateFieldGet4.change, | ||
exit = _classPrivateFieldGet4.exit; | ||
var match = this.match; // Notify all suggesters of the next valid text selection. | ||
var match = this.match; // Cancel update when a suggester isn't active | ||
this.updateWithNextSelection(); // Cancel update when a suggester isn't active | ||
if (!change && !exit || !isValidMatch(match)) { | ||
// TODO - when not active do a look forward to check the next position and | ||
// call the handler with the position. This will be used to | ||
return; | ||
} | ||
var shouldRunExit = appendTransaction === (exit === null || exit === void 0 ? void 0 : exit.suggester.appendTransaction) && this.shouldRunExit(); | ||
var shouldRunChange = appendTransaction === (change === null || change === void 0 ? void 0 : change.suggester.appendTransaction); | ||
if (!shouldRunExit && !shouldRunChange) { | ||
return; | ||
} // When a jump happens run the action that involves the position that occurs | ||
@@ -1158,4 +1202,4 @@ // later in the document. This is so that changes don't affect previous | ||
})) { | ||
var exitParameters = this.createParameter(exit); | ||
var changeParameters = this.createParameter(change); // Whether the jump was forwards or backwards. A forwards jump means that | ||
var exitDetails = this.createParameter(exit); | ||
var changeDetails = this.createParameter(change); // Whether the jump was forwards or backwards. A forwards jump means that | ||
// the user was within a suggester nearer the beginning of the document, | ||
@@ -1169,10 +1213,12 @@ // before jumping forward to a point later on in the document. | ||
// change so call the handler before the change handler. | ||
this.shouldRunExit() && exit.suggester.onChange(exitParameters); | ||
change.suggester.onChange(changeParameters); | ||
shouldRunExit && exit.suggester.onChange(exitDetails, tr); | ||
shouldRunChange && change.suggester.onChange(changeDetails, tr); | ||
} else { | ||
this.shouldRunExit() && exit.suggester.onChange(exitParameters); | ||
change.suggester.onChange(changeParameters); | ||
shouldRunExit && exit.suggester.onChange(exitDetails, tr); | ||
shouldRunChange && change.suggester.onChange(changeDetails, tr); | ||
} | ||
_classPrivateFieldSet__default['default'](this, _removed, false); | ||
if (shouldRunExit) { | ||
_classPrivateFieldSet__default['default'](this, _removed, false); | ||
} | ||
@@ -1182,8 +1228,8 @@ return; | ||
if (change) { | ||
change.suggester.onChange(this.createParameter(change)); | ||
if (change && shouldRunChange) { | ||
change.suggester.onChange(this.createParameter(change), tr); | ||
} | ||
if (exit && this.shouldRunExit()) { | ||
exit.suggester.onChange(this.createParameter(exit)); | ||
if (exit && shouldRunExit) { | ||
exit.suggester.onChange(this.createParameter(exit), tr); | ||
@@ -1198,2 +1244,4 @@ _classPrivateFieldSet__default['default'](this, _removed, false); | ||
} | ||
return; | ||
} | ||
@@ -1274,2 +1322,4 @@ /** | ||
_classPrivateFieldSet__default['default'](this, _removed, false); | ||
_classPrivateFieldSet__default['default'](this, _lastChangeFromAppend, false); | ||
} | ||
@@ -1308,6 +1358,10 @@ /** | ||
/** | ||
* Add a new suggest or replace it if it already exists. | ||
* A helper method to check is a match exists for the provided suggester name | ||
* at the provided position. | ||
*/ | ||
/** | ||
* Add a new suggest or replace it if it already exists. | ||
*/ | ||
addSuggester(suggester) { | ||
@@ -1341,13 +1395,3 @@ var previous = _classPrivateFieldGet__default['default'](this, _suggesters).find(item => item.name === suggester.name); | ||
} | ||
/** | ||
* Used to handle the view property of the plugin spec. | ||
*/ | ||
viewHandler() { | ||
return { | ||
update: this.onViewUpdate.bind(this) | ||
}; | ||
} | ||
toJSON() { | ||
@@ -1364,7 +1408,13 @@ return this.match; | ||
apply(parameter) { | ||
if (_classPrivateFieldGet__default['default'](this, _lastChangeFromAppend)) { | ||
_classPrivateFieldSet__default['default'](this, _lastChangeFromAppend, false); | ||
return this; | ||
} | ||
var tr = parameter.tr, | ||
state = parameter.state; | ||
var _classPrivateFieldGet3 = _classPrivateFieldGet__default['default'](this, _handlerMatches), | ||
exit = _classPrivateFieldGet3.exit; | ||
var _classPrivateFieldGet5 = _classPrivateFieldGet__default['default'](this, _handlerMatches), | ||
exit = _classPrivateFieldGet5.exit; | ||
@@ -1424,3 +1474,3 @@ var transactionHasChanged = tr.docChanged || tr.selectionSet; | ||
nodeName: suggestTag, | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
class: name ? "".concat(suggestClassName, " suggest-").concat(name) : suggestClassName | ||
}, { | ||
@@ -1430,3 +1480,13 @@ name | ||
} | ||
/** | ||
* Set that the last change was caused by an appended transaction. | ||
* | ||
* @internal | ||
*/ | ||
setLastChangeFromAppend() { | ||
_classPrivateFieldSet__default['default'](this, _lastChangeFromAppend, true); | ||
} | ||
} | ||
@@ -1446,3 +1506,3 @@ | ||
var suggesterWithDefaults = _objectSpread$1(_objectSpread$1({}, DEFAULT_SUGGESTER), suggester); | ||
var suggesterWithDefaults = _objectSpread__default['default'](_objectSpread__default['default']({}, DEFAULT_SUGGESTER), suggester); | ||
@@ -1513,3 +1573,10 @@ names.add(suggester.name); | ||
view: _view => { | ||
return pluginState.init(_view).viewHandler(); | ||
// Initialize the state with the required view before it is used. | ||
pluginState.init(_view); | ||
return { | ||
update: view => { | ||
// console.log('VIEW_UPDATE', { content: view.state.doc.textContent }); | ||
return pluginState.changeHandler(view.state.tr, false); | ||
} | ||
}; | ||
}, | ||
@@ -1523,2 +1590,3 @@ state: { | ||
apply: (tr, _pluginState, _oldState, state) => { | ||
// console.log('APPLY', { content: tr.doc.textContent }); | ||
return pluginState.apply({ | ||
@@ -1530,2 +1598,19 @@ tr, | ||
}, | ||
/** Append a transaction via the onChange handlers */ | ||
appendTransaction: (_, __, state) => { | ||
var tr = state.tr; // console.log('APPEND_TRANSACTION', { content: tr.doc.textContent }); | ||
// Run the transaction updater for the next selection. | ||
pluginState.updateWithNextSelection(tr); // Run the change handler. | ||
pluginState.changeHandler(tr, true); // Check if the transaction has been amended in any way. | ||
if (tr.docChanged || tr.steps.length > 0 || tr.selectionSet || tr.storedMarksSet) { | ||
pluginState.setLastChangeFromAppend(); | ||
return tr; | ||
} | ||
return null; | ||
}, | ||
props: { | ||
@@ -1544,2 +1629,3 @@ // Sets up a decoration (styling options) on the currently active | ||
exports.createRegexFromSuggester = createRegexFromSuggester; | ||
exports.findFromSuggesters = findFromSuggesters; | ||
exports.getSuggestPluginState = getSuggestPluginState; | ||
@@ -1557,2 +1643,3 @@ exports.getSuggesterWithDefaults = getSuggesterWithDefaults; | ||
exports.isRemovedReason = isRemovedReason; | ||
exports.isSelectionChangeReason = isSelectionChangeReason; | ||
exports.isSelectionExitReason = isSelectionExitReason; | ||
@@ -1559,0 +1646,0 @@ exports.isSplitReason = isSplitReason; |
@@ -7,3 +7,3 @@ "use strict"; | ||
var prosemirrorState = require("prosemirror-state"), _defineProperty = require("@babel/runtime/helpers/defineProperty"), _classPrivateFieldSet = require("@babel/runtime/helpers/classPrivateFieldSet"), _classPrivateFieldGet = require("@babel/runtime/helpers/classPrivateFieldGet"), prosemirrorView = require("prosemirror-view"), coreHelpers = require("@remirror/core-helpers"), escapeStringRegex = require("escape-string-regexp"), coreConstants = require("@remirror/core-constants"); | ||
var prosemirrorState = require("prosemirror-state"), _createForOfIteratorHelper = require("@babel/runtime/helpers/createForOfIteratorHelper"), _objectSpread = require("@babel/runtime/helpers/objectSpread2"), _defineProperty = require("@babel/runtime/helpers/defineProperty"), _classPrivateFieldSet = require("@babel/runtime/helpers/classPrivateFieldSet"), _classPrivateFieldGet = require("@babel/runtime/helpers/classPrivateFieldGet"), prosemirrorView = require("prosemirror-view"), coreHelpers = require("@remirror/core-helpers"), escapeStringRegex = require("escape-string-regexp"), coreConstants = require("@remirror/core-constants"); | ||
@@ -16,6 +16,6 @@ function _interopDefault(e) { | ||
var _defineProperty__default = _interopDefault(_defineProperty), _classPrivateFieldSet__default = _interopDefault(_classPrivateFieldSet), _classPrivateFieldGet__default = _interopDefault(_classPrivateFieldGet), escapeStringRegex__default = _interopDefault(escapeStringRegex); | ||
var _createForOfIteratorHelper__default = _interopDefault(_createForOfIteratorHelper), _objectSpread__default = _interopDefault(_objectSpread), _defineProperty__default = _interopDefault(_defineProperty), _classPrivateFieldSet__default = _interopDefault(_classPrivateFieldSet), _classPrivateFieldGet__default = _interopDefault(_classPrivateFieldGet), escapeStringRegex__default = _interopDefault(escapeStringRegex); | ||
function isChange(compare) { | ||
return !(!compare.prev || !compare.next || compare.prev.query.full === compare.next.query.full); | ||
return !(!compare.prev || !compare.next || compare.prev.text.full === compare.next.text.full); | ||
} | ||
@@ -64,2 +64,8 @@ | ||
var selectionChangeReasons = [ exports.ChangeReason.JumpBackward, exports.ChangeReason.JumpForward, exports.ChangeReason.Move, exports.ChangeReason.SelectionInside ]; | ||
function isSelectionChangeReason(value) { | ||
return coreHelpers.includes(selectionChangeReasons, value); | ||
} | ||
function isSplitReason(value) { | ||
@@ -97,88 +103,5 @@ return value === exports.ExitReason.Split; | ||
function _createForOfIteratorHelper(o, allowArrayLike) { | ||
var it; | ||
if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { | ||
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && "number" == typeof o.length) { | ||
it && (o = it); | ||
var i = 0, F = function() {}; | ||
return { | ||
s: F, | ||
n: function() { | ||
return i >= o.length ? { | ||
done: !0 | ||
} : { | ||
done: !1, | ||
value: o[i++] | ||
}; | ||
}, | ||
e: function(_e) { | ||
throw _e; | ||
}, | ||
f: F | ||
}; | ||
} | ||
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); | ||
} | ||
var err, normalCompletion = !0, didErr = !1; | ||
return { | ||
s: function() { | ||
it = o[Symbol.iterator](); | ||
}, | ||
n: function() { | ||
var step = it.next(); | ||
return normalCompletion = step.done, step; | ||
}, | ||
e: function(_e2) { | ||
didErr = !0, err = _e2; | ||
}, | ||
f: function() { | ||
try { | ||
normalCompletion || null == it.return || it.return(); | ||
} finally { | ||
if (didErr) throw err; | ||
} | ||
} | ||
}; | ||
} | ||
function _unsupportedIterableToArray(o, minLen) { | ||
if (o) { | ||
if ("string" == typeof o) return _arrayLikeToArray(o, minLen); | ||
var n = Object.prototype.toString.call(o).slice(8, -1); | ||
return "Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n ? Array.from(o) : "Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n) ? _arrayLikeToArray(o, minLen) : void 0; | ||
} | ||
} | ||
function _arrayLikeToArray(arr, len) { | ||
(null == len || len > arr.length) && (len = arr.length); | ||
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; | ||
return arr2; | ||
} | ||
function ownKeys(object, enumerableOnly) { | ||
var keys = Object.keys(object); | ||
if (Object.getOwnPropertySymbols) { | ||
var symbols = Object.getOwnPropertySymbols(object); | ||
enumerableOnly && (symbols = symbols.filter((function(sym) { | ||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | ||
}))), keys.push.apply(keys, symbols); | ||
} | ||
return keys; | ||
} | ||
function _objectSpread(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = null != arguments[i] ? arguments[i] : {}; | ||
i % 2 ? ownKeys(Object(source), !0).forEach((function(key) { | ||
_defineProperty__default.default(target, key, source[key]); | ||
})) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach((function(key) { | ||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | ||
})); | ||
} | ||
return target; | ||
} | ||
function createMatchWithReason(parameter) { | ||
var match = parameter.match, changeReason = parameter.changeReason, exitReason = parameter.exitReason; | ||
return _objectSpread(_objectSpread({}, match), {}, { | ||
return _objectSpread__default.default(_objectSpread__default.default({}, match), {}, { | ||
changeReason: changeReason, | ||
@@ -225,3 +148,5 @@ exitReason: exitReason | ||
startOfLine: startOfLine, | ||
supportedCharacters: supportedCharacters | ||
supportedCharacters: supportedCharacters, | ||
multiline: suggester.multiline, | ||
caseInsensitive: suggester.caseInsensitive | ||
}); | ||
@@ -310,3 +235,3 @@ return findPosition({ | ||
}); | ||
return updatedPrevious && updatedPrevious.query.full === match.query.full ? !state.selection.empty && (selection.from <= match.range.from || selection.to >= match.range.to) ? { | ||
return updatedPrevious && updatedPrevious.text.full === match.text.full ? !state.selection.empty && (selection.from <= match.range.from || selection.to >= match.range.to) ? { | ||
exit: createMatchWithReason({ | ||
@@ -395,3 +320,3 @@ match: match, | ||
function findFromSuggesters(parameter) { | ||
var _step, suggesters = parameter.suggesters, $pos = parameter.$pos, selectionEmpty = parameter.selectionEmpty, _iterator = _createForOfIteratorHelper(suggesters); | ||
var _step, suggesters = parameter.suggesters, $pos = parameter.$pos, selectionEmpty = parameter.selectionEmpty, _iterator = _createForOfIteratorHelper__default.default(suggesters); | ||
try { | ||
@@ -412,5 +337,3 @@ for (_iterator.s(); !(_step = _iterator.n()).done; ) { | ||
if (isPositionValidForSuggester(suggester, resolvedRange) && suggester.isValidPosition(resolvedRange, match)) return match; | ||
} catch (_unused2) { | ||
console.error("If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened."); | ||
} | ||
} catch (_unused2) {} | ||
} | ||
@@ -441,3 +364,3 @@ } catch (err) { | ||
function createRegexFromSuggester(parameter) { | ||
var char = parameter.char, matchOffset = parameter.matchOffset, startOfLine = parameter.startOfLine, supportedCharacters = parameter.supportedCharacters, _parameter$flags = parameter.flags, flags = void 0 === _parameter$flags ? "gm" : _parameter$flags, _parameter$captureCha = parameter.captureChar, captureChar = void 0 === _parameter$captureCha || _parameter$captureCha, charRegex = getCharAsRegex(char).source; | ||
var char = parameter.char, matchOffset = parameter.matchOffset, startOfLine = parameter.startOfLine, supportedCharacters = parameter.supportedCharacters, _parameter$captureCha = parameter.captureChar, captureChar = void 0 === _parameter$captureCha || _parameter$captureCha, _parameter$caseInsens = parameter.caseInsensitive, caseInsensitive = void 0 !== _parameter$caseInsens && _parameter$caseInsens, _parameter$multiline = parameter.multiline, flags = "g".concat(void 0 !== _parameter$multiline && _parameter$multiline ? "m" : "").concat(caseInsensitive ? "i" : ""), charRegex = getCharAsRegex(char).source; | ||
return captureChar && (charRegex = "(".concat(charRegex, ")")), new RegExp("".concat(getRegexPrefix(startOfLine), "(").concat(charRegex, ")").concat(getRegexSupportedCharacters(supportedCharacters, matchOffset)), flags); | ||
@@ -447,2 +370,3 @@ } | ||
var DEFAULT_SUGGESTER = { | ||
appendTransaction: !1, | ||
priority: 50, | ||
@@ -465,94 +389,13 @@ ignoredTag: "span", | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: !1 | ||
emptySelectionsOnly: !1, | ||
caseInsensitive: !1, | ||
multiline: !1 | ||
}; | ||
function getSuggesterWithDefaults(suggester) { | ||
return _objectSpread(_objectSpread({}, DEFAULT_SUGGESTER), suggester); | ||
return _objectSpread__default.default(_objectSpread__default.default({}, DEFAULT_SUGGESTER), suggester); | ||
} | ||
function _createForOfIteratorHelper$1(o, allowArrayLike) { | ||
var it; | ||
if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { | ||
if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && "number" == typeof o.length) { | ||
it && (o = it); | ||
var i = 0, F = function() {}; | ||
return { | ||
s: F, | ||
n: function() { | ||
return i >= o.length ? { | ||
done: !0 | ||
} : { | ||
done: !1, | ||
value: o[i++] | ||
}; | ||
}, | ||
e: function(_e) { | ||
throw _e; | ||
}, | ||
f: F | ||
}; | ||
} | ||
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); | ||
} | ||
var err, normalCompletion = !0, didErr = !1; | ||
return { | ||
s: function() { | ||
it = o[Symbol.iterator](); | ||
}, | ||
n: function() { | ||
var step = it.next(); | ||
return normalCompletion = step.done, step; | ||
}, | ||
e: function(_e2) { | ||
didErr = !0, err = _e2; | ||
}, | ||
f: function() { | ||
try { | ||
normalCompletion || null == it.return || it.return(); | ||
} finally { | ||
if (didErr) throw err; | ||
} | ||
} | ||
}; | ||
} | ||
var _docChanged = new WeakMap, _ignoreNextExit = new WeakMap, _suggesters = new WeakMap, _next = new WeakMap, _prev = new WeakMap, _handlerMatches = new WeakMap, _ignored = new WeakMap, _removed = new WeakMap, _lastChangeFromAppend = new WeakMap; | ||
function _unsupportedIterableToArray$1(o, minLen) { | ||
if (o) { | ||
if ("string" == typeof o) return _arrayLikeToArray$1(o, minLen); | ||
var n = Object.prototype.toString.call(o).slice(8, -1); | ||
return "Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n ? Array.from(o) : "Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n) ? _arrayLikeToArray$1(o, minLen) : void 0; | ||
} | ||
} | ||
function _arrayLikeToArray$1(arr, len) { | ||
(null == len || len > arr.length) && (len = arr.length); | ||
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; | ||
return arr2; | ||
} | ||
function ownKeys$1(object, enumerableOnly) { | ||
var keys = Object.keys(object); | ||
if (Object.getOwnPropertySymbols) { | ||
var symbols = Object.getOwnPropertySymbols(object); | ||
enumerableOnly && (symbols = symbols.filter((function(sym) { | ||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | ||
}))), keys.push.apply(keys, symbols); | ||
} | ||
return keys; | ||
} | ||
function _objectSpread$1(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = null != arguments[i] ? arguments[i] : {}; | ||
i % 2 ? ownKeys$1(Object(source), !0).forEach((function(key) { | ||
_defineProperty__default.default(target, key, source[key]); | ||
})) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys$1(Object(source)).forEach((function(key) { | ||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | ||
})); | ||
} | ||
return target; | ||
} | ||
var _docChanged = new WeakMap, _ignoreNextExit = new WeakMap, _suggesters = new WeakMap, _next = new WeakMap, _prev = new WeakMap, _handlerMatches = new WeakMap, _ignored = new WeakMap, _removed = new WeakMap; | ||
class SuggestState { | ||
@@ -571,3 +414,3 @@ static create(suggesters) { | ||
} | ||
constructor(suggesters) { | ||
constructor(_suggesters2) { | ||
_docChanged.set(this, { | ||
@@ -597,4 +440,10 @@ writable: !0, | ||
value: !1 | ||
}), _lastChangeFromAppend.set(this, { | ||
writable: !0, | ||
value: !1 | ||
}), _defineProperty__default.default(this, "setMarkRemoved", () => { | ||
_classPrivateFieldSet__default.default(this, _removed, !0); | ||
}), _defineProperty__default.default(this, "findNextTextSelection", selection => { | ||
var doc = selection.$from.doc, pos = Math.min(doc.nodeSize - 2, selection.to + 1), $pos = doc.resolve(pos), nextSelection = prosemirrorState.Selection.findFrom($pos, 1, !0); | ||
if (isTextSelection(nextSelection)) return nextSelection; | ||
}), _defineProperty__default.default(this, "ignoreNextExit", () => { | ||
@@ -607,3 +456,3 @@ _classPrivateFieldSet__default.default(this, _ignoreNextExit, !0); | ||
class: suggester.ignoredClassName | ||
} : {}, decoration = prosemirrorView.Decoration.inline(from, to, _objectSpread$1({ | ||
} : {}, decoration = prosemirrorView.Decoration.inline(from, to, _objectSpread__default.default({ | ||
nodeName: suggester.ignoredTag | ||
@@ -626,5 +475,10 @@ }, attributes), { | ||
} else _classPrivateFieldSet__default.default(this, _ignored, prosemirrorView.DecorationSet.empty); | ||
}); | ||
}), _defineProperty__default.default(this, "findMatchAtPosition", ($pos, name) => findFromSuggesters({ | ||
suggesters: name ? _classPrivateFieldGet__default.default(this, _suggesters).filter(suggester => suggester.name === name) : _classPrivateFieldGet__default.default(this, _suggesters), | ||
$pos: $pos, | ||
docChanged: !1, | ||
selectionEmpty: !0 | ||
})); | ||
var mapper = createSuggesterMapper(); | ||
_classPrivateFieldSet__default.default(this, _suggesters, suggesters.map(mapper)), | ||
_classPrivateFieldSet__default.default(this, _suggesters, _suggesters2.map(mapper)), | ||
_classPrivateFieldSet__default.default(this, _suggesters, coreHelpers.sort(_classPrivateFieldGet__default.default(this, _suggesters), (a, b) => b.priority - a.priority)); | ||
@@ -637,3 +491,3 @@ } | ||
var _match$suggester = match.suggester, name = _match$suggester.name, char = _match$suggester.char; | ||
return _objectSpread$1({ | ||
return _objectSpread__default.default({ | ||
view: this.view, | ||
@@ -652,10 +506,13 @@ addIgnored: this.addIgnored, | ||
} | ||
updateWithNextSelection() { | ||
var _this$view$state = this.view.state, doc = _this$view$state.doc, selection = _this$view$state.selection, pos = Math.min(doc.nodeSize - 2, selection.to + 1), $pos = doc.resolve(pos), nextSelection = prosemirrorState.Selection.findFrom($pos, 1, !0); | ||
if (isTextSelection(nextSelection)) { | ||
var _step, _iterator = _createForOfIteratorHelper$1(_classPrivateFieldGet__default.default(this, _suggesters)); | ||
updateWithNextSelection(tr) { | ||
var nextSelection = this.findNextTextSelection(tr.selection); | ||
if (nextSelection) { | ||
var _step, _iterator = _createForOfIteratorHelper__default.default(_classPrivateFieldGet__default.default(this, _suggesters)); | ||
try { | ||
for (_iterator.s(); !(_step = _iterator.n()).done; ) { | ||
var _suggester$checkNextV, suggester = _step.value; | ||
null === (_suggester$checkNextV = suggester.checkNextValidSelection) || void 0 === _suggester$checkNextV || _suggester$checkNextV.call(suggester, nextSelection.$from, this.view.state); | ||
var _classPrivateFieldGet2, _classPrivateFieldGet3, _suggester$checkNextV, suggester = _step.value, change = null === (_classPrivateFieldGet2 = _classPrivateFieldGet__default.default(this, _handlerMatches).change) || void 0 === _classPrivateFieldGet2 ? void 0 : _classPrivateFieldGet2.suggester.name, exit = null === (_classPrivateFieldGet3 = _classPrivateFieldGet__default.default(this, _handlerMatches).exit) || void 0 === _classPrivateFieldGet3 ? void 0 : _classPrivateFieldGet3.suggester.name; | ||
null === (_suggester$checkNextV = suggester.checkNextValidSelection) || void 0 === _suggester$checkNextV || _suggester$checkNextV.call(suggester, nextSelection.$from, tr, { | ||
change: change, | ||
exit: exit | ||
}); | ||
} | ||
@@ -669,16 +526,20 @@ } catch (err) { | ||
} | ||
onViewUpdate() { | ||
var _classPrivateFieldGet2 = _classPrivateFieldGet__default.default(this, _handlerMatches), change = _classPrivateFieldGet2.change, exit = _classPrivateFieldGet2.exit, match = this.match; | ||
if (this.updateWithNextSelection(), (change || exit) && isValidMatch(match)) { | ||
if (change && exit && isJumpReason({ | ||
change: change, | ||
exit: exit | ||
})) { | ||
var exitParameters = this.createParameter(exit), changeParameters = this.createParameter(change); | ||
exit.range.from, change.range.from; | ||
return this.shouldRunExit() && exit.suggester.onChange(exitParameters), change.suggester.onChange(changeParameters), | ||
void _classPrivateFieldSet__default.default(this, _removed, !1); | ||
changeHandler(tr, appendTransaction) { | ||
var _classPrivateFieldGet4 = _classPrivateFieldGet__default.default(this, _handlerMatches), change = _classPrivateFieldGet4.change, exit = _classPrivateFieldGet4.exit, match = this.match; | ||
if ((change || exit) && isValidMatch(match)) { | ||
var shouldRunExit = appendTransaction === (null == exit ? void 0 : exit.suggester.appendTransaction) && this.shouldRunExit(), shouldRunChange = appendTransaction === (null == change ? void 0 : change.suggester.appendTransaction); | ||
if (shouldRunExit || shouldRunChange) { | ||
if (change && exit && isJumpReason({ | ||
change: change, | ||
exit: exit | ||
})) { | ||
var exitDetails = this.createParameter(exit), changeDetails = this.createParameter(change); | ||
exit.range.from, change.range.from; | ||
return shouldRunExit && exit.suggester.onChange(exitDetails, tr), shouldRunChange && change.suggester.onChange(changeDetails, tr), | ||
void (shouldRunExit && _classPrivateFieldSet__default.default(this, _removed, !1)); | ||
} | ||
change && shouldRunChange && change.suggester.onChange(this.createParameter(change), tr), | ||
exit && shouldRunExit && (exit.suggester.onChange(this.createParameter(exit), tr), | ||
_classPrivateFieldSet__default.default(this, _removed, !1), isInvalidSplitReason(exit.exitReason) && _classPrivateFieldSet__default.default(this, _handlerMatches, coreHelpers.object())); | ||
} | ||
change && change.suggester.onChange(this.createParameter(change)), exit && this.shouldRunExit() && (exit.suggester.onChange(this.createParameter(exit)), | ||
_classPrivateFieldSet__default.default(this, _removed, !1), isInvalidSplitReason(exit.exitReason) && _classPrivateFieldSet__default.default(this, _handlerMatches, coreHelpers.object())); | ||
} | ||
@@ -702,3 +563,4 @@ } | ||
_classPrivateFieldSet__default.default(this, _handlerMatches, coreHelpers.object()), | ||
_classPrivateFieldSet__default.default(this, _next, void 0), _classPrivateFieldSet__default.default(this, _removed, !1); | ||
_classPrivateFieldSet__default.default(this, _next, void 0), _classPrivateFieldSet__default.default(this, _removed, !1), | ||
_classPrivateFieldSet__default.default(this, _lastChangeFromAppend, !1); | ||
} | ||
@@ -733,7 +595,2 @@ updateReasons(parameter) { | ||
} | ||
viewHandler() { | ||
return { | ||
update: this.onViewUpdate.bind(this) | ||
}; | ||
} | ||
toJSON() { | ||
@@ -743,2 +600,4 @@ return this.match; | ||
apply(parameter) { | ||
if (_classPrivateFieldGet__default.default(this, _lastChangeFromAppend)) return _classPrivateFieldSet__default.default(this, _lastChangeFromAppend, !1), | ||
this; | ||
var tr = parameter.tr, state = parameter.state, exit = _classPrivateFieldGet__default.default(this, _handlerMatches).exit; | ||
@@ -760,3 +619,3 @@ return tr.docChanged || tr.selectionSet || _classPrivateFieldGet__default.default(this, _removed) ? (_classPrivateFieldSet__default.default(this, _docChanged, tr.docChanged), | ||
nodeName: suggestTag, | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
class: name ? "".concat(suggestClassName, " suggest-").concat(name) : suggestClassName | ||
}, { | ||
@@ -766,2 +625,5 @@ name: name | ||
} | ||
setLastChangeFromAppend() { | ||
_classPrivateFieldSet__default.default(this, _lastChangeFromAppend, !0); | ||
} | ||
} | ||
@@ -773,3 +635,3 @@ | ||
if (names.has(suggester.name)) throw new Error("A suggester already exists with the name '".concat(suggester.name, "'. The name provided must be unique.")); | ||
var suggesterWithDefaults = _objectSpread$1(_objectSpread$1({}, DEFAULT_SUGGESTER), suggester); | ||
var suggesterWithDefaults = _objectSpread__default.default(_objectSpread__default.default({}, DEFAULT_SUGGESTER), suggester); | ||
return names.add(suggester.name), suggesterWithDefaults; | ||
@@ -798,3 +660,5 @@ }; | ||
key: suggestPluginKey, | ||
view: _view => pluginState.init(_view).viewHandler(), | ||
view: _view => (pluginState.init(_view), { | ||
update: view => pluginState.changeHandler(view.state.tr, !1) | ||
}), | ||
state: { | ||
@@ -807,2 +671,8 @@ init: () => pluginState, | ||
}, | ||
appendTransaction: (_, __, state) => { | ||
var tr = state.tr; | ||
return pluginState.updateWithNextSelection(tr), pluginState.changeHandler(tr, !0), | ||
tr.docChanged || tr.steps.length > 0 || tr.selectionSet || tr.storedMarksSet ? (pluginState.setLastChangeFromAppend(), | ||
tr) : null; | ||
}, | ||
props: { | ||
@@ -815,11 +685,12 @@ decorations: state => pluginState.createDecorations(state) | ||
exports.DEFAULT_SUGGESTER = DEFAULT_SUGGESTER, exports.addSuggester = addSuggester, | ||
exports.createRegexFromSuggester = createRegexFromSuggester, exports.getSuggestPluginState = getSuggestPluginState, | ||
exports.getSuggesterWithDefaults = getSuggesterWithDefaults, exports.isChange = isChange, | ||
exports.isChangeReason = isChangeReason, exports.isEntry = isEntry, exports.isExit = isExit, | ||
exports.isExitReason = isExitReason, exports.isInvalidSplitReason = isInvalidSplitReason, | ||
exports.createRegexFromSuggester = createRegexFromSuggester, exports.findFromSuggesters = findFromSuggesters, | ||
exports.getSuggestPluginState = getSuggestPluginState, exports.getSuggesterWithDefaults = getSuggesterWithDefaults, | ||
exports.isChange = isChange, exports.isChangeReason = isChangeReason, exports.isEntry = isEntry, | ||
exports.isExit = isExit, exports.isExitReason = isExitReason, exports.isInvalidSplitReason = isInvalidSplitReason, | ||
exports.isJump = isJump, exports.isJumpReason = isJumpReason, exports.isMove = isMove, | ||
exports.isRemovedReason = isRemovedReason, exports.isSelectionExitReason = isSelectionExitReason, | ||
exports.isSplitReason = isSplitReason, exports.isValidMatch = isValidMatch, exports.markActiveInRange = markActiveInRange, | ||
exports.isRemovedReason = isRemovedReason, exports.isSelectionChangeReason = isSelectionChangeReason, | ||
exports.isSelectionExitReason = isSelectionExitReason, exports.isSplitReason = isSplitReason, | ||
exports.isValidMatch = isValidMatch, exports.markActiveInRange = markActiveInRange, | ||
exports.positionHasMarks = positionHasMarks, exports.rangeHasMarks = rangeHasMarks, | ||
exports.removeSuggester = removeSuggester, exports.selectionOutsideMatch = selectionOutsideMatch, | ||
exports.suggest = suggest; |
import { TextSelection, Selection, PluginKey, Plugin } from 'prosemirror-state'; | ||
import _createForOfIteratorHelper from '@babel/runtime/helpers/esm/createForOfIteratorHelper'; | ||
import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2'; | ||
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty'; | ||
@@ -6,3 +8,3 @@ import _classPrivateFieldSet from '@babel/runtime/helpers/esm/classPrivateFieldSet'; | ||
import { DecorationSet, Decoration } from 'prosemirror-view'; | ||
import { isString, includes, isObject, range, isRegExp, object, findMatches, isEmptyArray, bool, sort, isFunction } from '@remirror/core-helpers'; | ||
import { isString, includes, isObject, range, isRegExp, findMatches, isEmptyArray, object, bool, sort, isFunction } from '@remirror/core-helpers'; | ||
import escapeStringRegex from 'escape-string-regexp'; | ||
@@ -25,2 +27,8 @@ import { NULL_CHARACTER } from '@remirror/core-constants'; | ||
* handlers are fired. | ||
* | ||
* @param $pos - the next valid position that supports text selections. | ||
* @param tr - the transaction that can be mutated when `appendTransaction` is | ||
* set to true. | ||
* @param matches - the possibly undefined exit and change matcher names. These | ||
* can be used to check if the name matches the current suggester. | ||
*/ | ||
@@ -81,3 +89,3 @@ | ||
function isChange(compare) { | ||
return !!(compare.prev && compare.next && compare.prev.query.full !== compare.next.query.full); | ||
return !!(compare.prev && compare.next && compare.prev.text.full !== compare.next.text.full); | ||
} | ||
@@ -136,2 +144,6 @@ /** | ||
} | ||
var selectionChangeReasons = [ChangeReason.JumpBackward, ChangeReason.JumpForward, ChangeReason.Move, ChangeReason.SelectionInside]; | ||
function isSelectionChangeReason(value) { | ||
return includes(selectionChangeReasons, value); | ||
} | ||
/** | ||
@@ -198,12 +210,2 @@ * Checks that the reason passed is a split reason. This typically means that we | ||
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
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); } | ||
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; } | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
/** | ||
@@ -312,3 +314,5 @@ * Small utility method for creating a match with the reason property available. | ||
supportedCharacters = suggester.supportedCharacters, | ||
matchOffset = suggester.matchOffset; // Create the regular expression to match the text against | ||
matchOffset = suggester.matchOffset, | ||
multiline = suggester.multiline, | ||
caseInsensitive = suggester.caseInsensitive; // Create the regular expression to match the text against | ||
@@ -319,3 +323,5 @@ var regexp = createRegexFromSuggester({ | ||
startOfLine, | ||
supportedCharacters | ||
supportedCharacters, | ||
multiline, | ||
caseInsensitive | ||
}); // All the text in the current node | ||
@@ -478,3 +484,3 @@ | ||
if (!updatedPrevious || updatedPrevious.query.full !== match.query.full) { | ||
if (!updatedPrevious || updatedPrevious.text.full !== match.text.full) { | ||
return createInsertReason({ | ||
@@ -731,7 +737,4 @@ prev: match, | ||
} catch (_unused2) { | ||
// This log is kept here even though it should probably be removed. It | ||
// should not happen, so if it does, please open an issue and a use case | ||
// for replication. | ||
console.error('If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened.'); | ||
} catch (_unused2) {// Captures any errors which can pop up when all the content in the editor | ||
// is deleted or an invalid position was provided. | ||
} | ||
@@ -793,6 +796,9 @@ } | ||
supportedCharacters = parameter.supportedCharacters, | ||
_parameter$flags = parameter.flags, | ||
flags = _parameter$flags === void 0 ? 'gm' : _parameter$flags, | ||
_parameter$captureCha = parameter.captureChar, | ||
captureChar = _parameter$captureCha === void 0 ? true : _parameter$captureCha; | ||
captureChar = _parameter$captureCha === void 0 ? true : _parameter$captureCha, | ||
_parameter$caseInsens = parameter.caseInsensitive, | ||
caseInsensitive = _parameter$caseInsens === void 0 ? false : _parameter$caseInsens, | ||
_parameter$multiline = parameter.multiline, | ||
multiline = _parameter$multiline === void 0 ? false : _parameter$multiline; | ||
var flags = "g".concat(multiline ? 'm' : '').concat(caseInsensitive ? 'i' : ''); | ||
var charRegex = getCharAsRegex(char).source; | ||
@@ -811,2 +817,3 @@ | ||
var DEFAULT_SUGGESTER = { | ||
appendTransaction: false, | ||
priority: 50, | ||
@@ -829,3 +836,5 @@ ignoredTag: 'span', | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: false | ||
emptySelectionsOnly: false, | ||
caseInsensitive: false, | ||
multiline: false | ||
}; | ||
@@ -840,11 +849,2 @@ /** | ||
function _createForOfIteratorHelper$1(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(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$1(o, minLen); } | ||
function _arrayLikeToArray$1(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; } | ||
function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
/** | ||
@@ -870,2 +870,4 @@ * The `prosemirror-suggest` state which manages the list of suggesters. | ||
var _lastChangeFromAppend = /*#__PURE__*/new WeakMap(); | ||
class SuggestState { | ||
@@ -927,3 +929,3 @@ /** | ||
constructor(suggesters) { | ||
constructor(_suggesters2) { | ||
_docChanged.set(this, { | ||
@@ -969,2 +971,7 @@ writable: true, | ||
_lastChangeFromAppend.set(this, { | ||
writable: true, | ||
value: false | ||
}); | ||
_defineProperty(this, "setMarkRemoved", () => { | ||
@@ -974,2 +981,20 @@ _classPrivateFieldSet(this, _removed, true); | ||
_defineProperty(this, "findNextTextSelection", selection => { | ||
var doc = selection.$from.doc; // Make sure the position doesn't exceed the bounds of the document. | ||
var pos = Math.min(doc.nodeSize - 2, selection.to + 1); | ||
var $pos = doc.resolve(pos); // Get the position furthest along in the editor to pass back to suggesters | ||
// which have the handler. | ||
var nextSelection = Selection.findFrom($pos, 1, true); // Ignore non-text selections and null / undefined values. This is needed | ||
// for TS mainly, since the `true` in the `Selection.findFrom` method means | ||
// only `TextSelection` instances will be returned. | ||
if (!isTextSelection(nextSelection)) { | ||
return; | ||
} | ||
return nextSelection; | ||
}); | ||
_defineProperty(this, "ignoreNextExit", () => { | ||
@@ -996,3 +1021,3 @@ _classPrivateFieldSet(this, _ignoreNextExit, true); | ||
} : {}; | ||
var decoration = Decoration.inline(from, to, _objectSpread$1({ | ||
var decoration = Decoration.inline(from, to, _objectSpread({ | ||
nodeName: suggester.ignoredTag | ||
@@ -1046,5 +1071,15 @@ }, attributes), { | ||
_defineProperty(this, "findMatchAtPosition", ($pos, name) => { | ||
var suggesters = name ? _classPrivateFieldGet(this, _suggesters).filter(suggester => suggester.name === name) : _classPrivateFieldGet(this, _suggesters); | ||
return findFromSuggesters({ | ||
suggesters, | ||
$pos, | ||
docChanged: false, | ||
selectionEmpty: true | ||
}); | ||
}); | ||
var mapper = createSuggesterMapper(); | ||
_classPrivateFieldSet(this, _suggesters, suggesters.map(mapper)); | ||
_classPrivateFieldSet(this, _suggesters, _suggesters2.map(mapper)); | ||
@@ -1076,3 +1111,3 @@ _classPrivateFieldSet(this, _suggesters, sort(_classPrivateFieldGet(this, _suggesters), (a, b) => b.priority - a.priority)); | ||
char = _match$suggester.char; | ||
return _objectSpread$1({ | ||
return _objectSpread({ | ||
view: this.view, | ||
@@ -1101,17 +1136,20 @@ addIgnored: this.addIgnored, | ||
} | ||
/** | ||
* Find the next text selection from the current selection. | ||
*/ | ||
updateWithNextSelection() { | ||
var _this$view$state = this.view.state, | ||
doc = _this$view$state.doc, | ||
selection = _this$view$state.selection; // Make sure the position doesn't exceed the bounds of the document. | ||
var pos = Math.min(doc.nodeSize - 2, selection.to + 1); | ||
var $pos = doc.resolve(pos); // Get the position furthest along in the editor to pass back to suggesters | ||
/** | ||
* Update all the suggesters with the next valid selection. This is called | ||
* within the `appendTransaction` ProseMirror method before any of the change | ||
* handlers are called. | ||
* | ||
* @internal | ||
*/ | ||
updateWithNextSelection(tr) { | ||
// Get the position furthest along in the editor to pass back to suggesters | ||
// which have the handler. | ||
var nextSelection = this.findNextTextSelection(tr.selection); | ||
var nextSelection = Selection.findFrom($pos, 1, true); // Ignore non-text selections and null / undefined values. This is needed | ||
// for TS mainly, since the `true` in the `Selection.findFrom` method means | ||
// only `TextSelection` instances will be returned. | ||
if (!isTextSelection(nextSelection)) { | ||
if (!nextSelection) { | ||
return; | ||
@@ -1121,3 +1159,3 @@ } // Update every suggester with a method attached. | ||
var _iterator = _createForOfIteratorHelper$1(_classPrivateFieldGet(this, _suggesters)), | ||
var _iterator = _createForOfIteratorHelper(_classPrivateFieldGet(this, _suggesters)), | ||
_step; | ||
@@ -1127,6 +1165,11 @@ | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var _suggester$checkNextV; | ||
var _classPrivateFieldGet2, _classPrivateFieldGet3, _suggester$checkNextV; | ||
var suggester = _step.value; | ||
(_suggester$checkNextV = suggester.checkNextValidSelection) === null || _suggester$checkNextV === void 0 ? void 0 : _suggester$checkNextV.call(suggester, nextSelection.$from, this.view.state); | ||
var change = (_classPrivateFieldGet2 = _classPrivateFieldGet(this, _handlerMatches).change) === null || _classPrivateFieldGet2 === void 0 ? void 0 : _classPrivateFieldGet2.suggester.name; | ||
var exit = (_classPrivateFieldGet3 = _classPrivateFieldGet(this, _handlerMatches).exit) === null || _classPrivateFieldGet3 === void 0 ? void 0 : _classPrivateFieldGet3.suggester.name; | ||
(_suggester$checkNextV = suggester.checkNextValidSelection) === null || _suggester$checkNextV === void 0 ? void 0 : _suggester$checkNextV.call(suggester, nextSelection.$from, tr, { | ||
change, | ||
exit | ||
}); | ||
} | ||
@@ -1140,19 +1183,24 @@ } catch (err) { | ||
/** | ||
* Manages the view updates. | ||
* Call the `onChange` handlers. | ||
* | ||
* @internal | ||
*/ | ||
onViewUpdate() { | ||
var _classPrivateFieldGet2 = _classPrivateFieldGet(this, _handlerMatches), | ||
change = _classPrivateFieldGet2.change, | ||
exit = _classPrivateFieldGet2.exit; | ||
changeHandler(tr, appendTransaction) { | ||
var _classPrivateFieldGet4 = _classPrivateFieldGet(this, _handlerMatches), | ||
change = _classPrivateFieldGet4.change, | ||
exit = _classPrivateFieldGet4.exit; | ||
var match = this.match; // Notify all suggesters of the next valid text selection. | ||
var match = this.match; // Cancel update when a suggester isn't active | ||
this.updateWithNextSelection(); // Cancel update when a suggester isn't active | ||
if (!change && !exit || !isValidMatch(match)) { | ||
// TODO - when not active do a look forward to check the next position and | ||
// call the handler with the position. This will be used to | ||
return; | ||
} | ||
var shouldRunExit = appendTransaction === (exit === null || exit === void 0 ? void 0 : exit.suggester.appendTransaction) && this.shouldRunExit(); | ||
var shouldRunChange = appendTransaction === (change === null || change === void 0 ? void 0 : change.suggester.appendTransaction); | ||
if (!shouldRunExit && !shouldRunChange) { | ||
return; | ||
} // When a jump happens run the action that involves the position that occurs | ||
@@ -1167,4 +1215,4 @@ // later in the document. This is so that changes don't affect previous | ||
})) { | ||
var exitParameters = this.createParameter(exit); | ||
var changeParameters = this.createParameter(change); // Whether the jump was forwards or backwards. A forwards jump means that | ||
var exitDetails = this.createParameter(exit); | ||
var changeDetails = this.createParameter(change); // Whether the jump was forwards or backwards. A forwards jump means that | ||
// the user was within a suggester nearer the beginning of the document, | ||
@@ -1178,10 +1226,12 @@ // before jumping forward to a point later on in the document. | ||
// change so call the handler before the change handler. | ||
this.shouldRunExit() && exit.suggester.onChange(exitParameters); | ||
change.suggester.onChange(changeParameters); | ||
shouldRunExit && exit.suggester.onChange(exitDetails, tr); | ||
shouldRunChange && change.suggester.onChange(changeDetails, tr); | ||
} else { | ||
this.shouldRunExit() && exit.suggester.onChange(exitParameters); | ||
change.suggester.onChange(changeParameters); | ||
shouldRunExit && exit.suggester.onChange(exitDetails, tr); | ||
shouldRunChange && change.suggester.onChange(changeDetails, tr); | ||
} | ||
_classPrivateFieldSet(this, _removed, false); | ||
if (shouldRunExit) { | ||
_classPrivateFieldSet(this, _removed, false); | ||
} | ||
@@ -1191,8 +1241,8 @@ return; | ||
if (change) { | ||
change.suggester.onChange(this.createParameter(change)); | ||
if (change && shouldRunChange) { | ||
change.suggester.onChange(this.createParameter(change), tr); | ||
} | ||
if (exit && this.shouldRunExit()) { | ||
exit.suggester.onChange(this.createParameter(exit)); | ||
if (exit && shouldRunExit) { | ||
exit.suggester.onChange(this.createParameter(exit), tr); | ||
@@ -1207,2 +1257,4 @@ _classPrivateFieldSet(this, _removed, false); | ||
} | ||
return; | ||
} | ||
@@ -1283,2 +1335,4 @@ /** | ||
_classPrivateFieldSet(this, _removed, false); | ||
_classPrivateFieldSet(this, _lastChangeFromAppend, false); | ||
} | ||
@@ -1317,6 +1371,10 @@ /** | ||
/** | ||
* Add a new suggest or replace it if it already exists. | ||
* A helper method to check is a match exists for the provided suggester name | ||
* at the provided position. | ||
*/ | ||
/** | ||
* Add a new suggest or replace it if it already exists. | ||
*/ | ||
addSuggester(suggester) { | ||
@@ -1350,13 +1408,3 @@ var previous = _classPrivateFieldGet(this, _suggesters).find(item => item.name === suggester.name); | ||
} | ||
/** | ||
* Used to handle the view property of the plugin spec. | ||
*/ | ||
viewHandler() { | ||
return { | ||
update: this.onViewUpdate.bind(this) | ||
}; | ||
} | ||
toJSON() { | ||
@@ -1373,7 +1421,13 @@ return this.match; | ||
apply(parameter) { | ||
if (_classPrivateFieldGet(this, _lastChangeFromAppend)) { | ||
_classPrivateFieldSet(this, _lastChangeFromAppend, false); | ||
return this; | ||
} | ||
var tr = parameter.tr, | ||
state = parameter.state; | ||
var _classPrivateFieldGet3 = _classPrivateFieldGet(this, _handlerMatches), | ||
exit = _classPrivateFieldGet3.exit; | ||
var _classPrivateFieldGet5 = _classPrivateFieldGet(this, _handlerMatches), | ||
exit = _classPrivateFieldGet5.exit; | ||
@@ -1433,3 +1487,3 @@ var transactionHasChanged = tr.docChanged || tr.selectionSet; | ||
nodeName: suggestTag, | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
class: name ? "".concat(suggestClassName, " suggest-").concat(name) : suggestClassName | ||
}, { | ||
@@ -1439,3 +1493,13 @@ name | ||
} | ||
/** | ||
* Set that the last change was caused by an appended transaction. | ||
* | ||
* @internal | ||
*/ | ||
setLastChangeFromAppend() { | ||
_classPrivateFieldSet(this, _lastChangeFromAppend, true); | ||
} | ||
} | ||
@@ -1455,3 +1519,3 @@ | ||
var suggesterWithDefaults = _objectSpread$1(_objectSpread$1({}, DEFAULT_SUGGESTER), suggester); | ||
var suggesterWithDefaults = _objectSpread(_objectSpread({}, DEFAULT_SUGGESTER), suggester); | ||
@@ -1522,3 +1586,10 @@ names.add(suggester.name); | ||
view: _view => { | ||
return pluginState.init(_view).viewHandler(); | ||
// Initialize the state with the required view before it is used. | ||
pluginState.init(_view); | ||
return { | ||
update: view => { | ||
// console.log('VIEW_UPDATE', { content: view.state.doc.textContent }); | ||
return pluginState.changeHandler(view.state.tr, false); | ||
} | ||
}; | ||
}, | ||
@@ -1532,2 +1603,3 @@ state: { | ||
apply: (tr, _pluginState, _oldState, state) => { | ||
// console.log('APPLY', { content: tr.doc.textContent }); | ||
return pluginState.apply({ | ||
@@ -1539,2 +1611,19 @@ tr, | ||
}, | ||
/** Append a transaction via the onChange handlers */ | ||
appendTransaction: (_, __, state) => { | ||
var tr = state.tr; // console.log('APPEND_TRANSACTION', { content: tr.doc.textContent }); | ||
// Run the transaction updater for the next selection. | ||
pluginState.updateWithNextSelection(tr); // Run the change handler. | ||
pluginState.changeHandler(tr, true); // Check if the transaction has been amended in any way. | ||
if (tr.docChanged || tr.steps.length > 0 || tr.selectionSet || tr.storedMarksSet) { | ||
pluginState.setLastChangeFromAppend(); | ||
return tr; | ||
} | ||
return null; | ||
}, | ||
props: { | ||
@@ -1550,2 +1639,2 @@ // Sets up a decoration (styling options) on the currently active | ||
export { ChangeReason, DEFAULT_SUGGESTER, ExitReason, addSuggester, createRegexFromSuggester, getSuggestPluginState, getSuggesterWithDefaults, isChange, isChangeReason, isEntry, isExit, isExitReason, isInvalidSplitReason, isJump, isJumpReason, isMove, isRemovedReason, isSelectionExitReason, isSplitReason, isValidMatch, markActiveInRange, positionHasMarks, rangeHasMarks, removeSuggester, selectionOutsideMatch, suggest }; | ||
export { ChangeReason, DEFAULT_SUGGESTER, ExitReason, addSuggester, createRegexFromSuggester, findFromSuggesters, getSuggestPluginState, getSuggesterWithDefaults, isChange, isChangeReason, isEntry, isExit, isExitReason, isInvalidSplitReason, isJump, isJumpReason, isMove, isRemovedReason, isSelectionChangeReason, isSelectionExitReason, isSplitReason, isValidMatch, markActiveInRange, positionHasMarks, rangeHasMarks, removeSuggester, selectionOutsideMatch, suggest }; |
{ | ||
"name": "prosemirror-suggest", | ||
"version": "1.0.0-next.34", | ||
"version": "1.0.0-next.35", | ||
"description": "Primitives for building your prosemirror suggestion and autocomplete functionality", | ||
@@ -24,4 +24,4 @@ "homepage": "https://github.com/remirror/remirror/tree/HEAD/packages/prosemirror-suggest", | ||
"@babel/runtime": "^7.11.0", | ||
"@remirror/core-constants": "1.0.0-next.34", | ||
"@remirror/core-helpers": "1.0.0-next.34", | ||
"@remirror/core-constants": "1.0.0-next.35", | ||
"@remirror/core-helpers": "1.0.0-next.35", | ||
"escape-string-regexp": "^4.0.0", | ||
@@ -35,5 +35,5 @@ "type-fest": "^0.16.0" | ||
"@types/prosemirror-view": "^1.15.0", | ||
"prosemirror-model": "^1.11.0", | ||
"prosemirror-model": "^1.11.2", | ||
"prosemirror-state": "^1.3.3", | ||
"prosemirror-view": "^1.15.5" | ||
"prosemirror-view": "^1.15.7" | ||
}, | ||
@@ -40,0 +40,0 @@ "peerDependencies": { |
@@ -5,8 +5,8 @@ # prosemirror-suggest | ||
[![Version][version]][npm] [![Weekly Downloads][downloads-badge]][npm] [![Bundled size][size-badge]][size] [![Typed Codebase][typescript]](./src/index.ts) ![MIT License][license] | ||
[![Version][version]][npm] [![Weekly Downloads][downloads-badge]][npm] [![Bundled size][size-badge]][size] [![Typed Codebase][typescript]](#) [![MIT License][license]](#) | ||
[version]: https://flat.badgen.net/npm/v/prosemirror-suggest | ||
[npm]: https://npmjs.com/package/prosemirror-suggest | ||
[version]: https://flat.badgen.net/npm/v/prosemirror-suggest/next | ||
[npm]: https://npmjs.com/package/prosemirror-suggest/v/next | ||
[license]: https://flat.badgen.net/badge/license/MIT/purple | ||
[size]: https://bundlephobia.com/result?p=prosemirror-suggest | ||
[size]: https://bundlephobia.com/result?p=prosemirror-suggest@next | ||
[size-badge]: https://flat.badgen.net/bundlephobia/minzip/prosemirror-suggest | ||
@@ -13,0 +13,0 @@ [typescript]: https://flat.badgen.net/badge/icon/TypeScript?icon=typescript&label |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7061
296345
+ Added@remirror/core-constants@1.0.0-next.35(transitive)
+ Added@remirror/core-helpers@1.0.0-next.35(transitive)
+ Added@remirror/core-types@1.0.0-next.35(transitive)
+ Added@remirror/pm@1.0.0-next.35(transitive)
- Removed@remirror/core-constants@1.0.0-next.34(transitive)
- Removed@remirror/core-helpers@1.0.0-next.34(transitive)
- Removed@remirror/core-types@1.0.0-next.34(transitive)
- Removed@remirror/pm@1.0.0-next.34(transitive)