@sendbird/actionbook-core 0.9.8 → 0.10.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/ui/index.js CHANGED
@@ -2649,6 +2649,18 @@ function useEditorView(config) {
2649
2649
  viewInstanceRef.current = null;
2650
2650
  };
2651
2651
  }, []);
2652
+ const prevEditableRef = useRef(config.editable);
2653
+ useEffect(() => {
2654
+ if (prevEditableRef.current !== config.editable) {
2655
+ prevEditableRef.current = config.editable;
2656
+ const view = viewInstanceRef.current;
2657
+ if (view) {
2658
+ const tr = view.state.tr;
2659
+ tr.setMeta("editableChanged", true);
2660
+ view.dispatch(tr);
2661
+ }
2662
+ }
2663
+ }, [config.editable]);
2652
2664
  const viewRef = useCallback((container) => {
2653
2665
  if (container === containerRef.current) return;
2654
2666
  if (viewInstanceRef.current) {
@@ -2886,14 +2898,6 @@ function createInputRulesPlugin() {
2886
2898
  rules.push(
2887
2899
  new InputRule(JUMP_POINT_RE2, (state, match, start, end) => {
2888
2900
  const id = match[1];
2889
- let exists = false;
2890
- state.doc.descendants((node) => {
2891
- if (node.type === jumpPointType && node.attrs.id === id) {
2892
- exists = true;
2893
- return false;
2894
- }
2895
- });
2896
- if (exists) return null;
2897
2901
  const tr = state.tr.delete(start, end).insert(start, jumpPointType.create({ id }));
2898
2902
  const afterAtom = start + 1;
2899
2903
  tr.insertText(" ", afterAtom);
@@ -5407,18 +5411,10 @@ function createJumpPointEditPlugin() {
5407
5411
  const [, id] = match;
5408
5412
  const jumpPointType = newState.schema.nodes.jumpPoint;
5409
5413
  if (jumpPointType) {
5410
- let duplicate = false;
5411
- newState.doc.descendants((node, pos) => {
5412
- if (node.type === jumpPointType && node.attrs.id === id) {
5413
- if (pos < safeFrom || pos >= safeTo) duplicate = true;
5414
- }
5415
- });
5416
- if (!duplicate) {
5417
- reconvertTr.replaceWith(safeFrom, safeTo, jumpPointType.create({ id }));
5418
- const mappedCursor = reconvertTr.mapping.map(cursor);
5419
- const clampedCursor = Math.min(mappedCursor, reconvertTr.doc.content.size);
5420
- reconvertTr.setSelection(TextSelection3.near(reconvertTr.doc.resolve(clampedCursor)));
5421
- }
5414
+ reconvertTr.replaceWith(safeFrom, safeTo, jumpPointType.create({ id }));
5415
+ const mappedCursor = reconvertTr.mapping.map(cursor);
5416
+ const clampedCursor = Math.min(mappedCursor, reconvertTr.doc.content.size);
5417
+ reconvertTr.setSelection(TextSelection3.near(reconvertTr.doc.resolve(clampedCursor)));
5422
5418
  }
5423
5419
  }
5424
5420
  }
@@ -5934,7 +5930,7 @@ function createJinjaDecorationPlugin() {
5934
5930
  // src/ui/plugin/jinjaIfBlockPlugin.tsx
5935
5931
  import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
5936
5932
  import { createRoot as createRoot2 } from "react-dom/client";
5937
- import { TextSelection as TextSelection4 } from "prosemirror-state";
5933
+ import { Plugin as Plugin5, TextSelection as TextSelection4 } from "prosemirror-state";
5938
5934
  import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
5939
5935
  var PLACEHOLDER_TEXT = "Describe what AI agent should do when this condition is met";
5940
5936
  var CONDITION_PLACEHOLDER = "Write a condition in natural language";
@@ -6319,15 +6315,6 @@ function getElseBranch(view, nodePos) {
6319
6315
  }
6320
6316
  return false;
6321
6317
  }
6322
- function deleteBlock(view, blockPos) {
6323
- const blockNode = view.state.doc.nodeAt(blockPos);
6324
- if (blockNode?.type.name !== "jinjaIfBlock") {
6325
- return false;
6326
- }
6327
- view.dispatch(view.state.tr.delete(blockPos, blockPos + blockNode.nodeSize).scrollIntoView());
6328
- view.focus();
6329
- return true;
6330
- }
6331
6318
  function insertNewBranch(view, nodePos, branchType, condition = "") {
6332
6319
  const context = getBranchContext(view, nodePos);
6333
6320
  if (!context) return false;
@@ -6353,14 +6340,36 @@ function insertNewBranch(view, nodePos, branchType, condition = "") {
6353
6340
  function deleteBranch(view, nodePos, branchType) {
6354
6341
  const context = getBranchContext(view, nodePos);
6355
6342
  if (!context) return false;
6343
+ const { branchNode, branchPos, branchIndex, blockNode, blockPos } = context;
6344
+ const branchContent = branchNode.content;
6356
6345
  if (branchType === "if") {
6357
- if (context.blockNode.childCount === 1) {
6358
- return deleteBlock(view, context.blockPos);
6346
+ if (blockNode.childCount === 1) {
6347
+ const tr2 = view.state.tr;
6348
+ if (isBranchBodyEmpty(branchNode)) {
6349
+ tr2.replaceWith(blockPos, blockPos + blockNode.nodeSize, view.state.schema.nodes.paragraph.create());
6350
+ tr2.setSelection(TextSelection4.near(tr2.doc.resolve(blockPos)));
6351
+ } else {
6352
+ tr2.replaceWith(blockPos, blockPos + blockNode.nodeSize, branchContent);
6353
+ tr2.setSelection(TextSelection4.near(tr2.doc.resolve(blockPos)));
6354
+ }
6355
+ view.dispatch(tr2.scrollIntoView());
6356
+ view.focus();
6357
+ return true;
6359
6358
  }
6360
- const nextBranch = context.blockNode.child(context.branchIndex + 1);
6359
+ const nextBranch = blockNode.child(branchIndex + 1);
6361
6360
  const promotedCondition = typeof nextBranch.attrs.condition === "string" ? nextBranch.attrs.condition : "";
6362
- const tr = view.state.tr.delete(context.branchPos, context.branchPos + context.branchNode.nodeSize);
6363
- tr.setNodeMarkup(context.branchPos, void 0, {
6361
+ const tr = view.state.tr;
6362
+ if (!isBranchBodyEmpty(branchNode)) {
6363
+ const nextBranchPos = branchPos + branchNode.nodeSize;
6364
+ const nextBranchContentStart = nextBranchPos + 1;
6365
+ for (let i = branchContent.childCount - 1; i >= 0; i--) {
6366
+ tr.insert(nextBranchContentStart, branchContent.child(i));
6367
+ }
6368
+ }
6369
+ const mappedBranchPos = tr.mapping.map(branchPos);
6370
+ const mappedBranchEnd = tr.mapping.map(branchPos + branchNode.nodeSize);
6371
+ tr.delete(mappedBranchPos, mappedBranchEnd);
6372
+ tr.setNodeMarkup(mappedBranchPos, void 0, {
6364
6373
  ...nextBranch.attrs,
6365
6374
  branchType: "if",
6366
6375
  condition: promotedCondition
@@ -6369,7 +6378,23 @@ function deleteBranch(view, nodePos, branchType) {
6369
6378
  view.focus();
6370
6379
  return true;
6371
6380
  }
6372
- view.dispatch(view.state.tr.delete(context.branchPos, context.branchPos + context.branchNode.nodeSize).scrollIntoView());
6381
+ if (!isBranchBodyEmpty(branchNode) && branchIndex > 0) {
6382
+ const prevBranch = blockNode.child(branchIndex - 1);
6383
+ const prevBranchPos = branchPos - prevBranch.nodeSize;
6384
+ const prevBranchContentEnd = prevBranchPos + prevBranch.nodeSize - 1;
6385
+ const tr = view.state.tr;
6386
+ for (let i = 0; i < branchContent.childCount; i++) {
6387
+ tr.insert(prevBranchContentEnd + i, branchContent.child(i));
6388
+ }
6389
+ const mappedBranchPos = tr.mapping.map(branchPos);
6390
+ const mappedBranchEnd = tr.mapping.map(branchPos + branchNode.nodeSize);
6391
+ tr.delete(mappedBranchPos, mappedBranchEnd);
6392
+ tr.setSelection(TextSelection4.near(tr.doc.resolve(tr.mapping.map(prevBranchContentEnd)), -1));
6393
+ view.dispatch(tr.scrollIntoView());
6394
+ view.focus();
6395
+ return true;
6396
+ }
6397
+ view.dispatch(view.state.tr.delete(branchPos, branchPos + branchNode.nodeSize).scrollIntoView());
6373
6398
  view.focus();
6374
6399
  return true;
6375
6400
  }
@@ -6388,7 +6413,8 @@ function ConditionDisplay({
6388
6413
  branchType,
6389
6414
  condition,
6390
6415
  editable = true,
6391
- onConditionChange
6416
+ onConditionChange,
6417
+ onBackspaceEmpty
6392
6418
  }) {
6393
6419
  const [isEditing, setIsEditing] = useState3(false);
6394
6420
  const [draftValue, setDraftValue] = useState3(condition);
@@ -6443,6 +6469,10 @@ function ConditionDisplay({
6443
6469
  event.preventDefault();
6444
6470
  cancel();
6445
6471
  }
6472
+ if (event.key === "Backspace" && draftValue === "" && onBackspaceEmpty) {
6473
+ event.preventDefault();
6474
+ onBackspaceEmpty();
6475
+ }
6446
6476
  }
6447
6477
  }
6448
6478
  );
@@ -6562,7 +6592,8 @@ function JinjaBranchHeader({
6562
6592
  branchType,
6563
6593
  condition,
6564
6594
  editable,
6565
- onConditionChange
6595
+ onConditionChange,
6596
+ onBackspaceEmpty: onDelete
6566
6597
  }
6567
6598
  ),
6568
6599
  editable ? /* @__PURE__ */ jsxs5("div", { className: "jinja-branch-actions", ref: kebabRef, children: [
@@ -6692,10 +6723,13 @@ var JinjaIfBranchView = class {
6692
6723
  this.root = createRoot2(this.headerContainer);
6693
6724
  this._onSiblingsChanged = () => this.render();
6694
6725
  this.dom.addEventListener("jinja-siblings-changed", this._onSiblingsChanged);
6726
+ this._onEditableChanged = () => this.render();
6727
+ this.dom.addEventListener("jinja-editable-changed", this._onEditableChanged);
6695
6728
  this.syncDOM();
6696
6729
  this.render();
6697
6730
  }
6698
6731
  _onSiblingsChanged = null;
6732
+ _onEditableChanged = null;
6699
6733
  syncDOM() {
6700
6734
  const branchType = this.node.attrs.branchType;
6701
6735
  this.dom.className = `jinja-branch jinja-branch-${branchType}`;
@@ -6781,13 +6815,37 @@ var JinjaIfBranchView = class {
6781
6815
  if (this._onSiblingsChanged) {
6782
6816
  this.dom.removeEventListener("jinja-siblings-changed", this._onSiblingsChanged);
6783
6817
  }
6818
+ if (this._onEditableChanged) {
6819
+ this.dom.removeEventListener("jinja-editable-changed", this._onEditableChanged);
6820
+ }
6784
6821
  StyleManager.release();
6785
6822
  setTimeout(() => this.root.unmount(), 0);
6786
6823
  }
6787
6824
  };
6825
+ function createEditableWatcherPlugin() {
6826
+ let lastEditable = null;
6827
+ return new Plugin5({
6828
+ view(editorView) {
6829
+ lastEditable = editorView.editable;
6830
+ return {
6831
+ update(view) {
6832
+ const currentEditable = view.editable;
6833
+ if (lastEditable !== null && lastEditable !== currentEditable) {
6834
+ const event = new Event("jinja-editable-changed", { bubbles: true });
6835
+ view.dom.querySelectorAll("[data-jinja-branch]").forEach((el) => {
6836
+ el.dispatchEvent(event);
6837
+ });
6838
+ }
6839
+ lastEditable = currentEditable;
6840
+ }
6841
+ };
6842
+ }
6843
+ });
6844
+ }
6788
6845
  function createJinjaIfBlockPlugin() {
6789
6846
  return {
6790
6847
  name: "jinjaIfBlock",
6848
+ plugins: () => [createEditableWatcherPlugin()],
6791
6849
  nodeViews: () => ({
6792
6850
  jinjaIfBlock: (() => new JinjaIfBlockView()),
6793
6851
  jinjaIfBranch: ((node, view, getPos) => new JinjaIfBranchView(node, view, getPos))
@@ -6797,7 +6855,7 @@ function createJinjaIfBlockPlugin() {
6797
6855
 
6798
6856
  // src/ui/plugin/linkPlugin.ts
6799
6857
  import { InputRule as InputRule2, inputRules as inputRules2 } from "prosemirror-inputrules";
6800
- import { Plugin as Plugin5, PluginKey as PluginKey5, TextSelection as TextSelection5 } from "prosemirror-state";
6858
+ import { Plugin as Plugin6, PluginKey as PluginKey5, TextSelection as TextSelection5 } from "prosemirror-state";
6801
6859
  var LINK_INPUT_RE = /\\?\[([^\]]*?)\\?\]\(([^)\s]*?)(?:\s+"([^"]*)")?\)$/;
6802
6860
  var LINK_FULL_RE = /^\\?\[([^\]]*?)\\?\]\(([^)\s]*?)(?:\s+"([^"]*)")?\)$/;
6803
6861
  var linkEditKey = new PluginKey5("linkEdit");
@@ -6848,7 +6906,7 @@ function explodeLinkToRaw(state) {
6848
6906
  return tr;
6849
6907
  }
6850
6908
  function createLinkEditPlugin() {
6851
- return new Plugin5({
6909
+ return new Plugin6({
6852
6910
  key: linkEditKey,
6853
6911
  state: {
6854
6912
  init: () => ({ rawRange: null }),
@@ -6918,7 +6976,7 @@ function createLinkInputRule() {
6918
6976
  );
6919
6977
  }
6920
6978
  function createLinkClickPlugin() {
6921
- return new Plugin5({
6979
+ return new Plugin6({
6922
6980
  key: new PluginKey5("linkClick"),
6923
6981
  props: {
6924
6982
  handleDOMEvents: {
@@ -6971,7 +7029,7 @@ function createLinkPlugin() {
6971
7029
  }
6972
7030
 
6973
7031
  // src/ui/plugin/dragHandlePlugin.ts
6974
- import { Plugin as Plugin6, PluginKey as PluginKey6 } from "prosemirror-state";
7032
+ import { Plugin as Plugin7, PluginKey as PluginKey6 } from "prosemirror-state";
6975
7033
  var PLUGIN_KEY = new PluginKey6("dragHandle");
6976
7034
  var GRIP_SVG = `<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
6977
7035
  <circle cx="4" cy="2.5" r="1.2"/><circle cx="8" cy="2.5" r="1.2"/>
@@ -7779,7 +7837,7 @@ function createDragHandlePlugin() {
7779
7837
  plugins: () => {
7780
7838
  let controller = null;
7781
7839
  return [
7782
- new Plugin6({
7840
+ new Plugin7({
7783
7841
  key: PLUGIN_KEY,
7784
7842
  view(editorView) {
7785
7843
  controller = new DragHandleController(editorView);
@@ -7902,7 +7960,7 @@ function createTodoNodeViewPlugin() {
7902
7960
  }
7903
7961
 
7904
7962
  // src/ui/plugin/placeholderPlugin.ts
7905
- import { Plugin as Plugin7, PluginKey as PluginKey7 } from "prosemirror-state";
7963
+ import { Plugin as Plugin8, PluginKey as PluginKey7 } from "prosemirror-state";
7906
7964
  import { Decoration as Decoration4, DecorationSet as DecorationSet4 } from "prosemirror-view";
7907
7965
  var PLACEHOLDER_TEXT2 = "Type to start writing, or press / to insert an action.";
7908
7966
  var pluginKey2 = new PluginKey7("placeholder");
@@ -7931,7 +7989,7 @@ function createPlaceholderPlugin() {
7931
7989
  return {
7932
7990
  name: "placeholder",
7933
7991
  plugins: () => [
7934
- new Plugin7({
7992
+ new Plugin8({
7935
7993
  key: pluginKey2,
7936
7994
  state: {
7937
7995
  init(_, state) {
@@ -7955,7 +8013,7 @@ function createPlaceholderPlugin() {
7955
8013
  }
7956
8014
 
7957
8015
  // src/ui/plugin/slashCommandPlugin.ts
7958
- import { Plugin as Plugin8, PluginKey as PluginKey8 } from "prosemirror-state";
8016
+ import { Plugin as Plugin9, PluginKey as PluginKey8 } from "prosemirror-state";
7959
8017
  var slashCommandKey = new PluginKey8("slashCommand");
7960
8018
  var TRIGGER_RE = /(?:^|\s)(\/[^\s]*)$/;
7961
8019
  function deriveState(state, dismissedFrom) {
@@ -7983,7 +8041,7 @@ function deriveState(state, dismissedFrom) {
7983
8041
  };
7984
8042
  }
7985
8043
  function createSlashCommandPlugin() {
7986
- const plugin = new Plugin8({
8044
+ const plugin = new Plugin9({
7987
8045
  key: slashCommandKey,
7988
8046
  state: {
7989
8047
  init(_, state) {
@@ -9738,7 +9796,7 @@ function FloatingMenu({ view, editorState }) {
9738
9796
  }
9739
9797
 
9740
9798
  // src/ui/plugin/inlineSuggestPlugin.ts
9741
- import { Plugin as Plugin9, PluginKey as PluginKey9 } from "prosemirror-state";
9799
+ import { Plugin as Plugin10, PluginKey as PluginKey9 } from "prosemirror-state";
9742
9800
  import { Decoration as Decoration5, DecorationSet as DecorationSet5 } from "prosemirror-view";
9743
9801
  var inlineSuggestKey = new PluginKey9("inlineSuggest");
9744
9802
  var DEBOUNCE_MS = 600;
@@ -9747,7 +9805,7 @@ function createInlineSuggestPlugin(provider, endpoint, options) {
9747
9805
  return {
9748
9806
  name: "inlineSuggest",
9749
9807
  plugins: () => [
9750
- new Plugin9({
9808
+ new Plugin10({
9751
9809
  key: inlineSuggestKey,
9752
9810
  state: {
9753
9811
  init: () => ({ suggestion: null, anchorPos: null }),