This commit is contained in:
2025-01-04 00:34:03 +01:00
parent 41829408dc
commit 0ca14bbc19
18111 changed files with 1871397 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
'use strict';
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var prosemirrorState = require('prosemirror-state');
var prosemirrorTransform = require('prosemirror-transform');
var InputRule = _createClass(function InputRule(match, handler) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
_classCallCheck(this, InputRule);
this.match = match;
this.match = match;
this.handler = typeof handler == "string" ? stringHandler(handler) : handler;
this.undoable = options.undoable !== false;
this.inCode = options.inCode || false;
});
function stringHandler(string) {
return function (state, match, start, end) {
var insert = string;
if (match[1]) {
var offset = match[0].lastIndexOf(match[1]);
insert += match[0].slice(offset + match[1].length);
start += offset;
var cutOff = start - end;
if (cutOff > 0) {
insert = match[0].slice(offset - cutOff, offset) + insert;
start = end;
}
}
return state.tr.insertText(insert, start, end);
};
}
var MAX_MATCH = 500;
function inputRules(_ref) {
var rules = _ref.rules;
var plugin = new prosemirrorState.Plugin({
state: {
init: function init() {
return null;
},
apply: function apply(tr, prev) {
var stored = tr.getMeta(this);
if (stored) return stored;
return tr.selectionSet || tr.docChanged ? null : prev;
}
},
props: {
handleTextInput: function handleTextInput(view, from, to, text) {
return run(view, from, to, text, rules, plugin);
},
handleDOMEvents: {
compositionend: function compositionend(view) {
setTimeout(function () {
var $cursor = view.state.selection.$cursor;
if ($cursor) run(view, $cursor.pos, $cursor.pos, "", rules, plugin);
});
}
}
},
isInputRules: true
});
return plugin;
}
function run(view, from, to, text, rules, plugin) {
if (view.composing) return false;
var state = view.state,
$from = state.doc.resolve(from);
var textBefore = $from.parent.textBetween(Math.max(0, $from.parentOffset - MAX_MATCH), $from.parentOffset, null, "\uFFFC") + text;
for (var i = 0; i < rules.length; i++) {
var rule = rules[i];
if ($from.parent.type.spec.code) {
if (!rule.inCode) continue;
} else if (rule.inCode === "only") {
continue;
}
var match = rule.match.exec(textBefore);
var tr = match && rule.handler(state, match, from - (match[0].length - text.length), to);
if (!tr) continue;
if (rule.undoable) tr.setMeta(plugin, {
transform: tr,
from: from,
to: to,
text: text
});
view.dispatch(tr);
return true;
}
return false;
}
var undoInputRule = function undoInputRule(state, dispatch) {
var plugins = state.plugins;
for (var i = 0; i < plugins.length; i++) {
var plugin = plugins[i],
undoable = void 0;
if (plugin.spec.isInputRules && (undoable = plugin.getState(state))) {
if (dispatch) {
var tr = state.tr,
toUndo = undoable.transform;
for (var j = toUndo.steps.length - 1; j >= 0; j--) tr.step(toUndo.steps[j].invert(toUndo.docs[j]));
if (undoable.text) {
var marks = tr.doc.resolve(undoable.from).marks();
tr.replaceWith(undoable.from, undoable.to, state.schema.text(undoable.text, marks));
} else {
tr["delete"](undoable.from, undoable.to);
}
dispatch(tr);
}
return true;
}
}
return false;
};
var emDash = new InputRule(/--$/, "—");
var ellipsis = new InputRule(/\.\.\.$/, "…");
var openDoubleQuote = new InputRule(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(")$/, "“");
var closeDoubleQuote = new InputRule(/"$/, "”");
var openSingleQuote = new InputRule(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(')$/, "");
var closeSingleQuote = new InputRule(/'$/, "");
var smartQuotes = [openDoubleQuote, closeDoubleQuote, openSingleQuote, closeSingleQuote];
function wrappingInputRule(regexp, nodeType) {
var getAttrs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var joinPredicate = arguments.length > 3 ? arguments[3] : undefined;
return new InputRule(regexp, function (state, match, start, end) {
var attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
var tr = state.tr["delete"](start, end);
var $start = tr.doc.resolve(start),
range = $start.blockRange(),
wrapping = range && prosemirrorTransform.findWrapping(range, nodeType, attrs);
if (!wrapping) return null;
tr.wrap(range, wrapping);
var before = tr.doc.resolve(start - 1).nodeBefore;
if (before && before.type == nodeType && prosemirrorTransform.canJoin(tr.doc, start - 1) && (!joinPredicate || joinPredicate(match, before))) tr.join(start - 1);
return tr;
});
}
function textblockTypeInputRule(regexp, nodeType) {
var getAttrs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
return new InputRule(regexp, function (state, match, start, end) {
var $start = state.doc.resolve(start);
var attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)) return null;
return state.tr["delete"](start, end).setBlockType(start, start, nodeType, attrs);
});
}
exports.InputRule = InputRule;
exports.closeDoubleQuote = closeDoubleQuote;
exports.closeSingleQuote = closeSingleQuote;
exports.ellipsis = ellipsis;
exports.emDash = emDash;
exports.inputRules = inputRules;
exports.openDoubleQuote = openDoubleQuote;
exports.openSingleQuote = openSingleQuote;
exports.smartQuotes = smartQuotes;
exports.textblockTypeInputRule = textblockTypeInputRule;
exports.undoInputRule = undoInputRule;
exports.wrappingInputRule = wrappingInputRule;

View File

@@ -0,0 +1,124 @@
import { EditorState, Transaction, Plugin, Command } from 'prosemirror-state';
import { NodeType, Attrs, Node } from 'prosemirror-model';
/**
Input rules are regular expressions describing a piece of text
that, when typed, causes something to happen. This might be
changing two dashes into an emdash, wrapping a paragraph starting
with `"> "` into a blockquote, or something entirely different.
*/
declare class InputRule {
inCode: boolean | "only";
/**
Create an input rule. The rule applies when the user typed
something and the text directly in front of the cursor matches
`match`, which should end with `$`.
The `handler` can be a string, in which case the matched text, or
the first matched group in the regexp, is replaced by that
string.
Or a it can be a function, which will be called with the match
array produced by
[`RegExp.exec`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec),
as well as the start and end of the matched range, and which can
return a [transaction](https://prosemirror.net/docs/ref/#state.Transaction) that describes the
rule's effect, or null to indicate the input was not handled.
*/
constructor(
/**
@internal
*/
match: RegExp, handler: string | ((state: EditorState, match: RegExpMatchArray, start: number, end: number) => Transaction | null), options?: {
/**
When set to false,
[`undoInputRule`](https://prosemirror.net/docs/ref/#inputrules.undoInputRule) doesn't work on
this rule.
*/
undoable?: boolean;
/**
By default, input rules will not apply inside nodes marked
as [code](https://prosemirror.net/docs/ref/#model.NodeSpec.code). Set this to true to change
that, or to `"only"` to _only_ match in such nodes.
*/
inCode?: boolean | "only";
});
}
type PluginState = {
transform: Transaction;
from: number;
to: number;
text: string;
} | null;
/**
Create an input rules plugin. When enabled, it will cause text
input that matches any of the given rules to trigger the rule's
action.
*/
declare function inputRules({ rules }: {
rules: readonly InputRule[];
}): Plugin<PluginState>;
/**
This is a command that will undo an input rule, if applying such a
rule was the last thing that the user did.
*/
declare const undoInputRule: Command;
/**
Converts double dashes to an emdash.
*/
declare const emDash: InputRule;
/**
Converts three dots to an ellipsis character.
*/
declare const ellipsis: InputRule;
/**
“Smart” opening double quotes.
*/
declare const openDoubleQuote: InputRule;
/**
“Smart” closing double quotes.
*/
declare const closeDoubleQuote: InputRule;
/**
“Smart” opening single quotes.
*/
declare const openSingleQuote: InputRule;
/**
“Smart” closing single quotes.
*/
declare const closeSingleQuote: InputRule;
/**
Smart-quote related input rules.
*/
declare const smartQuotes: readonly InputRule[];
/**
Build an input rule for automatically wrapping a textblock when a
given string is typed. The `regexp` argument is
directly passed through to the `InputRule` constructor. You'll
probably want the regexp to start with `^`, so that the pattern can
only occur at the start of a textblock.
`nodeType` is the type of node to wrap in. If it needs attributes,
you can either pass them directly, or pass a function that will
compute them from the regular expression match.
By default, if there's a node with the same type above the newly
wrapped node, the rule will try to [join](https://prosemirror.net/docs/ref/#transform.Transform.join) those
two nodes. You can pass a join predicate, which takes a regular
expression match and the node before the wrapped node, and can
return a boolean to indicate whether a join should happen.
*/
declare function wrappingInputRule(regexp: RegExp, nodeType: NodeType, getAttrs?: Attrs | null | ((matches: RegExpMatchArray) => Attrs | null), joinPredicate?: (match: RegExpMatchArray, node: Node) => boolean): InputRule;
/**
Build an input rule that changes the type of a textblock when the
matched text is typed into it. You'll usually want to start your
regexp with `^` to that it is only matched at the start of a
textblock. The optional `getAttrs` parameter can be used to compute
the new node's attributes, and works the same as in the
`wrappingInputRule` function.
*/
declare function textblockTypeInputRule(regexp: RegExp, nodeType: NodeType, getAttrs?: Attrs | null | ((match: RegExpMatchArray) => Attrs | null)): InputRule;
export { InputRule, closeDoubleQuote, closeSingleQuote, ellipsis, emDash, inputRules, openDoubleQuote, openSingleQuote, smartQuotes, textblockTypeInputRule, undoInputRule, wrappingInputRule };

View File

@@ -0,0 +1,225 @@
import { Plugin } from 'prosemirror-state';
import { findWrapping, canJoin } from 'prosemirror-transform';
/**
Input rules are regular expressions describing a piece of text
that, when typed, causes something to happen. This might be
changing two dashes into an emdash, wrapping a paragraph starting
with `"> "` into a blockquote, or something entirely different.
*/
class InputRule {
// :: (RegExp, union<string, (state: EditorState, match: [string], start: number, end: number) → ?Transaction>)
/**
Create an input rule. The rule applies when the user typed
something and the text directly in front of the cursor matches
`match`, which should end with `$`.
The `handler` can be a string, in which case the matched text, or
the first matched group in the regexp, is replaced by that
string.
Or a it can be a function, which will be called with the match
array produced by
[`RegExp.exec`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec),
as well as the start and end of the matched range, and which can
return a [transaction](https://prosemirror.net/docs/ref/#state.Transaction) that describes the
rule's effect, or null to indicate the input was not handled.
*/
constructor(
/**
@internal
*/
match, handler, options = {}) {
this.match = match;
this.match = match;
this.handler = typeof handler == "string" ? stringHandler(handler) : handler;
this.undoable = options.undoable !== false;
this.inCode = options.inCode || false;
}
}
function stringHandler(string) {
return function (state, match, start, end) {
let insert = string;
if (match[1]) {
let offset = match[0].lastIndexOf(match[1]);
insert += match[0].slice(offset + match[1].length);
start += offset;
let cutOff = start - end;
if (cutOff > 0) {
insert = match[0].slice(offset - cutOff, offset) + insert;
start = end;
}
}
return state.tr.insertText(insert, start, end);
};
}
const MAX_MATCH = 500;
/**
Create an input rules plugin. When enabled, it will cause text
input that matches any of the given rules to trigger the rule's
action.
*/
function inputRules({ rules }) {
let plugin = new Plugin({
state: {
init() { return null; },
apply(tr, prev) {
let stored = tr.getMeta(this);
if (stored)
return stored;
return tr.selectionSet || tr.docChanged ? null : prev;
}
},
props: {
handleTextInput(view, from, to, text) {
return run(view, from, to, text, rules, plugin);
},
handleDOMEvents: {
compositionend: (view) => {
setTimeout(() => {
let { $cursor } = view.state.selection;
if ($cursor)
run(view, $cursor.pos, $cursor.pos, "", rules, plugin);
});
}
}
},
isInputRules: true
});
return plugin;
}
function run(view, from, to, text, rules, plugin) {
if (view.composing)
return false;
let state = view.state, $from = state.doc.resolve(from);
let textBefore = $from.parent.textBetween(Math.max(0, $from.parentOffset - MAX_MATCH), $from.parentOffset, null, "\ufffc") + text;
for (let i = 0; i < rules.length; i++) {
let rule = rules[i];
if ($from.parent.type.spec.code) {
if (!rule.inCode)
continue;
}
else if (rule.inCode === "only") {
continue;
}
let match = rule.match.exec(textBefore);
let tr = match && rule.handler(state, match, from - (match[0].length - text.length), to);
if (!tr)
continue;
if (rule.undoable)
tr.setMeta(plugin, { transform: tr, from, to, text });
view.dispatch(tr);
return true;
}
return false;
}
/**
This is a command that will undo an input rule, if applying such a
rule was the last thing that the user did.
*/
const undoInputRule = (state, dispatch) => {
let plugins = state.plugins;
for (let i = 0; i < plugins.length; i++) {
let plugin = plugins[i], undoable;
if (plugin.spec.isInputRules && (undoable = plugin.getState(state))) {
if (dispatch) {
let tr = state.tr, toUndo = undoable.transform;
for (let j = toUndo.steps.length - 1; j >= 0; j--)
tr.step(toUndo.steps[j].invert(toUndo.docs[j]));
if (undoable.text) {
let marks = tr.doc.resolve(undoable.from).marks();
tr.replaceWith(undoable.from, undoable.to, state.schema.text(undoable.text, marks));
}
else {
tr.delete(undoable.from, undoable.to);
}
dispatch(tr);
}
return true;
}
}
return false;
};
/**
Converts double dashes to an emdash.
*/
const emDash = new InputRule(/--$/, "—");
/**
Converts three dots to an ellipsis character.
*/
const ellipsis = new InputRule(/\.\.\.$/, "…");
/**
“Smart” opening double quotes.
*/
const openDoubleQuote = new InputRule(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(")$/, "“");
/**
“Smart” closing double quotes.
*/
const closeDoubleQuote = new InputRule(/"$/, "”");
/**
“Smart” opening single quotes.
*/
const openSingleQuote = new InputRule(/(?:^|[\s\{\[\(\<'"\u2018\u201C])(')$/, "");
/**
“Smart” closing single quotes.
*/
const closeSingleQuote = new InputRule(/'$/, "");
/**
Smart-quote related input rules.
*/
const smartQuotes = [openDoubleQuote, closeDoubleQuote, openSingleQuote, closeSingleQuote];
/**
Build an input rule for automatically wrapping a textblock when a
given string is typed. The `regexp` argument is
directly passed through to the `InputRule` constructor. You'll
probably want the regexp to start with `^`, so that the pattern can
only occur at the start of a textblock.
`nodeType` is the type of node to wrap in. If it needs attributes,
you can either pass them directly, or pass a function that will
compute them from the regular expression match.
By default, if there's a node with the same type above the newly
wrapped node, the rule will try to [join](https://prosemirror.net/docs/ref/#transform.Transform.join) those
two nodes. You can pass a join predicate, which takes a regular
expression match and the node before the wrapped node, and can
return a boolean to indicate whether a join should happen.
*/
function wrappingInputRule(regexp, nodeType, getAttrs = null, joinPredicate) {
return new InputRule(regexp, (state, match, start, end) => {
let attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
let tr = state.tr.delete(start, end);
let $start = tr.doc.resolve(start), range = $start.blockRange(), wrapping = range && findWrapping(range, nodeType, attrs);
if (!wrapping)
return null;
tr.wrap(range, wrapping);
let before = tr.doc.resolve(start - 1).nodeBefore;
if (before && before.type == nodeType && canJoin(tr.doc, start - 1) &&
(!joinPredicate || joinPredicate(match, before)))
tr.join(start - 1);
return tr;
});
}
/**
Build an input rule that changes the type of a textblock when the
matched text is typed into it. You'll usually want to start your
regexp with `^` to that it is only matched at the start of a
textblock. The optional `getAttrs` parameter can be used to compute
the new node's attributes, and works the same as in the
`wrappingInputRule` function.
*/
function textblockTypeInputRule(regexp, nodeType, getAttrs = null) {
return new InputRule(regexp, (state, match, start, end) => {
let $start = state.doc.resolve(start);
let attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType))
return null;
return state.tr
.delete(start, end)
.setBlockType(start, start, nodeType, attrs);
});
}
export { InputRule, closeDoubleQuote, closeSingleQuote, ellipsis, emDash, inputRules, openDoubleQuote, openSingleQuote, smartQuotes, textblockTypeInputRule, undoInputRule, wrappingInputRule };