index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. import { PluginKey, Plugin, NodeSelection } from 'prosemirror-state';
  2. import { InputRule } from 'prosemirror-inputrules';
  3. import { expectDomTypeError, missingRootElement, getAtomFromSchemaFail } from '@milkdown/exception';
  4. const nav = typeof navigator != "undefined" ? navigator : null;
  5. const doc = typeof document != "undefined" ? document : null;
  6. const agent = nav && nav.userAgent || "";
  7. const ie_edge = /Edge\/(\d+)/.exec(agent);
  8. const ie_upto10 = /MSIE \d/.exec(agent);
  9. const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent);
  10. const ie = !!(ie_upto10 || ie_11up || ie_edge);
  11. const ie_version = ie_upto10 ? document.documentMode : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0;
  12. const gecko = !ie && /gecko\/(\d+)/i.test(agent);
  13. const gecko_version = gecko && +(/Firefox\/(\d+)/.exec(agent) || [0, 0])[1];
  14. const _chrome = !ie && /Chrome\/(\d+)/.exec(agent);
  15. const chrome = !!_chrome;
  16. const chrome_version = _chrome ? +_chrome[1] : 0;
  17. const safari = !ie && !!nav && /Apple Computer/.test(nav.vendor);
  18. const ios = safari && (/Mobile\/\w+/.test(agent) || !!nav && nav.maxTouchPoints > 2);
  19. const mac = ios || (nav ? /Mac/.test(nav.platform) : false);
  20. const android = /Android \d/.test(agent);
  21. const webkit = !!doc && "webkitFontSmoothing" in doc.documentElement.style;
  22. const webkit_version = webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0;
  23. var browser = /*#__PURE__*/Object.freeze({
  24. __proto__: null,
  25. android: android,
  26. chrome: chrome,
  27. chrome_version: chrome_version,
  28. gecko: gecko,
  29. gecko_version: gecko_version,
  30. ie: ie,
  31. ie_version: ie_version,
  32. ios: ios,
  33. mac: mac,
  34. safari: safari,
  35. webkit: webkit,
  36. webkit_version: webkit_version
  37. });
  38. function run(view, from, to, text, rules, plugin) {
  39. if (view.composing)
  40. return false;
  41. const state = view.state;
  42. const $from = state.doc.resolve(from);
  43. if ($from.parent.type.spec.code)
  44. return false;
  45. const textBefore = $from.parent.textBetween(Math.max(0, $from.parentOffset - 500), $from.parentOffset, void 0, "\uFFFC") + text;
  46. for (let i = 0; i < rules.length; i++) {
  47. const match = rules[i].match.exec(textBefore);
  48. const tr = match && match[0] && rules[i].handler(state, match, from - (match[0].length - text.length), to);
  49. if (!tr)
  50. continue;
  51. view.dispatch(tr.setMeta(plugin, { transform: tr, from, to, text }));
  52. return true;
  53. }
  54. return false;
  55. }
  56. const customInputRulesKey = new PluginKey("MILKDOWN_CUSTOM_INPUTRULES");
  57. function customInputRules({ rules }) {
  58. const plugin = new Plugin({
  59. key: customInputRulesKey,
  60. isInputRules: true,
  61. state: {
  62. init() {
  63. return null;
  64. },
  65. apply(tr, prev) {
  66. const stored = tr.getMeta(this);
  67. if (stored)
  68. return stored;
  69. return tr.selectionSet || tr.docChanged ? null : prev;
  70. }
  71. },
  72. props: {
  73. handleTextInput(view, from, to, text) {
  74. return run(view, from, to, text, rules, plugin);
  75. },
  76. handleDOMEvents: {
  77. compositionend: (view) => {
  78. setTimeout(() => {
  79. const { $cursor } = view.state.selection;
  80. if ($cursor)
  81. run(view, $cursor.pos, $cursor.pos, "", rules, plugin);
  82. });
  83. return false;
  84. }
  85. },
  86. handleKeyDown(view, event) {
  87. if (event.key !== "Enter")
  88. return false;
  89. const { $cursor } = view.state.selection;
  90. if ($cursor)
  91. return run(view, $cursor.pos, $cursor.pos, "\n", rules, plugin);
  92. return false;
  93. }
  94. }
  95. });
  96. return plugin;
  97. }
  98. function markRule(regexp, markType, options = {}) {
  99. return new InputRule(regexp, (state, match, start, end) => {
  100. var _a, _b, _c, _d;
  101. const { tr } = state;
  102. const matchLength = match.length;
  103. let group = match[matchLength - 1];
  104. let fullMatch = match[0];
  105. let initialStoredMarks = [];
  106. let markEnd = end;
  107. const captured = {
  108. group,
  109. fullMatch,
  110. start,
  111. end
  112. };
  113. const result = (_a = options.updateCaptured) == null ? void 0 : _a.call(options, captured);
  114. Object.assign(captured, result);
  115. ({ group, fullMatch, start, end } = captured);
  116. if (fullMatch === null)
  117. return null;
  118. if ((group == null ? void 0 : group.trim()) === "")
  119. return null;
  120. if (group) {
  121. const startSpaces = fullMatch.search(/\S/);
  122. const textStart = start + fullMatch.indexOf(group);
  123. const textEnd = textStart + group.length;
  124. initialStoredMarks = (_b = tr.storedMarks) != null ? _b : [];
  125. if (textEnd < end)
  126. tr.delete(textEnd, end);
  127. if (textStart > start)
  128. tr.delete(start + startSpaces, textStart);
  129. markEnd = start + startSpaces + group.length;
  130. const attrs = (_c = options.getAttr) == null ? void 0 : _c.call(options, match);
  131. tr.addMark(start, markEnd, markType.create(attrs));
  132. tr.setStoredMarks(initialStoredMarks);
  133. (_d = options.beforeDispatch) == null ? void 0 : _d.call(options, { match, start, end, tr });
  134. }
  135. return tr;
  136. });
  137. }
  138. function nodeRule(regexp, nodeType, options = {}) {
  139. return new InputRule(regexp, (state, match, start, end) => {
  140. var _a, _b, _c;
  141. const { tr } = state;
  142. let group = match[1];
  143. let fullMatch = match[0];
  144. const captured = {
  145. group,
  146. fullMatch,
  147. start,
  148. end
  149. };
  150. const result = (_a = options.updateCaptured) == null ? void 0 : _a.call(options, captured);
  151. Object.assign(captured, result);
  152. ({ group, fullMatch, start, end } = captured);
  153. if (fullMatch === null)
  154. return null;
  155. if (!group || group.trim() === "")
  156. return null;
  157. const attrs = (_b = options.getAttr) == null ? void 0 : _b.call(options, match);
  158. const node = nodeType.createAndFill(attrs);
  159. if (node) {
  160. tr.replaceRangeWith(nodeType.isBlock ? tr.doc.resolve(start).before() : start, end, node);
  161. (_c = options.beforeDispatch) == null ? void 0 : _c.call(options, { match: [fullMatch, group != null ? group : ""], start, end, tr });
  162. }
  163. return tr;
  164. });
  165. }
  166. var __defProp = Object.defineProperty;
  167. var __defProps = Object.defineProperties;
  168. var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
  169. var __getOwnPropSymbols = Object.getOwnPropertySymbols;
  170. var __hasOwnProp = Object.prototype.hasOwnProperty;
  171. var __propIsEnum = Object.prototype.propertyIsEnumerable;
  172. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  173. var __spreadValues = (a, b) => {
  174. for (var prop in b || (b = {}))
  175. if (__hasOwnProp.call(b, prop))
  176. __defNormalProp(a, prop, b[prop]);
  177. if (__getOwnPropSymbols)
  178. for (var prop of __getOwnPropSymbols(b)) {
  179. if (__propIsEnum.call(b, prop))
  180. __defNormalProp(a, prop, b[prop]);
  181. }
  182. return a;
  183. };
  184. var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
  185. function calculateNodePosition(view, target, handler) {
  186. const state = view.state;
  187. const { from } = state.selection;
  188. const { node } = view.domAtPos(from);
  189. const element = node instanceof Text ? node.parentElement : node;
  190. if (!(element instanceof HTMLElement))
  191. throw expectDomTypeError(element);
  192. const selectedNodeRect = element.getBoundingClientRect();
  193. const targetNodeRect = target.getBoundingClientRect();
  194. const parent = target.parentElement;
  195. if (!parent)
  196. throw expectDomTypeError(parent);
  197. const parentNodeRect = parent.getBoundingClientRect();
  198. const [top, left] = handler(selectedNodeRect, targetNodeRect, parentNodeRect);
  199. target.style.top = `${top}px`;
  200. target.style.left = `${left}px`;
  201. }
  202. function calculateTextPosition(view, target, handler) {
  203. const state = view.state;
  204. const { from, to } = state.selection;
  205. const start = view.coordsAtPos(from);
  206. const end = view.coordsAtPos(to);
  207. const targetNodeRect = target.getBoundingClientRect();
  208. const parent = target.parentElement;
  209. if (!parent)
  210. throw missingRootElement();
  211. const parentNodeRect = parent.getBoundingClientRect();
  212. const [top, left] = handler(start, end, targetNodeRect, parentNodeRect);
  213. target.style.top = `${top}px`;
  214. target.style.left = `${left}px`;
  215. }
  216. function minMax(value = 0, min = 0, max = 0) {
  217. return Math.min(Math.max(value, min), max);
  218. }
  219. function posToDOMRect(view, from, to) {
  220. const minPos = 0;
  221. const maxPos = view.state.doc.content.size;
  222. const resolvedFrom = minMax(from, minPos, maxPos);
  223. const resolvedEnd = minMax(to, minPos, maxPos);
  224. const start = view.coordsAtPos(resolvedFrom);
  225. const end = view.coordsAtPos(resolvedEnd, -1);
  226. const top = Math.min(start.top, end.top);
  227. const bottom = Math.max(start.bottom, end.bottom);
  228. const left = Math.min(start.left, end.left);
  229. const right = Math.max(start.right, end.right);
  230. const width = right - left;
  231. const height = bottom - top;
  232. const x = left;
  233. const y = top;
  234. const data = {
  235. top,
  236. bottom,
  237. left,
  238. right,
  239. width,
  240. height,
  241. x,
  242. y
  243. };
  244. return __spreadProps(__spreadValues({}, data), {
  245. toJSON: () => data
  246. });
  247. }
  248. function cloneTr(tr) {
  249. return Object.assign(Object.create(tr), tr).setTime(Date.now());
  250. }
  251. function equalNodeType(nodeType, node) {
  252. return Array.isArray(nodeType) && nodeType.includes(node.type) || node.type === nodeType;
  253. }
  254. function flatten(node, descend = true) {
  255. const result = [];
  256. node.descendants((child, pos) => {
  257. result.push({ node: child, pos });
  258. if (!descend)
  259. return false;
  260. return void 0;
  261. });
  262. return result;
  263. }
  264. function findChildren(predicate) {
  265. return (node, descend) => flatten(node, descend).filter((child) => predicate(child.node));
  266. }
  267. function findChildrenByMark(node, markType, descend) {
  268. return findChildren((child) => Boolean(markType.isInSet(child.marks)))(node, descend);
  269. }
  270. function getNodeFromSchema(type, schema) {
  271. const target = schema.nodes[type];
  272. if (!target)
  273. throw getAtomFromSchemaFail("node", type);
  274. return target;
  275. }
  276. function getMarkFromSchema(type, schema) {
  277. const target = schema.marks[type];
  278. if (!target)
  279. throw getAtomFromSchemaFail("mark", type);
  280. return target;
  281. }
  282. function findParentNodeClosestToPos(predicate) {
  283. return ($pos) => {
  284. for (let i = $pos.depth; i > 0; i--) {
  285. const node = $pos.node(i);
  286. if (predicate(node)) {
  287. return {
  288. pos: i > 0 ? $pos.before(i) : 0,
  289. start: $pos.start(i),
  290. depth: i,
  291. node
  292. };
  293. }
  294. }
  295. return void 0;
  296. };
  297. }
  298. function findParentNode(predicate) {
  299. return (selection) => {
  300. return findParentNodeClosestToPos(predicate)(selection.$from);
  301. };
  302. }
  303. function findSelectedNodeOfType(selection, nodeType) {
  304. if (!(selection instanceof NodeSelection))
  305. return;
  306. const { node, $from } = selection;
  307. if (equalNodeType(nodeType, node))
  308. return { node, pos: $from.pos, start: $from.start($from.depth), depth: $from.depth };
  309. return void 0;
  310. }
  311. export { browser, calculateNodePosition, calculateTextPosition, cloneTr, customInputRules, customInputRulesKey, equalNodeType, findChildren, findChildrenByMark, findParentNode, findParentNodeClosestToPos, findSelectedNodeOfType, flatten, getMarkFromSchema, getNodeFromSchema, markRule, nodeRule, posToDOMRect };
  312. //# sourceMappingURL=index.js.map