@domternal/core 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4066,16 +4066,50 @@ var Editor = class _Editor extends EventEmitter {
4066
4066
  return super.emit(event, ...args);
4067
4067
  }
4068
4068
  };
4069
- function positionFloating(reference, floating, options) {
4070
- const placementOpt = options?.placement ?? "bottom";
4069
+ var OPPOSITE_SIDE = {
4070
+ top: "bottom",
4071
+ bottom: "top",
4072
+ left: "right",
4073
+ right: "left"
4074
+ };
4075
+ function oppositePlacement(placement) {
4076
+ const [side = "", alignment] = placement.split("-");
4077
+ const opposite = OPPOSITE_SIDE[side] ?? side;
4078
+ return alignment ? `${opposite}-${alignment}` : opposite;
4079
+ }
4080
+ function buildMiddleware(options, placementOpt) {
4071
4081
  const paddingOpt = options?.padding ?? 10;
4072
4082
  const overflowOpts = options?.boundary ? { padding: paddingOpt, boundary: options.boundary } : { padding: paddingOpt };
4073
- const middleware = [
4074
- dom.offset(options?.offsetValue ?? 4),
4075
- dom.flip(overflowOpts),
4076
- dom.shift(overflowOpts),
4077
- dom.hide()
4078
- ];
4083
+ const constrain = options?.constrainHeight;
4084
+ const middleware = [dom.offset(options?.offsetValue ?? 4)];
4085
+ if (constrain) {
4086
+ middleware.push(
4087
+ dom.size({
4088
+ ...overflowOpts,
4089
+ apply({ availableHeight, elements }) {
4090
+ elements.floating.style.setProperty(
4091
+ "--dm-available-height",
4092
+ `${String(Math.max(constrain.minHeight, Math.floor(availableHeight)))}px`
4093
+ );
4094
+ }
4095
+ })
4096
+ );
4097
+ middleware.push(
4098
+ dom.flip({
4099
+ ...overflowOpts,
4100
+ crossAxis: false,
4101
+ fallbackPlacements: [oppositePlacement(placementOpt)]
4102
+ })
4103
+ );
4104
+ } else {
4105
+ middleware.push(dom.flip(overflowOpts));
4106
+ }
4107
+ middleware.push(dom.shift(overflowOpts));
4108
+ return middleware;
4109
+ }
4110
+ function positionFloating(reference, floating, options) {
4111
+ const placementOpt = options?.placement ?? "bottom";
4112
+ const middleware = [...buildMiddleware(options, placementOpt), dom.hide()];
4079
4113
  const update = () => {
4080
4114
  void dom.computePosition(
4081
4115
  reference,
@@ -4103,13 +4137,7 @@ function positionFloating(reference, floating, options) {
4103
4137
  }
4104
4138
  function positionFloatingOnce(reference, floating, options) {
4105
4139
  const placementOpt = options?.placement ?? "bottom";
4106
- const paddingOpt = options?.padding ?? 10;
4107
- const overflowOpts = options?.boundary ? { padding: paddingOpt, boundary: options.boundary } : { padding: paddingOpt };
4108
- const middleware = [
4109
- dom.offset(options?.offsetValue ?? 4),
4110
- dom.flip(overflowOpts),
4111
- dom.shift(overflowOpts)
4112
- ];
4140
+ const middleware = buildMiddleware(options, placementOpt);
4113
4141
  const update = () => {
4114
4142
  void dom.computePosition(
4115
4143
  reference,
@@ -4701,6 +4729,7 @@ var ToolbarController = class _ToolbarController {
4701
4729
  * Executes a toolbar button's command.
4702
4730
  */
4703
4731
  executeCommand(item) {
4732
+ if (!this.editor.isEditable && item.allowReadOnly !== true) return;
4704
4733
  _ToolbarController.executeItem(this.editor, item);
4705
4734
  this.updateActiveStates();
4706
4735
  }
@@ -4943,16 +4972,20 @@ var ToolbarController = class _ToolbarController {
4943
4972
  checkButtonDisabled(item, canProxy) {
4944
4973
  const wasDisabled = this._disabledMap.get(item.name) ?? false;
4945
4974
  let nowDisabled = false;
4946
- try {
4947
- if (item.emitEvent) {
4948
- nowDisabled = this.editor.isActive("codeBlock");
4949
- } else if (canProxy) {
4950
- const canCmd = canProxy[item.command];
4951
- if (canCmd) {
4952
- nowDisabled = item.commandArgs?.length ? !canCmd(...item.commandArgs) : !canCmd();
4975
+ if (!this.editor.isEditable && item.allowReadOnly !== true) {
4976
+ nowDisabled = true;
4977
+ } else {
4978
+ try {
4979
+ if (item.emitEvent) {
4980
+ nowDisabled = this.editor.isActive("codeBlock");
4981
+ } else if (canProxy) {
4982
+ const canCmd = canProxy[item.command];
4983
+ if (canCmd) {
4984
+ nowDisabled = item.commandArgs?.length ? !canCmd(...item.commandArgs) : !canCmd();
4985
+ }
4953
4986
  }
4987
+ } catch {
4954
4988
  }
4955
- } catch {
4956
4989
  }
4957
4990
  if (wasDisabled !== nowDisabled) {
4958
4991
  this._disabledMap.set(item.name, nowDisabled);
@@ -5364,6 +5397,7 @@ function createFloatingMenuPlugin(options) {
5364
5397
  };
5365
5398
  hideMenu();
5366
5399
  const isVisibleNow = (view) => {
5400
+ if (!editor.isEditable) return false;
5367
5401
  const wantsShow = shouldShow({ editor, view, state: view.state });
5368
5402
  if (!requireExplicitTrigger) return wantsShow;
5369
5403
  const triggered = pluginKey.getState(view.state)?.triggered ?? false;
@@ -5743,7 +5777,8 @@ var Heading = Node2.create({
5743
5777
  key: new state.PluginKey("headingKeydownFix"),
5744
5778
  props: {
5745
5779
  handleDOMEvents: {
5746
- keydown(_view, event) {
5780
+ keydown(view, event) {
5781
+ if (!view.editable) return false;
5747
5782
  if (!event.altKey || !(event.metaKey || event.ctrlKey)) return false;
5748
5783
  const level = codeToLevel[event.code];
5749
5784
  if (level === void 0) return false;
@@ -8822,7 +8857,13 @@ var UniqueID = Extension.create({
8822
8857
  "listItem",
8823
8858
  "taskItem",
8824
8859
  "image",
8825
- "horizontalRule"
8860
+ "horizontalRule",
8861
+ // Listed even though it lives in a separate package, exactly as
8862
+ // `image` already is: a global attribute only installs on types the
8863
+ // schema actually has, so naming it is inert when the table extension
8864
+ // is not loaded. Without it a table is the one block the block menu
8865
+ // cannot Copy link, and the one an id-anchored feature cannot address.
8866
+ "table"
8826
8867
  ],
8827
8868
  attributeName: "id",
8828
8869
  generateID: generateUUID,
@@ -8850,7 +8891,8 @@ var UniqueID = Extension.create({
8850
8891
  addProseMirrorPlugins() {
8851
8892
  const { types, attributeName, generateID, filterDuplicates } = this.options;
8852
8893
  const editor = this.editor;
8853
- const transformPastedSlice = (slice) => {
8894
+ const transformPastedSlice = (slice, view) => {
8895
+ if (view?.dragging?.move === true) return slice;
8854
8896
  const existingIDs = /* @__PURE__ */ new Set();
8855
8897
  editor?.state.doc.descendants((node) => {
8856
8898
  const id = node.attrs[attributeName];
@@ -8884,7 +8926,36 @@ var UniqueID = Extension.create({
8884
8926
  slice.openEnd
8885
8927
  );
8886
8928
  };
8887
- const assignMissingIDs = (doc, tr) => {
8929
+ const incumbentPositions = (oldDoc, mapPos) => {
8930
+ const incumbents = /* @__PURE__ */ new Map();
8931
+ oldDoc.descendants((node, pos) => {
8932
+ if (!types.includes(node.type.name)) return;
8933
+ const id = node.attrs[attributeName];
8934
+ if (id && !incumbents.has(id)) incumbents.set(id, mapPos(pos));
8935
+ });
8936
+ return incumbents;
8937
+ };
8938
+ const assignMissingIDs = (doc, tr, incumbents) => {
8939
+ const winners = /* @__PURE__ */ new Map();
8940
+ if (incumbents && incumbents.size > 0) {
8941
+ const occurrences = /* @__PURE__ */ new Map();
8942
+ doc.descendants((node, pos) => {
8943
+ if (!types.includes(node.type.name)) return;
8944
+ const id = node.attrs[attributeName];
8945
+ if (!id) return;
8946
+ const list = occurrences.get(id);
8947
+ if (list) list.push(pos);
8948
+ else occurrences.set(id, [pos]);
8949
+ });
8950
+ for (const [id, positions] of occurrences) {
8951
+ if (positions.length < 2) continue;
8952
+ const incumbentPos = incumbents.get(id);
8953
+ winners.set(
8954
+ id,
8955
+ incumbentPos !== void 0 && positions.includes(incumbentPos) ? incumbentPos : positions[0]
8956
+ );
8957
+ }
8958
+ }
8888
8959
  const seen = /* @__PURE__ */ new Set();
8889
8960
  doc.descendants((node, pos) => {
8890
8961
  if (!types.includes(node.type.name)) return;
@@ -8899,7 +8970,9 @@ var UniqueID = Extension.create({
8899
8970
  });
8900
8971
  return;
8901
8972
  }
8902
- if (seen.has(existingID)) {
8973
+ const winner = winners.get(existingID);
8974
+ const yieldsToWinner = winner !== void 0 && winner !== pos;
8975
+ if (seen.has(existingID) || yieldsToWinner) {
8903
8976
  let id = generateID();
8904
8977
  while (seen.has(id)) id = generateID();
8905
8978
  seen.add(id);
@@ -8921,6 +8994,7 @@ var UniqueID = Extension.create({
8921
8994
  const tr = editorView.state.tr;
8922
8995
  assignMissingIDs(editorView.state.doc, tr);
8923
8996
  if (tr.docChanged) {
8997
+ tr.setMeta("addToHistory", false);
8924
8998
  editorView.dispatch(tr);
8925
8999
  }
8926
9000
  }, 0);
@@ -8931,12 +9005,18 @@ var UniqueID = Extension.create({
8931
9005
  };
8932
9006
  },
8933
9007
  // Ensure new nodes get IDs
8934
- appendTransaction(transactions, _oldState, newState) {
9008
+ appendTransaction(transactions, oldState, newState) {
8935
9009
  const docChanged = transactions.some((tr2) => tr2.docChanged);
8936
9010
  if (!docChanged) return null;
9011
+ const mapForward = (pos) => transactions.reduce((p, transaction) => transaction.mapping.map(p), pos);
8937
9012
  const tr = newState.tr;
8938
- assignMissingIDs(newState.doc, tr);
8939
- return tr.docChanged ? tr : null;
9013
+ assignMissingIDs(newState.doc, tr, incumbentPositions(oldState.doc, mapForward));
9014
+ if (!tr.docChanged) return null;
9015
+ const ridesAlongWithAnEdit = transactions.some(
9016
+ (transaction) => transaction.docChanged && transaction.getMeta("addToHistory") !== false
9017
+ );
9018
+ if (!ridesAlongWithAnEdit) tr.setMeta("addToHistory", false);
9019
+ return tr;
8940
9020
  },
8941
9021
  // Handle paste - filter duplicates
8942
9022
  props: filterDuplicates ? {
@@ -9905,14 +9985,14 @@ var FontSize = Extension.create({
9905
9985
  addToolbarItems() {
9906
9986
  if (this.options.fontSizes.length === 0) return [];
9907
9987
  const sizes = this.options.fontSizes;
9908
- const items = sizes.map((size, i) => ({
9988
+ const items = sizes.map((size2, i) => ({
9909
9989
  type: "button",
9910
- name: `fontSize-${size}`,
9990
+ name: `fontSize-${size2}`,
9911
9991
  command: "setFontSize",
9912
- commandArgs: [size],
9913
- isActive: { name: "textStyle", attributes: { fontSize: size } },
9992
+ commandArgs: [size2],
9993
+ isActive: { name: "textStyle", attributes: { fontSize: size2 } },
9914
9994
  icon: "textSize",
9915
- label: size,
9995
+ label: size2,
9916
9996
  priority: 200 - i
9917
9997
  }));
9918
9998
  if (this.options.showReset) {
@@ -10376,7 +10456,7 @@ function createBubbleMenuPlugin(options) {
10376
10456
  if (from !== prevValue.from || to !== prevValue.to) {
10377
10457
  suppressed = false;
10378
10458
  }
10379
- const visible = !suppressed && !selection.empty && shouldShow({
10459
+ const visible = !suppressed && !selection.empty && editor.isEditable && shouldShow({
10380
10460
  editor,
10381
10461
  view: editor.view,
10382
10462
  state: newState,
@@ -10416,7 +10496,7 @@ function createBubbleMenuPlugin(options) {
10416
10496
  if (mouseDown) return;
10417
10497
  const { selection } = editor.view.state;
10418
10498
  const { from, to } = selection;
10419
- const show = !selection.empty && shouldShow({
10499
+ const show = !selection.empty && editor.isEditable && shouldShow({
10420
10500
  editor,
10421
10501
  view: editor.view,
10422
10502
  state: editor.view.state,
@@ -10452,6 +10532,10 @@ function createBubbleMenuPlugin(options) {
10452
10532
  return {
10453
10533
  update: (view, prevState) => {
10454
10534
  if (view.composing) return;
10535
+ if (!view.editable) {
10536
+ hideMenu();
10537
+ return;
10538
+ }
10455
10539
  const state = pluginKey.getState(view.state);
10456
10540
  const prevPluginState = pluginKey.getState(prevState);
10457
10541
  if (state?.visible === prevPluginState?.visible && state?.from === prevPluginState?.from && state?.to === prevPluginState?.to && !(state?.visible && view.state.doc !== prevState.doc)) {
@@ -10584,7 +10668,7 @@ var StarterKit = Extension.create({
10584
10668
  });
10585
10669
 
10586
10670
  // src/index.ts
10587
- var VERSION = "0.1.0";
10671
+ var VERSION = "0.14.0";
10588
10672
 
10589
10673
  Object.defineProperty(exports, "PluginKey", {
10590
10674
  enumerable: true,