prosemirror-suggest
Advanced tools
Comparing version 1.0.0-next.32 to 1.0.0-next.33
# prosemirror-suggest | ||
## 1.0.0-next.33 | ||
> 2020-09-07 | ||
### Minor Changes | ||
- 7a34e15d: Multiple improvements to the `prosemirror-suggest` implementation. | ||
Add support for setting a function to determine whether decorations should be ignored. `ShouldDisableDecorations` takes the current state and the active match and returns true when decorations should be disabled. | ||
Add support for `checkNextValidSelection` which is called for all suggesters to provide the opportunity to peek forward into the next valid text selection and decide whether or not any action should be taken. This is used in the `@remirror/extension-mention` to fix [#639](https://github.com/remirror/remirror/issues/639). | ||
Add option `emptySelectionsOnly` to prevent matches when the text selection is not empty. | ||
Prevent non-text selection from triggering matches. | ||
Adds missing range check to `invalidMarks` tests. | ||
- 7a34e15d: Add `invalidMarks` support. | ||
- Add the ability to disable all input rules if a certain mark is active. | ||
- Fix the `ItalicExtension` regex which was over eager. | ||
- Expose `decorationSet` for the `prosemirror-suggest` state. | ||
- Export `markActiveInRange`, `rangeHasMarks`, `positionHasMarks` from `prosemirror-suggest`. | ||
- Add helpers `getMarksByTags` and `getNodesByTags` to the `TagsExtension`. | ||
### Patch Changes | ||
- Updated dependencies [7a34e15d] | ||
- @remirror/core-constants@1.0.0-next.33 | ||
- @remirror/core-helpers@1.0.0-next.33 | ||
## 1.0.0-next.32 | ||
@@ -4,0 +36,0 @@ |
@@ -7,7 +7,7 @@ /** | ||
*/ | ||
export type { SuggestState } from './suggest-plugin'; | ||
export type { SuggestState } from './suggest-state'; | ||
export { addSuggester, getSuggestPluginState, removeSuggester, suggest } from './suggest-plugin'; | ||
export type { AddIgnoredParameter, CompareMatchParameter, DocChangedParameter, RangeWithCursor, MatchValue, ReasonMatchParameter, ReasonParameter, RemoveIgnoredParameter, SuggestChangeHandler, SuggestChangeHandlerParameter, SuggestIgnoreParameter, SuggestMarkParameter, SuggestReasonMap, SuggestMatch, SuggestStateMatchParameter, SuggestMatchWithReason, Suggester, SuggesterParameter, } from './suggest-types'; | ||
export type { AddIgnoredParameter, CompareMatchParameter, CheckNextValidSelection, DocChangedParameter, RangeWithCursor, MatchValue, ReasonMatchParameter, ReasonParameter, RemoveIgnoredParameter, ShouldDisableDecorations, SuggestChangeHandler, SuggestChangeHandlerParameter, SuggestIgnoreParameter, SuggestMarkParameter, SuggestReasonMap, SuggestMatch, SuggestStateMatchParameter, SuggestMatchWithReason, Suggester, SuggesterParameter, } from './suggest-types'; | ||
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, } from './suggest-utils'; | ||
export { createRegexFromSuggester, getSuggesterWithDefaults, DEFAULT_SUGGESTER, markActiveInRange, rangeHasMarks, positionHasMarks, } from './suggest-utils'; |
@@ -38,2 +38,1 @@ import { Plugin } from 'prosemirror-state'; | ||
export declare function suggest<Schema extends EditorSchema = EditorSchema>(...suggesters: Array<Suggester<Schema>>): Plugin<SuggestState<Schema>, Schema>; | ||
export type { SuggestState }; |
@@ -0,1 +1,2 @@ | ||
import { TextSelection } from 'prosemirror-state'; | ||
import type { CompareMatchParameter, EditorSchema, SelectionParameter, SuggestMatch, SuggestReasonMap, SuggestStateMatchParameter } from './suggest-types'; | ||
@@ -64,2 +65,8 @@ import { ChangeReason, ExitReason } from './suggest-types'; | ||
export declare function selectionOutsideMatch<Schema extends EditorSchema = EditorSchema>(parameter: Partial<SuggestStateMatchParameter<Schema>> & SelectionParameter<Schema>): boolean; | ||
/** | ||
* Predicate checking whether the selection is a `TextSelection`. | ||
* | ||
* @param value - the value to check | ||
*/ | ||
export declare function isTextSelection<Schema extends EditorSchema = EditorSchema>(value: unknown): value is TextSelection<Schema>; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import { PluginKey } from 'prosemirror-state'; | ||
import { DecorationSet } from 'prosemirror-view'; | ||
@@ -17,2 +18,6 @@ import type { AddIgnoredParameter, EditorSchema, EditorState, EditorStateParameter, EditorView, RemoveIgnoredParameter, Suggester, SuggestMatch, TransactionParameter } from './suggest-types'; | ||
/** | ||
* The set of all decorations. | ||
*/ | ||
get decorationSet(): DecorationSet; | ||
/** | ||
* True when the most recent change was to remove a mention. | ||
@@ -64,2 +69,3 @@ * | ||
private shouldRunExit; | ||
private updateWithNextSelection; | ||
/** | ||
@@ -147,3 +153,7 @@ * Manages the view updates. | ||
*/ | ||
decorations(state: EditorState<Schema>): DecorationSet<Schema>; | ||
createDecorations(state: EditorState<Schema>): DecorationSet<Schema>; | ||
} | ||
/** | ||
* This key is stored to provide access to the plugin state. | ||
*/ | ||
export declare const suggestPluginKey: PluginKey<any, any>; |
@@ -146,3 +146,3 @@ /** | ||
*/ | ||
disableDecorations?: boolean; | ||
disableDecorations?: boolean | ShouldDisableDecorations; | ||
/** | ||
@@ -191,4 +191,47 @@ * A list of node names which will be marked as invalid. | ||
isValidPosition?: (resolvedRange: ResolvedRangeWithCursor<Schema>, match: SuggestMatch<Schema>) => boolean; | ||
/** | ||
* This is a utility option that may be necessary for you when building | ||
* editable mentions using `prosemirror-suggest`. | ||
* | ||
* By default `prosemirror-suggest` is a backward looking solution to the | ||
* suggestions problem. It check backwards from the current cursor position to | ||
* see if any text matches any of the configured selections. For the majority | ||
* of use cases this is perfectly acceptable behaviour. | ||
* | ||
* However, [#639](https://github.com/remirror/remirror/issues/639) shows that | ||
* it's possible to delete forward and make mentions invalid. At the moment, | ||
* when this happens it would require creating a plugin to check each state | ||
* update and see whether the current next position has any invalid instances | ||
* of the mention mark. | ||
* | ||
* 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. | ||
* | ||
* @default null | ||
*/ | ||
checkNextValidSelection?: CheckNextValidSelection | null; | ||
/** | ||
* Whether this suggester should only be valid for empty selections. | ||
* | ||
* @default false | ||
*/ | ||
emptySelectionsOnly?: boolean; | ||
} | ||
/** | ||
* A function for checking whether the next selection is valid. | ||
* | ||
* It is called for all registered suggesters before any of the onChange | ||
* handlers are fired. | ||
*/ | ||
export declare type CheckNextValidSelection<Schema extends EditorSchema = EditorSchema> = ($pos: ResolvedPos<Schema>, state: EditorState<Schema>) => void; | ||
/** | ||
* A function that can be used to determine whether the decoration should be set | ||
* or not. | ||
* | ||
* @param match - the current active match | ||
* @param resolvedRange - the range of the match with each position resolved. | ||
*/ | ||
export declare type ShouldDisableDecorations = <Schema extends EditorSchema = EditorSchema>(state: EditorState<Schema>, match: Readonly<SuggestMatch<Schema>>) => boolean; | ||
/** | ||
* The potential reasons for an exit of a mention. | ||
@@ -640,2 +683,3 @@ */ | ||
export declare type EditorSchema = import('prosemirror-model').Schema<string, string>; | ||
export declare type ProsemirrorNode<Schema extends EditorSchema = EditorSchema> = import('prosemirror-model').Node<Schema>; | ||
export declare type Transaction<Schema extends EditorSchema = EditorSchema> = import('prosemirror-state').Transaction<Schema>; | ||
@@ -673,2 +717,4 @@ /** | ||
* working with a position in the editor. | ||
* | ||
* In prosemirror suggest this always uses the lower bound of the text selection. | ||
*/ | ||
@@ -675,0 +721,0 @@ $pos: ResolvedPos<Schema>; |
@@ -1,2 +0,2 @@ | ||
import type { CompareMatchParameter, DocChangedParameter, EditorSchema, EditorStateParameter, PickPartial, ResolvedPosParameter, Suggester, SuggestMatch, SuggestReasonMap } from './suggest-types'; | ||
import type { CompareMatchParameter, DocChangedParameter, EditorSchema, EditorStateParameter, PickPartial, ResolvedPos, ResolvedPosParameter, ResolvedRangeWithCursor, Suggester, SuggestMatch, SuggestReasonMap } from './suggest-types'; | ||
interface FindFromSuggestersParameter<Schema extends EditorSchema = EditorSchema> extends ResolvedPosParameter<Schema>, DocChangedParameter { | ||
@@ -7,2 +7,6 @@ /** | ||
suggesters: Array<Required<Suggester<Schema>>>; | ||
/** | ||
* When `true` the selection is empty. | ||
*/ | ||
selectionEmpty: boolean; | ||
} | ||
@@ -16,4 +20,28 @@ declare type FindReasonParameter<Schema extends EditorSchema = EditorSchema> = EditorStateParameter<Schema> & ResolvedPosParameter<Schema> & Partial<CompareMatchParameter<Schema>>; | ||
/** | ||
* Find a match for the provided matchers | ||
* Check whether the mark is active anywhere between `$from` and `$end`. | ||
* | ||
* Currently this is not doing exactly what it should. I've decided to be lazy | ||
* and only check the following. | ||
* | ||
* - Do any of the requested marks span the entire range using `rangeHasMarks`? | ||
* - Does the starting position have a mark? | ||
* - Does the cursor have a mark? | ||
* - Does the end position have a mark? | ||
* | ||
* In reality I should also check for each position within the range to see if a | ||
* target mark is active but I won't for now. | ||
*/ | ||
export declare function markActiveInRange<Schema extends EditorSchema = EditorSchema>(resolvedRange: Omit<ResolvedRangeWithCursor<Schema>, '$cursor'>, marks: string[]): boolean; | ||
/** | ||
* Check if the entire matching range `from` the start point all the way through | ||
* `to` the end point, has any of the provided marks that span it. | ||
*/ | ||
export declare function rangeHasMarks<Schema extends EditorSchema = EditorSchema>(resolvedRange: Omit<ResolvedRangeWithCursor<Schema>, '$cursor'>, marks: string[]): boolean; | ||
/** | ||
* Check if the provided position has the given marks. | ||
*/ | ||
export declare function positionHasMarks<Schema extends EditorSchema = EditorSchema>($pos: ResolvedPos<Schema>, marks: string[]): boolean; | ||
/** | ||
* Find a match for the provided matchers. | ||
*/ | ||
export declare function findFromSuggesters<Schema extends EditorSchema = EditorSchema>(parameter: FindFromSuggestersParameter<Schema>): SuggestMatch<Schema> | undefined; | ||
@@ -20,0 +48,0 @@ /** |
@@ -168,3 +168,12 @@ 'use strict'; | ||
} | ||
/** | ||
* Predicate checking whether the selection is a `TextSelection`. | ||
* | ||
* @param value - the value to check | ||
*/ | ||
function isTextSelection(value) { | ||
return coreHelpers.isObject(value) && value instanceof prosemirrorState.TextSelection; | ||
} | ||
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; } } }; } | ||
@@ -587,15 +596,18 @@ | ||
function markActiveInRange(resolvedRange, marks) { | ||
var $cursor = resolvedRange.$cursor, | ||
$from = resolvedRange.$from, | ||
$to = resolvedRange.$to; | ||
var cursorAtStart = $cursor.pos === $from.pos; | ||
var cursorAtEnd = $cursor.pos === $to.pos; | ||
return rangeHasMarks(resolvedRange, marks) || positionHasMarks($cursor, marks) || !cursorAtStart && positionHasMarks($from, marks) || !cursorAtEnd && positionHasMarks($to, marks); | ||
var $from = resolvedRange.$from, | ||
$to = resolvedRange.$to; // Check if there is a mark spanning the range of marks. | ||
if (rangeHasMarks(resolvedRange, marks)) { | ||
return true; | ||
} // Check if any of the positions in the available range have the active mark | ||
// associated with | ||
return coreHelpers.range($from.pos, $to.pos).some(value => positionHasMarks($from.doc.resolve(value), marks)); | ||
} | ||
/** | ||
* Check if the current matching range, from the start point all the way through | ||
* to the point, has the required marks. | ||
* Check if the entire matching range `from` the start point all the way through | ||
* `to` the end point, has any of the provided marks that span it. | ||
*/ | ||
function rangeHasMarks(resolvedRange, marks) { | ||
@@ -610,2 +622,5 @@ var _$from$marksAcross; | ||
} | ||
/** | ||
* Check if the provided position has the given marks. | ||
*/ | ||
@@ -623,3 +638,2 @@ function positionHasMarks($pos, marks) { | ||
function isPositionValidForSuggester(suggester, resolvedRange) { | ||
@@ -655,3 +669,3 @@ var $cursor = resolvedRange.$cursor; | ||
/** | ||
* Find a match for the provided matchers | ||
* Find a match for the provided matchers. | ||
*/ | ||
@@ -662,3 +676,4 @@ | ||
var suggesters = parameter.suggesters, | ||
$pos = parameter.$pos; // Find the first match and break when done | ||
$pos = parameter.$pos, | ||
selectionEmpty = parameter.selectionEmpty; // Find the first match and break when done | ||
@@ -672,2 +687,7 @@ var _iterator = _createForOfIteratorHelper(suggesters), | ||
// Make sure the selection is valid for this `suggester`. | ||
if (suggester.emptySelectionsOnly && !selectionEmpty) { | ||
continue; | ||
} | ||
try { | ||
@@ -698,3 +718,3 @@ var match = findMatch({ | ||
// for replication. | ||
console.warn('Error while finding match.'); | ||
console.error('If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened.'); | ||
} | ||
@@ -788,3 +808,5 @@ } | ||
validNodes: null, | ||
isValidPosition: () => true | ||
isValidPosition: () => true, | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: false | ||
}; | ||
@@ -799,2 +821,8 @@ /** | ||
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; } | ||
@@ -836,2 +864,8 @@ | ||
/** | ||
* The set of all decorations. | ||
*/ | ||
get decorationSet() { | ||
return _classPrivateFieldGet(this, _ignored); | ||
} | ||
/** | ||
* True when the most recent change was to remove a mention. | ||
@@ -846,2 +880,4 @@ * | ||
*/ | ||
get removed() { | ||
@@ -1041,2 +1077,37 @@ return _classPrivateFieldGet(this, _removed); | ||
} | ||
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 | ||
// 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; | ||
} // Update every suggester with a method attached. | ||
var _iterator = _createForOfIteratorHelper$1(_classPrivateFieldGet(this, _suggesters)), | ||
_step; | ||
try { | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var _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); | ||
} | ||
} catch (err) { | ||
_iterator.e(err); | ||
} finally { | ||
_iterator.f(); | ||
} | ||
} | ||
/** | ||
@@ -1052,5 +1123,9 @@ * Manages the view updates. | ||
var match = this.match; // Cancel update when a suggester isn't active | ||
var match = this.match; // Notify all suggesters of the next valid text selection. | ||
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; | ||
@@ -1191,7 +1266,11 @@ } // When a jump happens run the action that involves the position that occurs | ||
var match = findFromSuggesters({ | ||
suggesters: _classPrivateFieldGet(this, _suggesters), | ||
var suggesters = _classPrivateFieldGet(this, _suggesters); | ||
var selectionEmpty = state.selection.empty; | ||
var match = isTextSelection(state.selection) ? findFromSuggesters({ | ||
suggesters, | ||
$pos, | ||
docChanged | ||
}); // Track the next match if not being ignored. | ||
docChanged, | ||
selectionEmpty | ||
}) : undefined; // Track the next match if not being ignored. | ||
@@ -1299,3 +1378,3 @@ _classPrivateFieldSet(this, _next, match && this.shouldIgnoreMatch(match) ? undefined : match); // Store the matches with reasons | ||
decorations(state) { | ||
createDecorations(state) { | ||
var match = this.match; | ||
@@ -1307,3 +1386,6 @@ | ||
if (match.suggester.disableDecorations) { | ||
var disableDecorations = match.suggester.disableDecorations; | ||
var shouldSkip = coreHelpers.isFunction(disableDecorations) ? disableDecorations(state, match) : disableDecorations; | ||
if (shouldSkip) { | ||
return _classPrivateFieldGet(this, _ignored); | ||
@@ -1322,2 +1404,4 @@ } | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
}, { | ||
name | ||
})]); | ||
@@ -1346,5 +1430,9 @@ } | ||
} | ||
/** | ||
* This key is stored to provide access to the plugin state. | ||
*/ | ||
// This key is stored to provide access to the plugin state. | ||
var suggestPluginKey = /*#__PURE__*/new prosemirrorState.PluginKey('suggest'); | ||
/** | ||
@@ -1355,3 +1443,2 @@ * Get the state of the suggest plugin. | ||
*/ | ||
function getSuggestPluginState(state) { | ||
@@ -1424,3 +1511,3 @@ return suggestPluginKey.getState(state); | ||
decorations: state => { | ||
return pluginState.decorations(state); | ||
return pluginState.createDecorations(state); | ||
} | ||
@@ -1449,4 +1536,7 @@ } | ||
exports.isValidMatch = isValidMatch; | ||
exports.markActiveInRange = markActiveInRange; | ||
exports.positionHasMarks = positionHasMarks; | ||
exports.rangeHasMarks = rangeHasMarks; | ||
exports.removeSuggester = removeSuggester; | ||
exports.selectionOutsideMatch = selectionOutsideMatch; | ||
exports.suggest = suggest; |
@@ -1,2 +0,2 @@ | ||
import { Plugin, PluginKey } from 'prosemirror-state'; | ||
import { TextSelection, Selection, PluginKey, Plugin } from 'prosemirror-state'; | ||
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty'; | ||
@@ -6,3 +6,3 @@ import _classPrivateFieldSet from '@babel/runtime/helpers/esm/classPrivateFieldSet'; | ||
import { DecorationSet, Decoration } from 'prosemirror-view'; | ||
import { isString, includes, isRegExp, object, findMatches, isEmptyArray, bool, sort } from '@remirror/core-helpers'; | ||
import { isString, includes, isObject, range, isRegExp, object, findMatches, isEmptyArray, bool, sort, isFunction } from '@remirror/core-helpers'; | ||
import escapeStringRegex from 'escape-string-regexp'; | ||
@@ -21,2 +21,17 @@ import { NULL_CHARACTER } from '@remirror/core-constants'; | ||
/** | ||
* A function for checking whether the next selection is valid. | ||
* | ||
* It is called for all registered suggesters before any of the onChange | ||
* handlers are fired. | ||
*/ | ||
/** | ||
* A function that can be used to determine whether the decoration should be set | ||
* or not. | ||
* | ||
* @param match - the current active match | ||
* @param resolvedRange - the range of the match with each position resolved. | ||
*/ | ||
/** | ||
* The potential reasons for an exit of a mention. | ||
@@ -171,3 +186,12 @@ */ | ||
} | ||
/** | ||
* Predicate checking whether the selection is a `TextSelection`. | ||
* | ||
* @param value - the value to check | ||
*/ | ||
function isTextSelection(value) { | ||
return isObject(value) && value instanceof TextSelection; | ||
} | ||
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; } } }; } | ||
@@ -590,15 +614,18 @@ | ||
function markActiveInRange(resolvedRange, marks) { | ||
var $cursor = resolvedRange.$cursor, | ||
$from = resolvedRange.$from, | ||
$to = resolvedRange.$to; | ||
var cursorAtStart = $cursor.pos === $from.pos; | ||
var cursorAtEnd = $cursor.pos === $to.pos; | ||
return rangeHasMarks(resolvedRange, marks) || positionHasMarks($cursor, marks) || !cursorAtStart && positionHasMarks($from, marks) || !cursorAtEnd && positionHasMarks($to, marks); | ||
var $from = resolvedRange.$from, | ||
$to = resolvedRange.$to; // Check if there is a mark spanning the range of marks. | ||
if (rangeHasMarks(resolvedRange, marks)) { | ||
return true; | ||
} // Check if any of the positions in the available range have the active mark | ||
// associated with | ||
return range($from.pos, $to.pos).some(value => positionHasMarks($from.doc.resolve(value), marks)); | ||
} | ||
/** | ||
* Check if the current matching range, from the start point all the way through | ||
* to the point, has the required marks. | ||
* Check if the entire matching range `from` the start point all the way through | ||
* `to` the end point, has any of the provided marks that span it. | ||
*/ | ||
function rangeHasMarks(resolvedRange, marks) { | ||
@@ -613,2 +640,5 @@ var _$from$marksAcross; | ||
} | ||
/** | ||
* Check if the provided position has the given marks. | ||
*/ | ||
@@ -626,3 +656,2 @@ function positionHasMarks($pos, marks) { | ||
function isPositionValidForSuggester(suggester, resolvedRange) { | ||
@@ -658,3 +687,3 @@ var $cursor = resolvedRange.$cursor; | ||
/** | ||
* Find a match for the provided matchers | ||
* Find a match for the provided matchers. | ||
*/ | ||
@@ -665,3 +694,4 @@ | ||
var suggesters = parameter.suggesters, | ||
$pos = parameter.$pos; // Find the first match and break when done | ||
$pos = parameter.$pos, | ||
selectionEmpty = parameter.selectionEmpty; // Find the first match and break when done | ||
@@ -675,2 +705,7 @@ var _iterator = _createForOfIteratorHelper(suggesters), | ||
// Make sure the selection is valid for this `suggester`. | ||
if (suggester.emptySelectionsOnly && !selectionEmpty) { | ||
continue; | ||
} | ||
try { | ||
@@ -701,3 +736,3 @@ var match = findMatch({ | ||
// for replication. | ||
console.warn('Error while finding match.'); | ||
console.error('If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened.'); | ||
} | ||
@@ -791,3 +826,5 @@ } | ||
validNodes: null, | ||
isValidPosition: () => true | ||
isValidPosition: () => true, | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: false | ||
}; | ||
@@ -802,2 +839,8 @@ /** | ||
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; } | ||
@@ -839,2 +882,8 @@ | ||
/** | ||
* The set of all decorations. | ||
*/ | ||
get decorationSet() { | ||
return _classPrivateFieldGet(this, _ignored); | ||
} | ||
/** | ||
* True when the most recent change was to remove a mention. | ||
@@ -849,2 +898,4 @@ * | ||
*/ | ||
get removed() { | ||
@@ -1044,2 +1095,37 @@ return _classPrivateFieldGet(this, _removed); | ||
} | ||
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 | ||
// 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; | ||
} // Update every suggester with a method attached. | ||
var _iterator = _createForOfIteratorHelper$1(_classPrivateFieldGet(this, _suggesters)), | ||
_step; | ||
try { | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var _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); | ||
} | ||
} catch (err) { | ||
_iterator.e(err); | ||
} finally { | ||
_iterator.f(); | ||
} | ||
} | ||
/** | ||
@@ -1055,5 +1141,9 @@ * Manages the view updates. | ||
var match = this.match; // Cancel update when a suggester isn't active | ||
var match = this.match; // Notify all suggesters of the next valid text selection. | ||
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; | ||
@@ -1194,7 +1284,11 @@ } // When a jump happens run the action that involves the position that occurs | ||
var match = findFromSuggesters({ | ||
suggesters: _classPrivateFieldGet(this, _suggesters), | ||
var suggesters = _classPrivateFieldGet(this, _suggesters); | ||
var selectionEmpty = state.selection.empty; | ||
var match = isTextSelection(state.selection) ? findFromSuggesters({ | ||
suggesters, | ||
$pos, | ||
docChanged | ||
}); // Track the next match if not being ignored. | ||
docChanged, | ||
selectionEmpty | ||
}) : undefined; // Track the next match if not being ignored. | ||
@@ -1302,3 +1396,3 @@ _classPrivateFieldSet(this, _next, match && this.shouldIgnoreMatch(match) ? undefined : match); // Store the matches with reasons | ||
decorations(state) { | ||
createDecorations(state) { | ||
var match = this.match; | ||
@@ -1310,3 +1404,6 @@ | ||
if (match.suggester.disableDecorations) { | ||
var disableDecorations = match.suggester.disableDecorations; | ||
var shouldSkip = isFunction(disableDecorations) ? disableDecorations(state, match) : disableDecorations; | ||
if (shouldSkip) { | ||
return _classPrivateFieldGet(this, _ignored); | ||
@@ -1325,2 +1422,4 @@ } | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
}, { | ||
name | ||
})]); | ||
@@ -1349,5 +1448,9 @@ } | ||
} | ||
/** | ||
* This key is stored to provide access to the plugin state. | ||
*/ | ||
// This key is stored to provide access to the plugin state. | ||
var suggestPluginKey = /*#__PURE__*/new PluginKey('suggest'); | ||
/** | ||
@@ -1358,3 +1461,2 @@ * Get the state of the suggest plugin. | ||
*/ | ||
function getSuggestPluginState(state) { | ||
@@ -1427,3 +1529,3 @@ return suggestPluginKey.getState(state); | ||
decorations: state => { | ||
return pluginState.decorations(state); | ||
return pluginState.createDecorations(state); | ||
} | ||
@@ -1434,2 +1536,2 @@ } | ||
export { ChangeReason, DEFAULT_SUGGESTER, ExitReason, addSuggester, createRegexFromSuggester, getSuggestPluginState, getSuggesterWithDefaults, isChange, isChangeReason, isEntry, isExit, isExitReason, isInvalidSplitReason, isJump, isJumpReason, isMove, isRemovedReason, isSelectionExitReason, isSplitReason, isValidMatch, removeSuggester, selectionOutsideMatch, suggest }; | ||
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 }; |
@@ -168,3 +168,12 @@ 'use strict'; | ||
} | ||
/** | ||
* Predicate checking whether the selection is a `TextSelection`. | ||
* | ||
* @param value - the value to check | ||
*/ | ||
function isTextSelection(value) { | ||
return coreHelpers.isObject(value) && value instanceof prosemirrorState.TextSelection; | ||
} | ||
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; } } }; } | ||
@@ -587,15 +596,18 @@ | ||
function markActiveInRange(resolvedRange, marks) { | ||
var $cursor = resolvedRange.$cursor, | ||
$from = resolvedRange.$from, | ||
$to = resolvedRange.$to; | ||
var cursorAtStart = $cursor.pos === $from.pos; | ||
var cursorAtEnd = $cursor.pos === $to.pos; | ||
return rangeHasMarks(resolvedRange, marks) || positionHasMarks($cursor, marks) || !cursorAtStart && positionHasMarks($from, marks) || !cursorAtEnd && positionHasMarks($to, marks); | ||
var $from = resolvedRange.$from, | ||
$to = resolvedRange.$to; // Check if there is a mark spanning the range of marks. | ||
if (rangeHasMarks(resolvedRange, marks)) { | ||
return true; | ||
} // Check if any of the positions in the available range have the active mark | ||
// associated with | ||
return coreHelpers.range($from.pos, $to.pos).some(value => positionHasMarks($from.doc.resolve(value), marks)); | ||
} | ||
/** | ||
* Check if the current matching range, from the start point all the way through | ||
* to the point, has the required marks. | ||
* Check if the entire matching range `from` the start point all the way through | ||
* `to` the end point, has any of the provided marks that span it. | ||
*/ | ||
function rangeHasMarks(resolvedRange, marks) { | ||
@@ -610,2 +622,5 @@ var _$from$marksAcross; | ||
} | ||
/** | ||
* Check if the provided position has the given marks. | ||
*/ | ||
@@ -623,3 +638,2 @@ function positionHasMarks($pos, marks) { | ||
function isPositionValidForSuggester(suggester, resolvedRange) { | ||
@@ -655,3 +669,3 @@ var $cursor = resolvedRange.$cursor; | ||
/** | ||
* Find a match for the provided matchers | ||
* Find a match for the provided matchers. | ||
*/ | ||
@@ -662,3 +676,4 @@ | ||
var suggesters = parameter.suggesters, | ||
$pos = parameter.$pos; // Find the first match and break when done | ||
$pos = parameter.$pos, | ||
selectionEmpty = parameter.selectionEmpty; // Find the first match and break when done | ||
@@ -672,2 +687,7 @@ var _iterator = _createForOfIteratorHelper(suggesters), | ||
// Make sure the selection is valid for this `suggester`. | ||
if (suggester.emptySelectionsOnly && !selectionEmpty) { | ||
continue; | ||
} | ||
try { | ||
@@ -698,3 +718,3 @@ var match = findMatch({ | ||
// for replication. | ||
console.warn('Error while finding match.'); | ||
console.error('If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened.'); | ||
} | ||
@@ -788,3 +808,5 @@ } | ||
validNodes: null, | ||
isValidPosition: () => true | ||
isValidPosition: () => true, | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: false | ||
}; | ||
@@ -799,2 +821,8 @@ /** | ||
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; } | ||
@@ -836,2 +864,8 @@ | ||
/** | ||
* The set of all decorations. | ||
*/ | ||
get decorationSet() { | ||
return _classPrivateFieldGet(this, _ignored); | ||
} | ||
/** | ||
* True when the most recent change was to remove a mention. | ||
@@ -846,2 +880,4 @@ * | ||
*/ | ||
get removed() { | ||
@@ -1041,2 +1077,37 @@ return _classPrivateFieldGet(this, _removed); | ||
} | ||
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 | ||
// 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; | ||
} // Update every suggester with a method attached. | ||
var _iterator = _createForOfIteratorHelper$1(_classPrivateFieldGet(this, _suggesters)), | ||
_step; | ||
try { | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var _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); | ||
} | ||
} catch (err) { | ||
_iterator.e(err); | ||
} finally { | ||
_iterator.f(); | ||
} | ||
} | ||
/** | ||
@@ -1052,5 +1123,9 @@ * Manages the view updates. | ||
var match = this.match; // Cancel update when a suggester isn't active | ||
var match = this.match; // Notify all suggesters of the next valid text selection. | ||
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; | ||
@@ -1191,7 +1266,11 @@ } // When a jump happens run the action that involves the position that occurs | ||
var match = findFromSuggesters({ | ||
suggesters: _classPrivateFieldGet(this, _suggesters), | ||
var suggesters = _classPrivateFieldGet(this, _suggesters); | ||
var selectionEmpty = state.selection.empty; | ||
var match = isTextSelection(state.selection) ? findFromSuggesters({ | ||
suggesters, | ||
$pos, | ||
docChanged | ||
}); // Track the next match if not being ignored. | ||
docChanged, | ||
selectionEmpty | ||
}) : undefined; // Track the next match if not being ignored. | ||
@@ -1299,3 +1378,3 @@ _classPrivateFieldSet(this, _next, match && this.shouldIgnoreMatch(match) ? undefined : match); // Store the matches with reasons | ||
decorations(state) { | ||
createDecorations(state) { | ||
var match = this.match; | ||
@@ -1307,3 +1386,6 @@ | ||
if (match.suggester.disableDecorations) { | ||
var disableDecorations = match.suggester.disableDecorations; | ||
var shouldSkip = coreHelpers.isFunction(disableDecorations) ? disableDecorations(state, match) : disableDecorations; | ||
if (shouldSkip) { | ||
return _classPrivateFieldGet(this, _ignored); | ||
@@ -1322,2 +1404,4 @@ } | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
}, { | ||
name | ||
})]); | ||
@@ -1346,5 +1430,9 @@ } | ||
} | ||
/** | ||
* This key is stored to provide access to the plugin state. | ||
*/ | ||
// This key is stored to provide access to the plugin state. | ||
var suggestPluginKey = /*#__PURE__*/new prosemirrorState.PluginKey('suggest'); | ||
/** | ||
@@ -1355,3 +1443,2 @@ * Get the state of the suggest plugin. | ||
*/ | ||
function getSuggestPluginState(state) { | ||
@@ -1424,3 +1511,3 @@ return suggestPluginKey.getState(state); | ||
decorations: state => { | ||
return pluginState.decorations(state); | ||
return pluginState.createDecorations(state); | ||
} | ||
@@ -1449,4 +1536,7 @@ } | ||
exports.isValidMatch = isValidMatch; | ||
exports.markActiveInRange = markActiveInRange; | ||
exports.positionHasMarks = positionHasMarks; | ||
exports.rangeHasMarks = rangeHasMarks; | ||
exports.removeSuggester = removeSuggester; | ||
exports.selectionOutsideMatch = selectionOutsideMatch; | ||
exports.suggest = suggest; |
@@ -86,2 +86,6 @@ "use strict"; | ||
function isTextSelection(value) { | ||
return coreHelpers.isObject(value) && value instanceof prosemirrorState.TextSelection; | ||
} | ||
function _createForOfIteratorHelper(o, allowArrayLike) { | ||
@@ -362,4 +366,4 @@ var it; | ||
function markActiveInRange(resolvedRange, marks) { | ||
var $cursor = resolvedRange.$cursor, $from = resolvedRange.$from, $to = resolvedRange.$to, cursorAtStart = $cursor.pos === $from.pos, cursorAtEnd = $cursor.pos === $to.pos; | ||
return rangeHasMarks(resolvedRange, marks) || positionHasMarks($cursor, marks) || !cursorAtStart && positionHasMarks($from, marks) || !cursorAtEnd && positionHasMarks($to, marks); | ||
var $from = resolvedRange.$from, $to = resolvedRange.$to; | ||
return !!rangeHasMarks(resolvedRange, marks) || coreHelpers.range($from.pos, $to.pos).some(value => positionHasMarks($from.doc.resolve(value), marks)); | ||
} | ||
@@ -383,7 +387,7 @@ | ||
function findFromSuggesters(parameter) { | ||
var _step, suggesters = parameter.suggesters, $pos = parameter.$pos, _iterator = _createForOfIteratorHelper(suggesters); | ||
var _step, suggesters = parameter.suggesters, $pos = parameter.$pos, selectionEmpty = parameter.selectionEmpty, _iterator = _createForOfIteratorHelper(suggesters); | ||
try { | ||
for (_iterator.s(); !(_step = _iterator.n()).done; ) { | ||
var suggester = _step.value; | ||
try { | ||
if (!suggester.emptySelectionsOnly || selectionEmpty) try { | ||
var match = findMatch({ | ||
@@ -401,3 +405,3 @@ suggester: suggester, | ||
} catch (_unused2) { | ||
console.warn("Error while finding match."); | ||
console.error("If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened."); | ||
} | ||
@@ -449,3 +453,5 @@ } | ||
validNodes: null, | ||
isValidPosition: () => !0 | ||
isValidPosition: () => !0, | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: !1 | ||
}; | ||
@@ -457,2 +463,62 @@ | ||
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; | ||
} | ||
} | ||
}; | ||
} | ||
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) { | ||
@@ -487,2 +553,5 @@ var keys = Object.keys(object); | ||
} | ||
get decorationSet() { | ||
return _classPrivateFieldGet(this, _ignored); | ||
} | ||
get removed() { | ||
@@ -569,5 +638,21 @@ return _classPrivateFieldGet(this, _removed); | ||
} | ||
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(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); | ||
} | ||
} catch (err) { | ||
_iterator.e(err); | ||
} finally { | ||
_iterator.f(); | ||
} | ||
} | ||
} | ||
onViewUpdate() { | ||
var _classPrivateFieldGet2 = _classPrivateFieldGet(this, _handlerMatches), change = _classPrivateFieldGet2.change, exit = _classPrivateFieldGet2.exit, match = this.match; | ||
if ((change || exit) && isValidMatch(match)) { | ||
if (this.updateWithNextSelection(), (change || exit) && isValidMatch(match)) { | ||
if (change && exit && isJumpReason({ | ||
@@ -605,7 +690,8 @@ change: change, | ||
updateReasons(parameter) { | ||
var $pos = parameter.$pos, state = parameter.state, docChanged = _classPrivateFieldGet(this, _docChanged), match = findFromSuggesters({ | ||
suggesters: _classPrivateFieldGet(this, _suggesters), | ||
var $pos = parameter.$pos, state = parameter.state, docChanged = _classPrivateFieldGet(this, _docChanged), suggesters = _classPrivateFieldGet(this, _suggesters), selectionEmpty = state.selection.empty, match = isTextSelection(state.selection) ? findFromSuggesters({ | ||
suggesters: suggesters, | ||
$pos: $pos, | ||
docChanged: docChanged | ||
}); | ||
docChanged: docChanged, | ||
selectionEmpty: selectionEmpty | ||
}) : void 0; | ||
_classPrivateFieldSet(this, _next, match && this.shouldIgnoreMatch(match) ? void 0 : match), | ||
@@ -649,6 +735,7 @@ _classPrivateFieldSet(this, _handlerMatches, findReason({ | ||
} | ||
decorations(state) { | ||
createDecorations(state) { | ||
var match = this.match; | ||
if (!isValidMatch(match)) return _classPrivateFieldGet(this, _ignored); | ||
if (match.suggester.disableDecorations) return _classPrivateFieldGet(this, _ignored); | ||
var disableDecorations = match.suggester.disableDecorations; | ||
if (coreHelpers.isFunction(disableDecorations) ? disableDecorations(state, match) : disableDecorations) return _classPrivateFieldGet(this, _ignored); | ||
var range = match.range, suggester = match.suggester, name = suggester.name, suggestTag = suggester.suggestTag, suggestClassName = suggester.suggestClassName, from = range.from, to = range.to; | ||
@@ -658,2 +745,4 @@ return this.shouldIgnoreMatch(match) ? _classPrivateFieldGet(this, _ignored) : _classPrivateFieldGet(this, _ignored).add(state.doc, [ prosemirrorView.Decoration.inline(from, to, { | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
}, { | ||
name: name | ||
}) ]); | ||
@@ -700,3 +789,3 @@ } | ||
props: { | ||
decorations: state => pluginState.decorations(state) | ||
decorations: state => pluginState.createDecorations(state) | ||
} | ||
@@ -713,3 +802,5 @@ }); | ||
exports.isRemovedReason = isRemovedReason, exports.isSelectionExitReason = isSelectionExitReason, | ||
exports.isSplitReason = isSplitReason, exports.isValidMatch = isValidMatch, exports.removeSuggester = removeSuggester, | ||
exports.selectionOutsideMatch = selectionOutsideMatch, exports.suggest = suggest; | ||
exports.isSplitReason = isSplitReason, exports.isValidMatch = isValidMatch, exports.markActiveInRange = markActiveInRange, | ||
exports.positionHasMarks = positionHasMarks, exports.rangeHasMarks = rangeHasMarks, | ||
exports.removeSuggester = removeSuggester, exports.selectionOutsideMatch = selectionOutsideMatch, | ||
exports.suggest = suggest; |
@@ -1,2 +0,2 @@ | ||
import { Plugin, PluginKey } from 'prosemirror-state'; | ||
import { TextSelection, Selection, PluginKey, Plugin } from 'prosemirror-state'; | ||
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty'; | ||
@@ -6,3 +6,3 @@ import _classPrivateFieldSet from '@babel/runtime/helpers/esm/classPrivateFieldSet'; | ||
import { DecorationSet, Decoration } from 'prosemirror-view'; | ||
import { isString, includes, isRegExp, object, findMatches, isEmptyArray, bool, sort } from '@remirror/core-helpers'; | ||
import { isString, includes, isObject, range, isRegExp, object, findMatches, isEmptyArray, bool, sort, isFunction } from '@remirror/core-helpers'; | ||
import escapeStringRegex from 'escape-string-regexp'; | ||
@@ -21,2 +21,17 @@ import { NULL_CHARACTER } from '@remirror/core-constants'; | ||
/** | ||
* A function for checking whether the next selection is valid. | ||
* | ||
* It is called for all registered suggesters before any of the onChange | ||
* handlers are fired. | ||
*/ | ||
/** | ||
* A function that can be used to determine whether the decoration should be set | ||
* or not. | ||
* | ||
* @param match - the current active match | ||
* @param resolvedRange - the range of the match with each position resolved. | ||
*/ | ||
/** | ||
* The potential reasons for an exit of a mention. | ||
@@ -171,3 +186,12 @@ */ | ||
} | ||
/** | ||
* Predicate checking whether the selection is a `TextSelection`. | ||
* | ||
* @param value - the value to check | ||
*/ | ||
function isTextSelection(value) { | ||
return isObject(value) && value instanceof TextSelection; | ||
} | ||
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; } } }; } | ||
@@ -590,15 +614,18 @@ | ||
function markActiveInRange(resolvedRange, marks) { | ||
var $cursor = resolvedRange.$cursor, | ||
$from = resolvedRange.$from, | ||
$to = resolvedRange.$to; | ||
var cursorAtStart = $cursor.pos === $from.pos; | ||
var cursorAtEnd = $cursor.pos === $to.pos; | ||
return rangeHasMarks(resolvedRange, marks) || positionHasMarks($cursor, marks) || !cursorAtStart && positionHasMarks($from, marks) || !cursorAtEnd && positionHasMarks($to, marks); | ||
var $from = resolvedRange.$from, | ||
$to = resolvedRange.$to; // Check if there is a mark spanning the range of marks. | ||
if (rangeHasMarks(resolvedRange, marks)) { | ||
return true; | ||
} // Check if any of the positions in the available range have the active mark | ||
// associated with | ||
return range($from.pos, $to.pos).some(value => positionHasMarks($from.doc.resolve(value), marks)); | ||
} | ||
/** | ||
* Check if the current matching range, from the start point all the way through | ||
* to the point, has the required marks. | ||
* Check if the entire matching range `from` the start point all the way through | ||
* `to` the end point, has any of the provided marks that span it. | ||
*/ | ||
function rangeHasMarks(resolvedRange, marks) { | ||
@@ -613,2 +640,5 @@ var _$from$marksAcross; | ||
} | ||
/** | ||
* Check if the provided position has the given marks. | ||
*/ | ||
@@ -626,3 +656,2 @@ function positionHasMarks($pos, marks) { | ||
function isPositionValidForSuggester(suggester, resolvedRange) { | ||
@@ -658,3 +687,3 @@ var $cursor = resolvedRange.$cursor; | ||
/** | ||
* Find a match for the provided matchers | ||
* Find a match for the provided matchers. | ||
*/ | ||
@@ -665,3 +694,4 @@ | ||
var suggesters = parameter.suggesters, | ||
$pos = parameter.$pos; // Find the first match and break when done | ||
$pos = parameter.$pos, | ||
selectionEmpty = parameter.selectionEmpty; // Find the first match and break when done | ||
@@ -675,2 +705,7 @@ var _iterator = _createForOfIteratorHelper(suggesters), | ||
// Make sure the selection is valid for this `suggester`. | ||
if (suggester.emptySelectionsOnly && !selectionEmpty) { | ||
continue; | ||
} | ||
try { | ||
@@ -701,3 +736,3 @@ var match = findMatch({ | ||
// for replication. | ||
console.warn('Error while finding match.'); | ||
console.error('If you see this message then something went wrong internally. Please open an issue with the steps you took when it happened.'); | ||
} | ||
@@ -791,3 +826,5 @@ } | ||
validNodes: null, | ||
isValidPosition: () => true | ||
isValidPosition: () => true, | ||
checkNextValidSelection: null, | ||
emptySelectionsOnly: false | ||
}; | ||
@@ -802,2 +839,8 @@ /** | ||
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; } | ||
@@ -839,2 +882,8 @@ | ||
/** | ||
* The set of all decorations. | ||
*/ | ||
get decorationSet() { | ||
return _classPrivateFieldGet(this, _ignored); | ||
} | ||
/** | ||
* True when the most recent change was to remove a mention. | ||
@@ -849,2 +898,4 @@ * | ||
*/ | ||
get removed() { | ||
@@ -1044,2 +1095,37 @@ return _classPrivateFieldGet(this, _removed); | ||
} | ||
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 | ||
// 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; | ||
} // Update every suggester with a method attached. | ||
var _iterator = _createForOfIteratorHelper$1(_classPrivateFieldGet(this, _suggesters)), | ||
_step; | ||
try { | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var _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); | ||
} | ||
} catch (err) { | ||
_iterator.e(err); | ||
} finally { | ||
_iterator.f(); | ||
} | ||
} | ||
/** | ||
@@ -1055,5 +1141,9 @@ * Manages the view updates. | ||
var match = this.match; // Cancel update when a suggester isn't active | ||
var match = this.match; // Notify all suggesters of the next valid text selection. | ||
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; | ||
@@ -1194,7 +1284,11 @@ } // When a jump happens run the action that involves the position that occurs | ||
var match = findFromSuggesters({ | ||
suggesters: _classPrivateFieldGet(this, _suggesters), | ||
var suggesters = _classPrivateFieldGet(this, _suggesters); | ||
var selectionEmpty = state.selection.empty; | ||
var match = isTextSelection(state.selection) ? findFromSuggesters({ | ||
suggesters, | ||
$pos, | ||
docChanged | ||
}); // Track the next match if not being ignored. | ||
docChanged, | ||
selectionEmpty | ||
}) : undefined; // Track the next match if not being ignored. | ||
@@ -1302,3 +1396,3 @@ _classPrivateFieldSet(this, _next, match && this.shouldIgnoreMatch(match) ? undefined : match); // Store the matches with reasons | ||
decorations(state) { | ||
createDecorations(state) { | ||
var match = this.match; | ||
@@ -1310,3 +1404,6 @@ | ||
if (match.suggester.disableDecorations) { | ||
var disableDecorations = match.suggester.disableDecorations; | ||
var shouldSkip = isFunction(disableDecorations) ? disableDecorations(state, match) : disableDecorations; | ||
if (shouldSkip) { | ||
return _classPrivateFieldGet(this, _ignored); | ||
@@ -1325,2 +1422,4 @@ } | ||
class: name ? "".concat(suggestClassName, " ").concat(suggestClassName, "-").concat(name) : suggestClassName | ||
}, { | ||
name | ||
})]); | ||
@@ -1349,5 +1448,9 @@ } | ||
} | ||
/** | ||
* This key is stored to provide access to the plugin state. | ||
*/ | ||
// This key is stored to provide access to the plugin state. | ||
var suggestPluginKey = /*#__PURE__*/new PluginKey('suggest'); | ||
/** | ||
@@ -1358,3 +1461,2 @@ * Get the state of the suggest plugin. | ||
*/ | ||
function getSuggestPluginState(state) { | ||
@@ -1427,3 +1529,3 @@ return suggestPluginKey.getState(state); | ||
decorations: state => { | ||
return pluginState.decorations(state); | ||
return pluginState.createDecorations(state); | ||
} | ||
@@ -1434,2 +1536,2 @@ } | ||
export { ChangeReason, DEFAULT_SUGGESTER, ExitReason, addSuggester, createRegexFromSuggester, getSuggestPluginState, getSuggesterWithDefaults, isChange, isChangeReason, isEntry, isExit, isExitReason, isInvalidSplitReason, isJump, isJumpReason, isMove, isRemovedReason, isSelectionExitReason, isSplitReason, isValidMatch, removeSuggester, selectionOutsideMatch, suggest }; | ||
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 }; |
{ | ||
"name": "prosemirror-suggest", | ||
"version": "1.0.0-next.32", | ||
"version": "1.0.0-next.33", | ||
"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.32", | ||
"@remirror/core-helpers": "1.0.0-next.32", | ||
"@remirror/core-constants": "1.0.0-next.33", | ||
"@remirror/core-helpers": "1.0.0-next.33", | ||
"escape-string-regexp": "^4.0.0", | ||
@@ -28,0 +28,0 @@ "type-fest": "^0.16.0" |
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
292202
6841
+ Added@remirror/core-constants@1.0.0-next.33(transitive)
+ Added@remirror/core-helpers@1.0.0-next.33(transitive)
+ Added@remirror/core-types@1.0.0-next.33(transitive)
- Removed@remirror/core-constants@1.0.0-next.32(transitive)
- Removed@remirror/core-helpers@1.0.0-next.32(transitive)
- Removed@remirror/core-types@1.0.0-next.32(transitive)