@sendbird/actionbook-core 0.10.6 → 0.10.7

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.
@@ -61,6 +61,7 @@ type HeadingNode = {
61
61
  type ListItemNode = {
62
62
  readonly type: 'listItem';
63
63
  readonly checked?: boolean | null;
64
+ readonly value?: number | null;
64
65
  readonly spread?: boolean;
65
66
  readonly content: readonly BlockNode[];
66
67
  };
@@ -3,7 +3,7 @@ import { Plugin, Command, EditorState, PluginKey } from 'prosemirror-state';
3
3
  import { InputRule } from 'prosemirror-inputrules';
4
4
  import { EditorView, Decoration, NodeView } from 'prosemirror-view';
5
5
  import React$1, { ReactElement, RefCallback } from 'react';
6
- import { D as DocumentNode, A as AstNode, t as LlmCompletionEndpoint, I as InlineNode, B as BlockNode, v as JSONContent } from '../types-DK_GhIWZ.js';
6
+ import { D as DocumentNode, A as AstNode, t as LlmCompletionEndpoint, I as InlineNode, B as BlockNode, v as JSONContent } from '../types-BQ95zx4j.js';
7
7
 
8
8
  /**
9
9
  * ProseMirror Schema for Actionbook documents.
package/dist/ui/index.js CHANGED
@@ -55,7 +55,7 @@ var actionbookSchema = new Schema({
55
55
  },
56
56
  listItem: {
57
57
  content: "block+",
58
- attrs: { checked: { default: null } },
58
+ attrs: { checked: { default: null }, value: { default: null } },
59
59
  parseDOM: [
60
60
  {
61
61
  tag: "li",
@@ -63,20 +63,25 @@ var actionbookSchema = new Schema({
63
63
  const el = dom;
64
64
  const checkbox = el.querySelector('input[type="checkbox"]');
65
65
  if (checkbox) {
66
- return { checked: checkbox.checked };
66
+ return { checked: checkbox.checked, value: el.value || null };
67
67
  }
68
68
  if (el.dataset.checked != null) {
69
- return { checked: el.dataset.checked === "true" };
69
+ return { checked: el.dataset.checked === "true", value: el.value || null };
70
70
  }
71
- return { checked: null };
71
+ return { checked: null, value: el.value || null };
72
72
  }
73
73
  }
74
74
  ],
75
75
  toDOM(node) {
76
+ const liAttrs = {};
76
77
  if (node.attrs.checked != null) {
77
- return ["li", { class: "todo-item", "data-checked": String(node.attrs.checked) }, 0];
78
+ liAttrs.class = "todo-item";
79
+ liAttrs["data-checked"] = String(node.attrs.checked);
78
80
  }
79
- return ["li", 0];
81
+ if (node.attrs.value != null) {
82
+ liAttrs.value = String(node.attrs.value);
83
+ }
84
+ return Object.keys(liAttrs).length > 0 ? ["li", liAttrs, 0] : ["li", 0];
80
85
  },
81
86
  defining: true
82
87
  },
@@ -1425,6 +1430,10 @@ function convertPMListItem(node, depth = 0) {
1425
1430
  if (typeof checked === "boolean") {
1426
1431
  base.checked = checked;
1427
1432
  }
1433
+ const value = node.attrs?.value;
1434
+ if (value != null) {
1435
+ base.value = value;
1436
+ }
1428
1437
  return base;
1429
1438
  }
1430
1439
  function fromProseMirrorJSON(pmJSON) {
@@ -2320,13 +2329,21 @@ function blockToMdast(node, depth = 0) {
2320
2329
  ];
2321
2330
  }
2322
2331
  case "orderedList": {
2323
- const items = node.content.map((li) => listItemToMdast(li, depth + 1));
2332
+ const spread = node.spread ?? false;
2333
+ let counter = node.start;
2334
+ const items = node.content.map((li) => {
2335
+ const mdastLi = listItemToMdast(li, depth + 1);
2336
+ if (li.value != null) counter = li.value;
2337
+ mdastLi._ordinalValue = counter;
2338
+ counter++;
2339
+ return mdastLi;
2340
+ });
2324
2341
  return [
2325
2342
  {
2326
2343
  type: "list",
2327
2344
  ordered: true,
2328
- start: node.start,
2329
- spread: node.spread ?? false,
2345
+ start: node.content[0]?.value ?? node.start,
2346
+ spread,
2330
2347
  children: items
2331
2348
  }
2332
2349
  ];
@@ -2415,10 +2432,24 @@ function linkHandler(node, parent, state, info) {
2415
2432
  const titlePart = title ? ` "${title.replace(/"/g, '\\"')}"` : "";
2416
2433
  return `[${childrenText}](${url}${titlePart})`;
2417
2434
  }
2435
+ function listItemHandler(node, parent, state, info) {
2436
+ const value = node._ordinalValue;
2437
+ if (value != null && parent && parent.ordered) {
2438
+ const list = parent;
2439
+ const savedStart = list.start;
2440
+ const idx = list.children.indexOf(node);
2441
+ list.start = value - idx;
2442
+ const result = defaultHandlers3.listItem(node, parent, state, info);
2443
+ list.start = savedStart;
2444
+ return result;
2445
+ }
2446
+ return defaultHandlers3.listItem(node, parent, state, info);
2447
+ }
2418
2448
  function serializeToMarkdown(doc2) {
2419
2449
  const mdastTree = toMdast(doc2);
2420
2450
  const raw = toMarkdown(mdastTree, {
2421
2451
  bullet: "-",
2452
+ bulletOrdered: ".",
2422
2453
  rule: "-",
2423
2454
  listItemIndent: "one",
2424
2455
  incrementListMarker: true,
@@ -2434,6 +2465,7 @@ function serializeToMarkdown(doc2) {
2434
2465
  handlers: {
2435
2466
  text: textHandler,
2436
2467
  link: linkHandler,
2468
+ listItem: listItemHandler,
2437
2469
  ...resourceTagToMarkdown().handlers,
2438
2470
  ...jumpPointToMarkdown().handlers
2439
2471
  },
@@ -2569,8 +2601,11 @@ function convertBlock2(node) {
2569
2601
  type: "listItem",
2570
2602
  content: node.content.flatMap(convertBlockToArray)
2571
2603
  };
2572
- if (node.checked != null) {
2573
- result.attrs = { checked: node.checked };
2604
+ if (node.checked != null || node.value != null) {
2605
+ result.attrs = {
2606
+ ...node.checked != null ? { checked: node.checked } : {},
2607
+ ...node.value != null ? { value: node.value } : {}
2608
+ };
2574
2609
  }
2575
2610
  return result;
2576
2611
  }
@@ -3025,15 +3060,22 @@ var STRIKE_RE = /(?:^|[^~])~~([^~]+)~~$/;
3025
3060
  var CODE_RE = /(?:^|[^`])`([^`]+)`$/;
3026
3061
  function findParentList(state, pos) {
3027
3062
  const $pos = state.doc.resolve(pos);
3028
- const { bulletList: blType, orderedList: olType } = actionbookSchema.nodes;
3029
3063
  for (let d = $pos.depth; d > 0; d--) {
3030
3064
  const node = $pos.node(d);
3031
- if (node.type === blType || node.type === olType) {
3065
+ const name = node.type.name;
3066
+ if (name === "bulletList" || name === "orderedList") {
3032
3067
  return { depth: d, node };
3033
3068
  }
3034
3069
  }
3035
3070
  return null;
3036
3071
  }
3072
+ function isInsideList(state, pos) {
3073
+ const $pos = state.doc.resolve(pos);
3074
+ for (let d = $pos.depth; d > 0; d--) {
3075
+ if ($pos.node(d).type.name === "listItem") return true;
3076
+ }
3077
+ return false;
3078
+ }
3037
3079
  var NOOP = /* @__PURE__ */ Symbol("noop");
3038
3080
  function handleListInputRule(state, start, end, listType, attrs) {
3039
3081
  const resolvePos = Math.max(start, end - 1);
@@ -3044,27 +3086,46 @@ function handleListInputRule(state, start, end, listType, attrs) {
3044
3086
  const paraContentSize = $from.parent.content.size;
3045
3087
  const matchedLen = end - start;
3046
3088
  const isMarkerOnly = paraContentSize === matchedLen;
3047
- if (listNode.type === listType) {
3048
- if (isMarkerOnly && listType === actionbookSchema.nodes.orderedList && attrs?.start != null) {
3049
- const newStart = attrs.start;
3050
- const currentStart = listNode.attrs.start ?? 1;
3051
- if (newStart !== currentStart) {
3052
- const listStart = $from.before(listDepth);
3089
+ if (listNode.type.name === listType.name) {
3090
+ if (listType.name === "orderedList" && attrs?.start != null) {
3091
+ const newValue = attrs.start;
3092
+ let liDepth2 = -1;
3093
+ for (let d = $from.depth; d > 0; d--) {
3094
+ if ($from.node(d).type.name === "listItem") {
3095
+ liDepth2 = d;
3096
+ break;
3097
+ }
3098
+ }
3099
+ if (liDepth2 > 0) {
3100
+ const liIndex2 = $from.index(listDepth);
3101
+ const listStartNum = listNode.attrs.start ?? 1;
3102
+ const naturalNumber = listStartNum + liIndex2;
3103
+ const currentValue = $from.node(liDepth2).attrs.value;
3104
+ if (currentValue === newValue || currentValue == null && newValue === naturalNumber) {
3105
+ const tr3 = state.tr.delete(start, end);
3106
+ tr3.setSelection(TextSelection.near(tr3.doc.resolve(tr3.mapping.map(start))));
3107
+ return tr3;
3108
+ }
3053
3109
  const tr2 = state.tr.delete(start, end);
3054
- tr2.setNodeMarkup(tr2.mapping.map(listStart), void 0, { ...listNode.attrs, start: newStart });
3055
- tr2.setSelection(TextSelection.near(tr2.doc.resolve(tr2.mapping.map(start))));
3056
- return tr2;
3110
+ const $afterDelete = tr2.doc.resolve(tr2.mapping.map(resolvePos));
3111
+ for (let d = $afterDelete.depth; d > 0; d--) {
3112
+ if ($afterDelete.node(d).type.name === "listItem") {
3113
+ const pos = $afterDelete.before(d);
3114
+ const node = $afterDelete.node(d);
3115
+ tr2.setNodeMarkup(pos, void 0, { ...node.attrs, value: newValue });
3116
+ tr2.setSelection(TextSelection.near(tr2.doc.resolve(tr2.mapping.map(start))));
3117
+ return tr2;
3118
+ }
3119
+ }
3057
3120
  }
3058
3121
  }
3059
3122
  return NOOP;
3060
3123
  }
3061
- if (!isMarkerOnly) return NOOP;
3062
- const { listItem: liType } = actionbookSchema.nodes;
3063
3124
  const tr = state.tr.delete(start, end);
3064
3125
  const $pos = tr.doc.resolve(tr.mapping.map(resolvePos));
3065
3126
  let liDepth = -1;
3066
3127
  for (let d = $pos.depth; d > 0; d--) {
3067
- if ($pos.node(d).type === liType) {
3128
+ if ($pos.node(d).type.name === "listItem") {
3068
3129
  liDepth = d;
3069
3130
  break;
3070
3131
  }
@@ -3120,9 +3181,16 @@ function createInputRulesPlugin() {
3120
3181
  level: match[1].length
3121
3182
  }))
3122
3183
  );
3123
- rules.push(wrappingInputRule(BLOCKQUOTE_RE, actionbookSchema.nodes.blockquote));
3184
+ rules.push(
3185
+ new InputRule(BLOCKQUOTE_RE, (state, match, start, end) => {
3186
+ if (isInsideList(state, start)) return null;
3187
+ const fallback = wrappingInputRule(BLOCKQUOTE_RE, actionbookSchema.nodes.blockquote);
3188
+ return fallback.handler(state, match, start, end);
3189
+ })
3190
+ );
3124
3191
  rules.push(
3125
3192
  new InputRule(CODE_BLOCK_RE, (state, match, start, end) => {
3193
+ if (isInsideList(state, start)) return null;
3126
3194
  const language = match[1] || null;
3127
3195
  const $start = state.doc.resolve(start);
3128
3196
  const blockStart = $start.before($start.depth);
@@ -3138,6 +3206,7 @@ function createInputRulesPlugin() {
3138
3206
  );
3139
3207
  rules.push(
3140
3208
  new InputRule(HR_RE, (state, _match, start, end) => {
3209
+ if (isInsideList(state, start)) return null;
3141
3210
  const { horizontalRule: hrType, paragraph: pType } = actionbookSchema.nodes;
3142
3211
  const $start = state.doc.resolve(start);
3143
3212
  const blockStart = $start.before($start.depth);
@@ -3177,9 +3246,29 @@ function createInputRulesPlugin() {
3177
3246
  const fallback = wrappingInputRule(ORDERED_LIST_RE, olType, (m) => ({ start: +m[1] }));
3178
3247
  rules.push(
3179
3248
  new InputRule(ORDERED_LIST_RE, (state, match, start, end) => {
3180
- const result = handleListInputRule(state, start, end, olType, { start: +match[1] });
3181
- if (result === NOOP) return null;
3182
- if (result) return result;
3249
+ const typedNumber = +match[1];
3250
+ const resolvePos = Math.max(start, end - 1);
3251
+ const parentList = findParentList(state, resolvePos);
3252
+ if (parentList) {
3253
+ const { node: listNode } = parentList;
3254
+ if (listNode.type.name === "orderedList") {
3255
+ const tr = state.tr.delete(start, end);
3256
+ const $after = tr.doc.resolve(tr.mapping.map(resolvePos));
3257
+ for (let d = $after.depth; d > 0; d--) {
3258
+ if ($after.node(d).type.name === "listItem") {
3259
+ const liPos = $after.before(d);
3260
+ const liNode = $after.node(d);
3261
+ tr.setNodeMarkup(liPos, void 0, { ...liNode.attrs, value: typedNumber });
3262
+ tr.setSelection(TextSelection.near(tr.doc.resolve(tr.mapping.map(start))));
3263
+ return tr;
3264
+ }
3265
+ }
3266
+ return null;
3267
+ }
3268
+ const result = handleListInputRule(state, start, end, olType, { start: typedNumber });
3269
+ if (result === NOOP) return null;
3270
+ if (result) return result;
3271
+ }
3183
3272
  const handler = fallback.handler;
3184
3273
  return handler(state, match, start, end);
3185
3274
  })
@@ -5853,7 +5942,7 @@ function buildDocumentTree(doc2) {
5853
5942
 
5854
5943
  // src/ui/plugin/markdownClipboard.ts
5855
5944
  var key = new PluginKey2("markdownClipboard");
5856
- var MAX_PASTE_LIST_DEPTH = 3;
5945
+ var MAX_PASTE_LIST_DEPTH = 15;
5857
5946
  var MAX_FLATTEN_DEPTH = 128;
5858
5947
  function flattenDeepLists(node, listDepth = 0, _recurseDepth = 0) {
5859
5948
  if (_recurseDepth > MAX_FLATTEN_DEPTH) return node;
@@ -5944,6 +6033,22 @@ function createPlugin() {
5944
6033
  keyup() {
5945
6034
  shiftHeld = false;
5946
6035
  return false;
6036
+ },
6037
+ paste(view, event) {
6038
+ if (shiftHeld) return false;
6039
+ const clipboardData = event.clipboardData;
6040
+ const text2 = clipboardData?.getData("text/plain");
6041
+ if (!text2 || !URL_RE.test(text2.trim())) return false;
6042
+ const { from, to } = view.state.selection;
6043
+ if (from >= to) return false;
6044
+ const selectedText = view.state.doc.textBetween(from, to);
6045
+ if (!selectedText) return false;
6046
+ event.preventDefault();
6047
+ const linkType = view.state.schema.marks.link;
6048
+ if (!linkType) return false;
6049
+ const linkMark2 = linkType.create({ href: text2.trim() });
6050
+ view.dispatch(view.state.tr.addMark(from, to, linkMark2));
6051
+ return true;
5947
6052
  }
5948
6053
  },
5949
6054
  handlePaste(view, event) {
@@ -7103,60 +7208,18 @@ function deleteBranch(view, nodePos, branchType) {
7103
7208
  const context = getBranchContext(view, nodePos);
7104
7209
  if (!context) return false;
7105
7210
  const { branchNode, branchPos, branchIndex, blockNode, blockPos } = context;
7106
- const branchContent = branchNode.content;
7107
7211
  if (branchType === "if") {
7108
- if (blockNode.childCount === 1) {
7109
- const tr2 = view.state.tr;
7110
- if (isBranchBodyEmpty(branchNode)) {
7111
- tr2.replaceWith(blockPos, blockPos + blockNode.nodeSize, view.state.schema.nodes.paragraph.create());
7112
- tr2.setSelection(TextSelection4.near(tr2.doc.resolve(blockPos)));
7113
- } else {
7114
- tr2.replaceWith(blockPos, blockPos + blockNode.nodeSize, branchContent);
7115
- tr2.setSelection(TextSelection4.near(tr2.doc.resolve(blockPos)));
7116
- }
7117
- view.dispatch(tr2.scrollIntoView());
7118
- view.focus();
7119
- return true;
7120
- }
7121
- const nextBranch = blockNode.child(branchIndex + 1);
7122
- const promotedCondition = typeof nextBranch.attrs.condition === "string" ? nextBranch.attrs.condition : "";
7123
- const tr = view.state.tr;
7124
- if (!isBranchBodyEmpty(branchNode)) {
7125
- const nextBranchPos = branchPos + branchNode.nodeSize;
7126
- const nextBranchContentStart = nextBranchPos + 1;
7127
- for (let i = branchContent.childCount - 1; i >= 0; i--) {
7128
- tr.insert(nextBranchContentStart, branchContent.child(i));
7129
- }
7130
- }
7131
- const mappedBranchPos = tr.mapping.map(branchPos);
7132
- const mappedBranchEnd = tr.mapping.map(branchPos + branchNode.nodeSize);
7133
- tr.delete(mappedBranchPos, mappedBranchEnd);
7134
- tr.setNodeMarkup(mappedBranchPos, void 0, {
7135
- ...nextBranch.attrs,
7136
- branchType: "if",
7137
- condition: promotedCondition
7138
- });
7139
- view.dispatch(tr.scrollIntoView());
7212
+ const tr2 = view.state.tr;
7213
+ tr2.replaceWith(blockPos, blockPos + blockNode.nodeSize, view.state.schema.nodes.paragraph.create());
7214
+ tr2.setSelection(TextSelection4.near(tr2.doc.resolve(blockPos)));
7215
+ view.dispatch(tr2.scrollIntoView());
7140
7216
  view.focus();
7141
7217
  return true;
7142
7218
  }
7143
- if (!isBranchBodyEmpty(branchNode) && branchIndex > 0) {
7144
- const prevBranch = blockNode.child(branchIndex - 1);
7145
- const prevBranchPos = branchPos - prevBranch.nodeSize;
7146
- const prevBranchContentEnd = prevBranchPos + prevBranch.nodeSize - 1;
7147
- const tr = view.state.tr;
7148
- for (let i = 0; i < branchContent.childCount; i++) {
7149
- tr.insert(prevBranchContentEnd + i, branchContent.child(i));
7150
- }
7151
- const mappedBranchPos = tr.mapping.map(branchPos);
7152
- const mappedBranchEnd = tr.mapping.map(branchPos + branchNode.nodeSize);
7153
- tr.delete(mappedBranchPos, mappedBranchEnd);
7154
- tr.setSelection(TextSelection4.near(tr.doc.resolve(tr.mapping.map(prevBranchContentEnd)), -1));
7155
- view.dispatch(tr.scrollIntoView());
7156
- view.focus();
7157
- return true;
7158
- }
7159
- view.dispatch(view.state.tr.delete(branchPos, branchPos + branchNode.nodeSize).scrollIntoView());
7219
+ const tr = view.state.tr;
7220
+ tr.delete(branchPos, branchPos + branchNode.nodeSize);
7221
+ tr.setSelection(TextSelection4.near(tr.doc.resolve(tr.mapping.map(branchPos)), -1));
7222
+ view.dispatch(tr.scrollIntoView());
7160
7223
  view.focus();
7161
7224
  return true;
7162
7225
  }
@@ -7204,11 +7267,11 @@ function ConditionDisplay({
7204
7267
  return /* @__PURE__ */ jsx6("span", { className: "jinja-otherwise", children: "Otherwise" });
7205
7268
  }
7206
7269
  const commit = () => {
7207
- setIsEditing(false);
7208
- onConditionBlur?.();
7209
7270
  if (draftValue !== condition) {
7210
7271
  onConditionChange(draftValue);
7211
7272
  }
7273
+ setIsEditing(false);
7274
+ onConditionBlur?.();
7212
7275
  };
7213
7276
  const cancel = () => {
7214
7277
  setDraftValue(condition);
@@ -7326,24 +7389,9 @@ function JinjaBranchHeader({
7326
7389
  };
7327
7390
  }, [menuSource]);
7328
7391
  const menuItems = [];
7329
- const isOnlyIfBranch = branchType === "if" && isLastBranch && !hasElseBranch;
7330
- const canAddElif = editable && branchType !== "else" && (branchType === "elif" || isLastBranch);
7331
- const canAddElse = editable && branchType !== "else" && isLastBranch && !hasElseBranch;
7332
- if (canAddElif) {
7333
- menuItems.push({
7334
- label: "Else if",
7335
- onSelect: () => onAddBranch("elif")
7336
- });
7337
- }
7338
- if (canAddElse) {
7339
- menuItems.push({
7340
- label: "Else",
7341
- onSelect: () => onAddBranch("else")
7342
- });
7343
- }
7344
7392
  if (editable) {
7345
7393
  menuItems.push({
7346
- label: isOnlyIfBranch ? "Delete all" : "Delete",
7394
+ label: "Delete",
7347
7395
  onSelect: onDelete
7348
7396
  });
7349
7397
  }
@@ -8654,6 +8702,7 @@ function createDragHandlePlugin() {
8654
8702
  }
8655
8703
 
8656
8704
  // src/ui/plugin/todoNodeViewPlugin.tsx
8705
+ import { Plugin as Plugin10 } from "prosemirror-state";
8657
8706
  function createCheckboxDOM(checked) {
8658
8707
  const el = document.createElement("span");
8659
8708
  el.contentEditable = "false";
@@ -8736,14 +8785,63 @@ var TodoListItemView = class {
8736
8785
  return true;
8737
8786
  }
8738
8787
  };
8788
+ function createListItemValueResetPlugin() {
8789
+ return new Plugin10({
8790
+ appendTransaction(trs, oldState, newState) {
8791
+ if (!trs.some((tr2) => tr2.docChanged)) return null;
8792
+ const oldCount = oldState.doc.childCount;
8793
+ let hasNewListItems = false;
8794
+ newState.doc.descendants((node) => {
8795
+ if (hasNewListItems) return false;
8796
+ if (node.type.name === "listItem" && node.attrs.value != null) {
8797
+ hasNewListItems = true;
8798
+ }
8799
+ });
8800
+ if (!hasNewListItems) return null;
8801
+ let tr = newState.tr;
8802
+ let changed = false;
8803
+ newState.doc.descendants((node, pos) => {
8804
+ if (node.type.name !== "orderedList") return;
8805
+ let prevValue = null;
8806
+ node.forEach((li, offset) => {
8807
+ const liValue = li.attrs.value;
8808
+ if (liValue != null && liValue === prevValue) {
8809
+ const liPos = pos + 1 + offset;
8810
+ tr = tr.setNodeMarkup(liPos, void 0, { ...li.attrs, value: null });
8811
+ changed = true;
8812
+ }
8813
+ prevValue = liValue;
8814
+ });
8815
+ });
8816
+ return changed ? tr : null;
8817
+ }
8818
+ });
8819
+ }
8739
8820
  function createTodoNodeViewPlugin() {
8740
8821
  return {
8741
8822
  name: "todoNodeView",
8823
+ plugins: () => [createListItemValueResetPlugin()],
8742
8824
  nodeViews: () => ({
8743
8825
  listItem: ((node, view, getPos) => {
8744
8826
  if (node.attrs.checked == null) {
8745
8827
  const li = document.createElement("li");
8746
- return { dom: li, contentDOM: li };
8828
+ if (node.attrs.value != null) {
8829
+ li.value = node.attrs.value;
8830
+ }
8831
+ return {
8832
+ dom: li,
8833
+ contentDOM: li,
8834
+ update(updatedNode) {
8835
+ if (updatedNode.type.name !== "listItem") return false;
8836
+ if (updatedNode.attrs.checked != null) return false;
8837
+ if (updatedNode.attrs.value != null) {
8838
+ li.value = updatedNode.attrs.value;
8839
+ } else {
8840
+ li.removeAttribute("value");
8841
+ }
8842
+ return true;
8843
+ }
8844
+ };
8747
8845
  }
8748
8846
  return new TodoListItemView(node, view, getPos);
8749
8847
  })
@@ -8752,7 +8850,7 @@ function createTodoNodeViewPlugin() {
8752
8850
  }
8753
8851
 
8754
8852
  // src/ui/plugin/placeholderPlugin.ts
8755
- import { Plugin as Plugin10, PluginKey as PluginKey8 } from "prosemirror-state";
8853
+ import { Plugin as Plugin11, PluginKey as PluginKey8 } from "prosemirror-state";
8756
8854
  import { Decoration as Decoration5, DecorationSet as DecorationSet5 } from "prosemirror-view";
8757
8855
  var pluginKey2 = new PluginKey8("placeholder");
8758
8856
  function buildDecorations4(state) {
@@ -8771,7 +8869,8 @@ function buildDecorations4(state) {
8771
8869
  }
8772
8870
  const pos = $from.before($from.depth);
8773
8871
  const deco = Decoration5.node(pos, pos + parent.nodeSize, {
8774
- class: "ab-empty-paragraph"
8872
+ class: "ab-empty-paragraph",
8873
+ "data-placeholder": "Type to start writing, or press / to insert an action."
8775
8874
  });
8776
8875
  return DecorationSet5.create(doc2, [deco]);
8777
8876
  }
@@ -8780,7 +8879,7 @@ function createPlaceholderPlugin() {
8780
8879
  return {
8781
8880
  name: "placeholder",
8782
8881
  plugins: () => [
8783
- new Plugin10({
8882
+ new Plugin11({
8784
8883
  key: pluginKey2,
8785
8884
  view(editorView) {
8786
8885
  isEditable = editorView.editable;
@@ -8899,27 +8998,49 @@ function SlashCommandMenu({ view, editorState, items }) {
8899
8998
  view.focus();
8900
8999
  }
8901
9000
  }
9001
+ if (e.key === "Escape") {
9002
+ e.preventDefault();
9003
+ e.stopPropagation();
9004
+ if (range) {
9005
+ view.dispatch(view.state.tr.delete(range.from, range.to));
9006
+ }
9007
+ view.focus();
9008
+ }
8902
9009
  };
8903
9010
  document.addEventListener("keydown", onKeyDown, true);
8904
9011
  return () => document.removeEventListener("keydown", onKeyDown, true);
8905
9012
  }, [active, view, filtered, selectedIndex, range]);
8906
- if (!active || !view || !range || filtered.length === 0) return null;
8907
- const coords = view.coordsAtPos(range.from);
8908
- let top = coords.bottom + 4;
8909
- let left = coords.left;
8910
- left = Math.max(VPORT_MARGIN, Math.min(left, window.innerWidth - MENU_WIDTH - VPORT_MARGIN));
8911
- if (top + MAX_MENU_H > window.innerHeight - VPORT_MARGIN) {
8912
- top = coords.top - MAX_MENU_H - 4;
8913
- }
9013
+ const [menuPos, setMenuPos] = useState4(null);
9014
+ const menuRef = useRef4(null);
9015
+ useLayoutEffect(() => {
9016
+ if (!active || !view || !range || filtered.length === 0) {
9017
+ setMenuPos(null);
9018
+ return;
9019
+ }
9020
+ try {
9021
+ const coords = view.coordsAtPos(range.to);
9022
+ let left = coords.left;
9023
+ left = Math.max(VPORT_MARGIN, Math.min(left, window.innerWidth - MENU_WIDTH - VPORT_MARGIN));
9024
+ const menuHeight = menuRef.current?.offsetHeight ?? MAX_MENU_H;
9025
+ let top = coords.bottom + 4;
9026
+ if (top + menuHeight > window.innerHeight - VPORT_MARGIN) {
9027
+ top = coords.top - menuHeight - 4;
9028
+ }
9029
+ setMenuPos({ top, left });
9030
+ } catch {
9031
+ }
9032
+ });
9033
+ if (!active || !view || !range || filtered.length === 0 || !menuPos) return null;
8914
9034
  return createPortal2(
8915
9035
  /* @__PURE__ */ jsx7(
8916
9036
  "div",
8917
9037
  {
9038
+ ref: menuRef,
8918
9039
  className: "ab-slash-menu",
8919
9040
  style: {
8920
9041
  position: "fixed",
8921
- top,
8922
- left,
9042
+ top: menuPos.top,
9043
+ left: menuPos.left,
8923
9044
  width: MENU_WIDTH,
8924
9045
  maxHeight: MAX_MENU_H,
8925
9046
  overflowY: "auto",
@@ -10718,7 +10839,7 @@ function FloatingMenu({ view, editorState }) {
10718
10839
  }
10719
10840
 
10720
10841
  // src/ui/plugin/inlineSuggestPlugin.ts
10721
- import { Plugin as Plugin11, PluginKey as PluginKey9 } from "prosemirror-state";
10842
+ import { Plugin as Plugin12, PluginKey as PluginKey9 } from "prosemirror-state";
10722
10843
  import { Decoration as Decoration6, DecorationSet as DecorationSet6 } from "prosemirror-view";
10723
10844
  var inlineSuggestKey = new PluginKey9("inlineSuggest");
10724
10845
  var DEBOUNCE_MS = 600;
@@ -10727,7 +10848,7 @@ function createInlineSuggestPlugin(provider, endpoint, options) {
10727
10848
  return {
10728
10849
  name: "inlineSuggest",
10729
10850
  plugins: () => [
10730
- new Plugin11({
10851
+ new Plugin12({
10731
10852
  key: inlineSuggestKey,
10732
10853
  state: {
10733
10854
  init: () => ({ suggestion: null, anchorPos: null }),