@dialpad/dialtone 9.31.1 → 9.33.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.
Files changed (89) hide show
  1. package/README.md +6 -0
  2. package/dist/css/dialtone.css +11 -2
  3. package/dist/css/dialtone.min.css +1 -1
  4. package/dist/tokens/css/variables-dark.css +1 -1
  5. package/dist/tokens/css/variables-expressive-dark.css +1 -1
  6. package/dist/tokens/css/variables-expressive-light.css +1 -1
  7. package/dist/tokens/css/variables-expressive-sm-dark.css +1 -1
  8. package/dist/tokens/css/variables-expressive-sm-light.css +1 -1
  9. package/dist/tokens/css/variables-light.css +1 -1
  10. package/dist/tokens/css/variables-tmo-dark.css +1 -1
  11. package/dist/tokens/css/variables-tmo-light.css +1 -1
  12. package/dist/tokens/less/variables-dark.less +1 -1
  13. package/dist/tokens/less/variables-expressive-dark.less +1 -1
  14. package/dist/tokens/less/variables-expressive-light.less +1 -1
  15. package/dist/tokens/less/variables-expressive-sm-dark.less +1 -1
  16. package/dist/tokens/less/variables-expressive-sm-light.less +1 -1
  17. package/dist/tokens/less/variables-light.less +1 -1
  18. package/dist/tokens/less/variables-tmo-dark.less +1 -1
  19. package/dist/tokens/less/variables-tmo-light.less +1 -1
  20. package/dist/vue2/common/utils.cjs +8 -1
  21. package/dist/vue2/common/utils.cjs.map +1 -1
  22. package/dist/vue2/common/utils.js +8 -1
  23. package/dist/vue2/common/utils.js.map +1 -1
  24. package/dist/vue2/component-documentation.json +1 -1
  25. package/dist/vue2/lib/message-input.cjs +37 -3
  26. package/dist/vue2/lib/message-input.cjs.map +1 -1
  27. package/dist/vue2/lib/message-input.js +37 -3
  28. package/dist/vue2/lib/message-input.js.map +1 -1
  29. package/dist/vue2/lib/notice.cjs +10 -1
  30. package/dist/vue2/lib/notice.cjs.map +1 -1
  31. package/dist/vue2/lib/notice.js +10 -1
  32. package/dist/vue2/lib/notice.js.map +1 -1
  33. package/dist/vue2/lib/rich-text-editor.cjs +462 -66
  34. package/dist/vue2/lib/rich-text-editor.cjs.map +1 -1
  35. package/dist/vue2/lib/rich-text-editor.js +463 -67
  36. package/dist/vue2/lib/rich-text-editor.js.map +1 -1
  37. package/dist/vue2/types/common/utils/index.d.ts.map +1 -1
  38. package/dist/vue2/types/components/notice/notice.vue.d.ts +19 -0
  39. package/dist/vue2/types/components/notice/notice.vue.d.ts.map +1 -1
  40. package/dist/vue2/types/components/rich_text_editor/extensions/channels/channel.d.ts +2 -1
  41. package/dist/vue2/types/components/rich_text_editor/extensions/channels/channel.d.ts.map +1 -1
  42. package/dist/vue2/types/components/rich_text_editor/extensions/emoji/emoji.d.ts +1 -0
  43. package/dist/vue2/types/components/rich_text_editor/extensions/emoji/emoji.d.ts.map +1 -1
  44. package/dist/vue2/types/components/rich_text_editor/extensions/mentions/mention.d.ts +2 -1
  45. package/dist/vue2/types/components/rich_text_editor/extensions/mentions/mention.d.ts.map +1 -1
  46. package/dist/vue2/types/components/rich_text_editor/extensions/slash_command/SlashCommandComponent.vue.d.ts +47 -0
  47. package/dist/vue2/types/components/rich_text_editor/extensions/slash_command/SlashCommandComponent.vue.d.ts.map +1 -0
  48. package/dist/vue2/types/components/rich_text_editor/extensions/slash_command/SlashCommandSuggestion.vue.d.ts +17 -0
  49. package/dist/vue2/types/components/rich_text_editor/extensions/slash_command/SlashCommandSuggestion.vue.d.ts.map +1 -0
  50. package/dist/vue2/types/components/rich_text_editor/extensions/slash_command/slash_command.d.ts +2 -0
  51. package/dist/vue2/types/components/rich_text_editor/extensions/slash_command/slash_command.d.ts.map +1 -0
  52. package/dist/vue2/types/components/rich_text_editor/extensions/slash_command/suggestion.d.ts +12 -0
  53. package/dist/vue2/types/components/rich_text_editor/extensions/slash_command/suggestion.d.ts.map +1 -0
  54. package/dist/vue2/types/components/rich_text_editor/rich_text_editor.vue.d.ts +48 -1
  55. package/dist/vue2/types/components/rich_text_editor/rich_text_editor.vue.d.ts.map +1 -1
  56. package/dist/vue2/types/components/rich_text_editor/slash_command_suggestion.d.ts +15 -0
  57. package/dist/vue2/types/components/rich_text_editor/slash_command_suggestion.d.ts.map +1 -0
  58. package/dist/vue2/types/recipes/conversation_view/message_input/message_input.vue.d.ts +38 -2
  59. package/dist/vue2/types/recipes/conversation_view/message_input/message_input.vue.d.ts.map +1 -1
  60. package/dist/vue3/common/utils.cjs +8 -1
  61. package/dist/vue3/common/utils.cjs.map +1 -1
  62. package/dist/vue3/common/utils.js +8 -1
  63. package/dist/vue3/common/utils.js.map +1 -1
  64. package/dist/vue3/component-documentation.json +1 -1
  65. package/dist/vue3/lib/message-input.cjs +8 -1
  66. package/dist/vue3/lib/message-input.cjs.map +1 -1
  67. package/dist/vue3/lib/message-input.js +8 -1
  68. package/dist/vue3/lib/message-input.js.map +1 -1
  69. package/dist/vue3/lib/notice.cjs +10 -1
  70. package/dist/vue3/lib/notice.cjs.map +1 -1
  71. package/dist/vue3/lib/notice.js +10 -1
  72. package/dist/vue3/lib/notice.js.map +1 -1
  73. package/dist/vue3/lib/rich-text-editor.cjs +172 -10
  74. package/dist/vue3/lib/rich-text-editor.cjs.map +1 -1
  75. package/dist/vue3/lib/rich-text-editor.js +173 -11
  76. package/dist/vue3/lib/rich-text-editor.js.map +1 -1
  77. package/dist/vue3/types/common/utils/index.d.ts.map +1 -1
  78. package/dist/vue3/types/components/notice/notice.vue.d.ts +19 -0
  79. package/dist/vue3/types/components/notice/notice.vue.d.ts.map +1 -1
  80. package/dist/vue3/types/components/rich_text_editor/extensions/channels/channel.d.ts +2 -1
  81. package/dist/vue3/types/components/rich_text_editor/extensions/channels/channel.d.ts.map +1 -1
  82. package/dist/vue3/types/components/rich_text_editor/extensions/emoji/emoji.d.ts +1 -0
  83. package/dist/vue3/types/components/rich_text_editor/extensions/emoji/emoji.d.ts.map +1 -1
  84. package/dist/vue3/types/components/rich_text_editor/extensions/mentions/mention.d.ts +2 -1
  85. package/dist/vue3/types/components/rich_text_editor/extensions/mentions/mention.d.ts.map +1 -1
  86. package/dist/vue3/types/components/rich_text_editor/rich_text_editor.vue.d.ts +12 -1
  87. package/dist/vue3/types/components/rich_text_editor/rich_text_editor.vue.d.ts.map +1 -1
  88. package/dist/vue3/types/recipes/conversation_view/message_input/message_input.vue.d.ts +3 -2
  89. package/package.json +70 -68
@@ -18,7 +18,7 @@ import TextAlign from "@tiptap/extension-text-align";
18
18
  import { Node, mergeAttributes, nodeInputRule, nodePasteRule, getMarksBetween, combineTransactionSteps, getChangedRanges, findChildrenInRange, Mark } from "@tiptap/core";
19
19
  import { normalizeComponent } from "../chunks/_plugin-vue2_normalizer-sOSkiPF3.js";
20
20
  import { DtEmoji } from "./emoji.js";
21
- import { shortcodeToEmojiData, codeToEmojiData } from "../common/emoji.js";
21
+ import { codeToEmojiData } from "../common/emoji.js";
22
22
  import { PluginKey, Plugin } from "@tiptap/pm/state";
23
23
  import Suggestion from "@tiptap/suggestion";
24
24
  import { emojisIndexed } from "@dialpad/dialtone-emojis";
@@ -31,10 +31,10 @@ import { DtLink } from "./link.js";
31
31
  import { DtAvatar } from "./avatar.js";
32
32
  import DtIconHash from "@dialpad/dialtone-icons/vue2/hash";
33
33
  import DtIconLock from "@dialpad/dialtone-icons/vue2/lock";
34
+ import emojiRegex from "emoji-regex";
34
35
  import "./skeleton.js";
35
36
  import "../chunks/icon_constants-Dy4MEUJL.js";
36
37
  import "@dialpad/dialtone-icons/icons.json";
37
- import "emoji-regex";
38
38
  import "emoji-toolkit/emoji_strategy.json";
39
39
  import "../chunks/list_item_constants-u1xcN9Dd.js";
40
40
  import "./item-layout.js";
@@ -45,7 +45,7 @@ import "../common/constants.js";
45
45
  import "vue";
46
46
  import "../chunks/link_constants-nWVlXQBs.js";
47
47
  import "./presence.js";
48
- const _sfc_main$7 = {
48
+ const _sfc_main$9 = {
49
49
  name: "EmojiComponent",
50
50
  components: {
51
51
  NodeViewWrapper,
@@ -53,23 +53,23 @@ const _sfc_main$7 = {
53
53
  },
54
54
  props: nodeViewProps
55
55
  };
56
- var _sfc_render$7 = function render() {
56
+ var _sfc_render$9 = function render() {
57
57
  var _vm = this, _c = _vm._self._c;
58
58
  return _c("node-view-wrapper", { staticClass: "d-d-inline-block d-va-bottom d-lh0" }, [_c("dt-emoji", { attrs: { "size": "500", "code": _vm.node.attrs.code } })], 1);
59
59
  };
60
- var _sfc_staticRenderFns$7 = [];
61
- var __component__$7 = /* @__PURE__ */ normalizeComponent(
62
- _sfc_main$7,
63
- _sfc_render$7,
64
- _sfc_staticRenderFns$7,
60
+ var _sfc_staticRenderFns$9 = [];
61
+ var __component__$9 = /* @__PURE__ */ normalizeComponent(
62
+ _sfc_main$9,
63
+ _sfc_render$9,
64
+ _sfc_staticRenderFns$9,
65
65
  false,
66
66
  null,
67
67
  null,
68
68
  null,
69
69
  null
70
70
  );
71
- const EmojiComponent = __component__$7.exports;
72
- const _sfc_main$6 = {
71
+ const EmojiComponent = __component__$9.exports;
72
+ const _sfc_main$8 = {
73
73
  name: "SuggestionList",
74
74
  components: {
75
75
  DtListItem
@@ -152,11 +152,14 @@ const _sfc_main$6 = {
152
152
  case "channel":
153
153
  this.command({ name: item.name, id: item.id });
154
154
  break;
155
+ case "slash-command":
156
+ this.command({ command: item.command });
157
+ break;
155
158
  }
156
159
  }
157
160
  }
158
161
  };
159
- var _sfc_render$6 = function render2() {
162
+ var _sfc_render$8 = function render2() {
160
163
  var _vm = this, _c = _vm._self._c;
161
164
  return _c("div", { staticClass: "d-popover__dialog" }, [_c("ul", { directives: [{ name: "show", rawName: "v-show", value: _vm.items.length, expression: "items.length" }], ref: "suggestionList", staticClass: "dt-suggestion-list" }, _vm._l(_vm.items, function(item, index) {
162
165
  return _c("dt-list-item", { key: item.id, class: [
@@ -171,19 +174,19 @@ var _sfc_render$6 = function render2() {
171
174
  } } }, [_c(_vm.itemComponent, { tag: "component", attrs: { "item": item } })], 1);
172
175
  }), 1)]);
173
176
  };
174
- var _sfc_staticRenderFns$6 = [];
175
- var __component__$6 = /* @__PURE__ */ normalizeComponent(
176
- _sfc_main$6,
177
- _sfc_render$6,
178
- _sfc_staticRenderFns$6,
177
+ var _sfc_staticRenderFns$8 = [];
178
+ var __component__$8 = /* @__PURE__ */ normalizeComponent(
179
+ _sfc_main$8,
180
+ _sfc_render$8,
181
+ _sfc_staticRenderFns$8,
179
182
  false,
180
183
  null,
181
184
  null,
182
185
  null,
183
186
  null
184
187
  );
185
- const SuggestionList = __component__$6.exports;
186
- const _sfc_main$5 = {
188
+ const SuggestionList = __component__$8.exports;
189
+ const _sfc_main$7 = {
187
190
  name: "EmojiSuggestion",
188
191
  components: {
189
192
  DtEmoji,
@@ -196,22 +199,22 @@ const _sfc_main$5 = {
196
199
  }
197
200
  }
198
201
  };
199
- var _sfc_render$5 = function render3() {
202
+ var _sfc_render$7 = function render3() {
200
203
  var _vm = this, _c = _vm._self._c;
201
204
  return _c("dt-stack", { attrs: { "direction": "row", "gap": "400" } }, [_c("dt-emoji", { attrs: { "size": "200", "code": _vm.item.code } }), _vm._v(" " + _vm._s(_vm.item.code) + " ")], 1);
202
205
  };
203
- var _sfc_staticRenderFns$5 = [];
204
- var __component__$5 = /* @__PURE__ */ normalizeComponent(
205
- _sfc_main$5,
206
- _sfc_render$5,
207
- _sfc_staticRenderFns$5,
206
+ var _sfc_staticRenderFns$7 = [];
207
+ var __component__$7 = /* @__PURE__ */ normalizeComponent(
208
+ _sfc_main$7,
209
+ _sfc_render$7,
210
+ _sfc_staticRenderFns$7,
208
211
  false,
209
212
  null,
210
213
  null,
211
214
  null,
212
215
  null
213
216
  );
214
- const EmojiSuggestion = __component__$5.exports;
217
+ const EmojiSuggestion = __component__$7.exports;
215
218
  const suggestionOptions = {
216
219
  items: ({ query }) => {
217
220
  if (query.length < 2) {
@@ -302,7 +305,7 @@ const suggestionOptions = {
302
305
  };
303
306
  const EmojiPluginKey = new PluginKey("emoji");
304
307
  const inputShortCodeRegex = /:\w+:$/;
305
- const pasteShortCodeRegex = /:\w+:/g;
308
+ const emojiShortCodeRegex = /:\w+:/g;
306
309
  const inputUnicodeRegex = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])$/;
307
310
  const pasteUnicodeRegex = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g;
308
311
  const inputRuleMatch = (match) => {
@@ -315,7 +318,7 @@ const inputRuleMatch = (match) => {
315
318
  }
316
319
  };
317
320
  const shortCodePasteMatch = (text) => {
318
- const matches = [...text.matchAll(pasteShortCodeRegex)];
321
+ const matches = [...text.matchAll(emojiShortCodeRegex)];
319
322
  return matches.filter((match) => codeToEmojiData(match[0])).map((match) => ({
320
323
  index: match.index,
321
324
  text: match[0],
@@ -384,7 +387,7 @@ const Emoji = Node.create({
384
387
  },
385
388
  type: this.type,
386
389
  getAttributes(attrs) {
387
- const unicode = shortcodeToEmojiData(attrs[0]).unicode_output;
390
+ const unicode = codeToEmojiData(attrs[0]).unicode_output;
388
391
  const emoji = String.fromCodePoint(parseInt(unicode, 16));
389
392
  return {
390
393
  code: emoji,
@@ -587,7 +590,7 @@ const Link = Mark.create({
587
590
  ];
588
591
  }
589
592
  });
590
- const _sfc_main$4 = {
593
+ const _sfc_main$6 = {
591
594
  name: "MentionComponent",
592
595
  components: {
593
596
  NodeViewWrapper,
@@ -600,23 +603,50 @@ const _sfc_main$4 = {
600
603
  }
601
604
  }
602
605
  };
603
- var _sfc_render$4 = function render4() {
606
+ var _sfc_render$6 = function render4() {
604
607
  var _vm = this, _c = _vm._self._c;
605
608
  return _c("node-view-wrapper", { staticClass: "d-d-inline-block" }, [_c("dt-link", { attrs: { "kind": "mention" } }, [_vm._v(" " + _vm._s(_vm.text) + " ")])], 1);
606
609
  };
607
- var _sfc_staticRenderFns$4 = [];
608
- var __component__$4 = /* @__PURE__ */ normalizeComponent(
609
- _sfc_main$4,
610
- _sfc_render$4,
611
- _sfc_staticRenderFns$4,
610
+ var _sfc_staticRenderFns$6 = [];
611
+ var __component__$6 = /* @__PURE__ */ normalizeComponent(
612
+ _sfc_main$6,
613
+ _sfc_render$6,
614
+ _sfc_staticRenderFns$6,
612
615
  false,
613
616
  null,
614
617
  null,
615
618
  null,
616
619
  null
617
620
  );
618
- const MentionComponent = __component__$4.exports;
621
+ const MentionComponent = __component__$6.exports;
622
+ const mentionRegex = /@([\w.-]+)[^\w.-]?/g;
623
+ const mentionPasteMatch = (text, suggestions) => {
624
+ const matches = [...text.matchAll(mentionRegex)];
625
+ return matches.filter((match) => suggestions.some(({ id }) => id === match[1].trim())).map((match) => {
626
+ let mention = match[1];
627
+ if (!mention.endsWith(" "))
628
+ mention += " ";
629
+ return {
630
+ index: match.index,
631
+ text: mention,
632
+ match
633
+ };
634
+ });
635
+ };
636
+ const mentionInputMatch = (text, suggestions) => {
637
+ const match = text.match(/@([\w.-]+)[^\w.-]$/);
638
+ if (!match || !suggestions.some(({ id }) => id === match[1]))
639
+ return;
640
+ return {
641
+ index: match.index,
642
+ text: match[0],
643
+ match
644
+ };
645
+ };
619
646
  const MentionPlugin = Mention.extend({
647
+ name: "mention",
648
+ group: "inline",
649
+ inline: true,
620
650
  addNodeView() {
621
651
  return VueNodeViewRenderer(MentionComponent);
622
652
  },
@@ -644,10 +674,41 @@ const MentionPlugin = Mention.extend({
644
674
  return `@${node.attrs.id}`;
645
675
  },
646
676
  renderHTML({ HTMLAttributes }) {
647
- return ["mention-component", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
677
+ return ["mention-component", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
678
+ },
679
+ addInputRules() {
680
+ var _a;
681
+ const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" });
682
+ return [
683
+ nodeInputRule({
684
+ find: (text) => mentionInputMatch(text, suggestions),
685
+ type: this.type,
686
+ getAttributes(attrs) {
687
+ return suggestions.find(({ id }) => id === attrs[0].replace("@", "").trim());
688
+ }
689
+ })
690
+ ];
691
+ },
692
+ addPasteRules() {
693
+ var _a;
694
+ const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" });
695
+ return [
696
+ nodePasteRule({
697
+ find: (text) => mentionPasteMatch(text, suggestions),
698
+ type: this.type,
699
+ getAttributes(attrs) {
700
+ return suggestions.find(({ id }) => id === attrs[0].trim());
701
+ }
702
+ })
703
+ ];
704
+ }
705
+ }).configure({
706
+ suggestion: {
707
+ char: "@",
708
+ pluginKey: new PluginKey("mentionSuggestion")
648
709
  }
649
710
  });
650
- const _sfc_main$3 = {
711
+ const _sfc_main$5 = {
651
712
  name: "ChannelComponent",
652
713
  components: {
653
714
  NodeViewWrapper,
@@ -660,24 +721,50 @@ const _sfc_main$3 = {
660
721
  }
661
722
  }
662
723
  };
663
- var _sfc_render$3 = function render5() {
724
+ var _sfc_render$5 = function render5() {
664
725
  var _vm = this, _c = _vm._self._c;
665
726
  return _c("node-view-wrapper", { staticClass: "d-d-inline-block" }, [_c("dt-link", { attrs: { "kind": "mention" } }, [_vm._v(" " + _vm._s(_vm.text) + " ")])], 1);
666
727
  };
667
- var _sfc_staticRenderFns$3 = [];
668
- var __component__$3 = /* @__PURE__ */ normalizeComponent(
669
- _sfc_main$3,
670
- _sfc_render$3,
671
- _sfc_staticRenderFns$3,
728
+ var _sfc_staticRenderFns$5 = [];
729
+ var __component__$5 = /* @__PURE__ */ normalizeComponent(
730
+ _sfc_main$5,
731
+ _sfc_render$5,
732
+ _sfc_staticRenderFns$5,
672
733
  false,
673
734
  null,
674
735
  null,
675
736
  null,
676
737
  null
677
738
  );
678
- const ChannelComponent = __component__$3.exports;
739
+ const ChannelComponent = __component__$5.exports;
740
+ const channelRegex = /#([\w-]+)[^\w-]?/g;
741
+ const channelPasteMatch = (text, suggestions) => {
742
+ const matches = [...text.matchAll(channelRegex)];
743
+ return matches.filter((match) => suggestions.some(({ id }) => id === match[1].trim())).map((match) => {
744
+ let channel = match[1];
745
+ if (!channel.endsWith(" "))
746
+ channel += " ";
747
+ return {
748
+ index: match.index,
749
+ text: channel,
750
+ match
751
+ };
752
+ });
753
+ };
754
+ const channelInputMatch = (text, suggestions) => {
755
+ const match = text.match(/#([\w-]+)[^\w-]$/);
756
+ if (!match || !suggestions.some(({ id }) => id === match[1]))
757
+ return;
758
+ return {
759
+ index: match.index,
760
+ text: match[0],
761
+ match
762
+ };
763
+ };
679
764
  const ChannelPlugin = Mention.extend({
680
765
  name: "channel",
766
+ group: "inline",
767
+ inline: true,
681
768
  addNodeView() {
682
769
  return VueNodeViewRenderer(ChannelComponent);
683
770
  },
@@ -705,7 +792,33 @@ const ChannelPlugin = Mention.extend({
705
792
  return `#${node.attrs.id}`;
706
793
  },
707
794
  renderHTML({ HTMLAttributes }) {
708
- return ["channel-component", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
795
+ return ["channel-component", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
796
+ },
797
+ addInputRules() {
798
+ var _a;
799
+ const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" });
800
+ return [
801
+ nodeInputRule({
802
+ find: (text) => channelInputMatch(text, suggestions),
803
+ type: this.type,
804
+ getAttributes(attrs) {
805
+ return suggestions.find(({ id }) => id === attrs[0].replace("#", "").trim());
806
+ }
807
+ })
808
+ ];
809
+ },
810
+ addPasteRules() {
811
+ var _a;
812
+ const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" });
813
+ return [
814
+ nodePasteRule({
815
+ find: (text) => channelPasteMatch(text, suggestions),
816
+ type: this.type,
817
+ getAttributes(attrs) {
818
+ return suggestions.find(({ id }) => id === attrs[0].trim());
819
+ }
820
+ })
821
+ ];
709
822
  }
710
823
  }).configure({
711
824
  suggestion: {
@@ -713,6 +826,118 @@ const ChannelPlugin = Mention.extend({
713
826
  pluginKey: new PluginKey("channelSuggestion")
714
827
  }
715
828
  });
829
+ const _sfc_main$4 = {
830
+ name: "SlashCommandsComponent",
831
+ components: {
832
+ NodeViewWrapper
833
+ },
834
+ props: nodeViewProps,
835
+ emits: ["selected-command"],
836
+ computed: {
837
+ text() {
838
+ return "/" + this.$props.node.attrs.command;
839
+ }
840
+ },
841
+ created() {
842
+ this.$parent.$emit("selected-command", this.$props.node.attrs.command);
843
+ }
844
+ };
845
+ var _sfc_render$4 = function render6() {
846
+ var _vm = this, _c = _vm._self._c;
847
+ return _c("node-view-wrapper", { staticClass: "d-d-inline-block" }, [_vm._v(" " + _vm._s(_vm.text) + " ")]);
848
+ };
849
+ var _sfc_staticRenderFns$4 = [];
850
+ var __component__$4 = /* @__PURE__ */ normalizeComponent(
851
+ _sfc_main$4,
852
+ _sfc_render$4,
853
+ _sfc_staticRenderFns$4,
854
+ false,
855
+ null,
856
+ null,
857
+ null,
858
+ null
859
+ );
860
+ const SlashCommandComponent = __component__$4.exports;
861
+ const slashCommandPasteMatch = (text, slashCommandRegex) => {
862
+ const matches = [...text.matchAll(slashCommandRegex)];
863
+ return matches.map((match) => {
864
+ let slashCommand = match[2];
865
+ if (!slashCommand.endsWith(" "))
866
+ slashCommand += " ";
867
+ return {
868
+ index: match.index,
869
+ text: slashCommand,
870
+ match
871
+ };
872
+ });
873
+ };
874
+ const SlashCommandPlugin = Mention.extend({
875
+ name: "slash-commands",
876
+ group: "inline",
877
+ inline: true,
878
+ addNodeView() {
879
+ return VueNodeViewRenderer(SlashCommandComponent);
880
+ },
881
+ parseHTML() {
882
+ return [
883
+ {
884
+ tag: "command-component"
885
+ }
886
+ ];
887
+ },
888
+ addAttributes() {
889
+ return {
890
+ command: {
891
+ default: ""
892
+ },
893
+ paramentersExample: {
894
+ default: ""
895
+ },
896
+ description: {
897
+ default: ""
898
+ }
899
+ };
900
+ },
901
+ renderText({ node }) {
902
+ return `/${node.attrs.command}`;
903
+ },
904
+ renderHTML({ HTMLAttributes }) {
905
+ return ["command-component", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
906
+ },
907
+ addInputRules() {
908
+ var _a;
909
+ const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" }).map((suggestion) => suggestion.command);
910
+ const slashCommandRegex = new RegExp(`^((?:\\/)(${suggestions.join("|")})) $`);
911
+ return [
912
+ nodeInputRule({
913
+ find: slashCommandRegex,
914
+ type: this.type,
915
+ getAttributes(attrs) {
916
+ return { command: attrs[2] };
917
+ }
918
+ })
919
+ ];
920
+ },
921
+ addPasteRules() {
922
+ var _a;
923
+ const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" }).map((suggestion) => suggestion.command);
924
+ const slashCommandRegex = new RegExp(`^((?:\\/)(${suggestions.join("|")})) ?$`, "g");
925
+ return [
926
+ nodePasteRule({
927
+ find: (text) => slashCommandPasteMatch(text, slashCommandRegex),
928
+ type: this.type,
929
+ getAttributes(attrs) {
930
+ return { command: attrs[0].trim() };
931
+ }
932
+ })
933
+ ];
934
+ }
935
+ }).configure({
936
+ suggestion: {
937
+ char: "/",
938
+ pluginKey: new PluginKey("slashCommandSuggestion")
939
+ }
940
+ });
716
941
  const RICH_TEXT_EDITOR_OUTPUT_FORMATS = [
717
942
  "text",
718
943
  "json",
@@ -731,7 +956,7 @@ const RICH_TEXT_EDITOR_SUPPORTED_LINK_PROTOCOLS = [
731
956
  "sftp",
732
957
  "mailto"
733
958
  ];
734
- const _sfc_main$2 = {
959
+ const _sfc_main$3 = {
735
960
  name: "MentionSuggestion",
736
961
  components: {
737
962
  DtAvatar,
@@ -752,22 +977,22 @@ const _sfc_main$2 = {
752
977
  }
753
978
  }
754
979
  };
755
- var _sfc_render$2 = function render6() {
980
+ var _sfc_render$3 = function render7() {
756
981
  var _vm = this, _c = _vm._self._c;
757
982
  return _c("dt-stack", { attrs: { "direction": "row", "gap": "400" } }, [_c("dt-avatar", { attrs: { "full-name": _vm.name, "image-src": _vm.avatarSrc, "image-alt": _vm.name, "size": "xs" } }), _vm._v(" " + _vm._s(_vm.name) + " ")], 1);
758
983
  };
759
- var _sfc_staticRenderFns$2 = [];
760
- var __component__$2 = /* @__PURE__ */ normalizeComponent(
761
- _sfc_main$2,
762
- _sfc_render$2,
763
- _sfc_staticRenderFns$2,
984
+ var _sfc_staticRenderFns$3 = [];
985
+ var __component__$3 = /* @__PURE__ */ normalizeComponent(
986
+ _sfc_main$3,
987
+ _sfc_render$3,
988
+ _sfc_staticRenderFns$3,
764
989
  false,
765
990
  null,
766
991
  null,
767
992
  null,
768
993
  null
769
994
  );
770
- const MentionSuggestion = __component__$2.exports;
995
+ const MentionSuggestion = __component__$3.exports;
771
996
  const mentionSuggestion = {
772
997
  // This function comes from the user and passed to the editor directly.
773
998
  // This will also activate the mention plugin on the editor
@@ -823,7 +1048,7 @@ const mentionSuggestion = {
823
1048
  };
824
1049
  }
825
1050
  };
826
- const _sfc_main$1 = {
1051
+ const _sfc_main$2 = {
827
1052
  name: "ChannelSuggestion",
828
1053
  components: {
829
1054
  DtStack,
@@ -842,10 +1067,101 @@ const _sfc_main$1 = {
842
1067
  }
843
1068
  }
844
1069
  };
845
- var _sfc_render$1 = function render7() {
1070
+ var _sfc_render$2 = function render8() {
846
1071
  var _vm = this, _c = _vm._self._c;
847
1072
  return _c("dt-stack", { attrs: { "direction": "row", "gap": "400" } }, [!_vm.item.locked ? _c("dt-icon-hash", { attrs: { "size": "300" } }) : _c("dt-icon-lock", { attrs: { "size": "300" } }), _c("span", [_vm._v(_vm._s(_vm.name))])], 1);
848
1073
  };
1074
+ var _sfc_staticRenderFns$2 = [];
1075
+ var __component__$2 = /* @__PURE__ */ normalizeComponent(
1076
+ _sfc_main$2,
1077
+ _sfc_render$2,
1078
+ _sfc_staticRenderFns$2,
1079
+ false,
1080
+ null,
1081
+ null,
1082
+ null,
1083
+ null
1084
+ );
1085
+ const ChannelSuggestion = __component__$2.exports;
1086
+ const channelSuggestion = {
1087
+ // This function comes from the user and passed to the editor directly.
1088
+ // This will also activate the mention plugin on the editor
1089
+ // items: ({ query }) => { return [] },
1090
+ allowSpaces: true,
1091
+ render: () => {
1092
+ let component;
1093
+ let popup;
1094
+ return {
1095
+ onStart: (props) => {
1096
+ component = new VueRenderer(SuggestionList, {
1097
+ parent: void 0,
1098
+ propsData: {
1099
+ itemComponent: ChannelSuggestion,
1100
+ itemType: "channel",
1101
+ ...props
1102
+ },
1103
+ editor: props.editor
1104
+ });
1105
+ if (!props.clientRect) {
1106
+ return;
1107
+ }
1108
+ popup = tippy("body", {
1109
+ getReferenceClientRect: props.clientRect,
1110
+ appendTo: () => document.body,
1111
+ content: component.element,
1112
+ showOnCreate: true,
1113
+ interactive: true,
1114
+ trigger: "manual",
1115
+ placement: "top-start"
1116
+ });
1117
+ },
1118
+ onUpdate(props) {
1119
+ component.updateProps(props);
1120
+ if (!props.clientRect) {
1121
+ return;
1122
+ }
1123
+ popup[0].setProps({
1124
+ getReferenceClientRect: props.clientRect
1125
+ });
1126
+ },
1127
+ onKeyDown(props) {
1128
+ if (props.event.key === "Escape") {
1129
+ popup[0].hide();
1130
+ return true;
1131
+ }
1132
+ return component == null ? void 0 : component.ref.onKeyDown(props);
1133
+ },
1134
+ onExit() {
1135
+ popup[0].destroy();
1136
+ component.destroy();
1137
+ }
1138
+ };
1139
+ }
1140
+ };
1141
+ const _sfc_main$1 = {
1142
+ name: "SlashCommandSuggestion",
1143
+ props: {
1144
+ item: {
1145
+ type: Object,
1146
+ required: true
1147
+ }
1148
+ },
1149
+ computed: {
1150
+ command() {
1151
+ return this.item.command;
1152
+ },
1153
+ description() {
1154
+ return this.item.description;
1155
+ },
1156
+ parametersExample() {
1157
+ return this.item.parametersExample;
1158
+ }
1159
+ }
1160
+ };
1161
+ var _sfc_render$1 = function render9() {
1162
+ var _vm = this, _c = _vm._self._c;
1163
+ return _c("div", [_c("div", { staticClass: "d-body--md-compact" }, [_c("span", [_vm._v("/" + _vm._s(_vm.command))]), _vm.parametersExample ? _c("span", [_vm._v(" " + _vm._s(_vm.parametersExample))]) : _vm._e()]), _c("div", { staticClass: "d-body--sm" }, [_vm._v(" " + _vm._s(_vm.description) + " ")])]);
1164
+ };
849
1165
  var _sfc_staticRenderFns$1 = [];
850
1166
  var __component__$1 = /* @__PURE__ */ normalizeComponent(
851
1167
  _sfc_main$1,
@@ -857,12 +1173,13 @@ var __component__$1 = /* @__PURE__ */ normalizeComponent(
857
1173
  null,
858
1174
  null
859
1175
  );
860
- const ChannelSuggestion = __component__$1.exports;
861
- const channelSuggestion = {
1176
+ const SlashCommandSuggestion = __component__$1.exports;
1177
+ const slashCommandSuggestion = {
862
1178
  // This function comes from the user and passed to the editor directly.
863
1179
  // This will also activate the mention plugin on the editor
864
1180
  // items: ({ query }) => { return [] },
865
1181
  allowSpaces: true,
1182
+ startOfLine: true,
866
1183
  render: () => {
867
1184
  let component;
868
1185
  let popup;
@@ -871,8 +1188,8 @@ const channelSuggestion = {
871
1188
  component = new VueRenderer(SuggestionList, {
872
1189
  parent: void 0,
873
1190
  propsData: {
874
- itemComponent: ChannelSuggestion,
875
- itemType: "channel",
1191
+ itemComponent: SlashCommandSuggestion,
1192
+ itemType: "slash-command",
876
1193
  ...props
877
1194
  },
878
1195
  editor: props.editor
@@ -1035,6 +1352,23 @@ const _sfc_main = {
1035
1352
  type: Object,
1036
1353
  default: null
1037
1354
  },
1355
+ /**
1356
+ * suggestion object containing the items query function.
1357
+ * The valid keys passed into this object can be found here: https://tiptap.dev/api/utilities/suggestion
1358
+ *
1359
+ * The only required key is the items function which is used to query the slash commands for suggestion.
1360
+ * items({ query }) => { return [SlashCommandObject]; }
1361
+ * SlashCommandObject format:
1362
+ * { command: string, description: string, parametersExample?: string }
1363
+ * The "parametersExample" parameter is optional, and describes an example
1364
+ * of the parameters that command can take.
1365
+ *
1366
+ * When null, it does not add the plugin.
1367
+ */
1368
+ slashCommandSuggestion: {
1369
+ type: Object,
1370
+ default: null
1371
+ },
1038
1372
  /**
1039
1373
  * Whether the input allows for block quote.
1040
1374
  */
@@ -1087,7 +1421,7 @@ const _sfc_main = {
1087
1421
  "input",
1088
1422
  /**
1089
1423
  * Event to sync the value with the parent
1090
- * @event input
1424
+ * @event update:value
1091
1425
  * @type {String|JSON}
1092
1426
  */
1093
1427
  "update:value",
@@ -1107,7 +1441,8 @@ const _sfc_main = {
1107
1441
  data() {
1108
1442
  return {
1109
1443
  editor: null,
1110
- popoverOpened: false
1444
+ popoverOpened: false,
1445
+ internalValue: this.value
1111
1446
  };
1112
1447
  },
1113
1448
  computed: {
@@ -1171,6 +1506,10 @@ const _sfc_main = {
1171
1506
  const suggestionObject = { ...this.channelSuggestion, ...channelSuggestion };
1172
1507
  extensions.push(ChannelPlugin.configure({ suggestion: suggestionObject }));
1173
1508
  }
1509
+ if (this.slashCommandSuggestion) {
1510
+ const suggestionObject = { ...this.slashCommandSuggestion, ...slashCommandSuggestion };
1511
+ extensions.push(SlashCommandPlugin.configure({ suggestion: suggestionObject }));
1512
+ }
1174
1513
  extensions.push(Emoji);
1175
1514
  extensions.push(TextAlign.configure({
1176
1515
  types: ["paragraph"],
@@ -1224,7 +1563,8 @@ const _sfc_main = {
1224
1563
  if (newValue === currentValue) {
1225
1564
  return;
1226
1565
  }
1227
- this.editor.commands.setContent(newValue, false);
1566
+ this.internalValue = newValue;
1567
+ this.insertContent();
1228
1568
  }
1229
1569
  },
1230
1570
  created() {
@@ -1234,10 +1574,12 @@ const _sfc_main = {
1234
1574
  this.destroyEditor();
1235
1575
  },
1236
1576
  methods: {
1577
+ onSelectedCommand(command) {
1578
+ this.$emit("selected-command", command);
1579
+ },
1237
1580
  createEditor() {
1238
1581
  this.editor = new Editor({
1239
1582
  autofocus: this.autoFocus,
1240
- content: this.value,
1241
1583
  editable: this.editable,
1242
1584
  extensions: this.extensions,
1243
1585
  editorProps: {
@@ -1247,8 +1589,62 @@ const _sfc_main = {
1247
1589
  }
1248
1590
  }
1249
1591
  });
1592
+ this.insertContent();
1250
1593
  this.addEditorListeners();
1251
1594
  },
1595
+ /**
1596
+ * This function is necessary as tiptap doesn't render the content passed
1597
+ * directly through `editor.commands.setContent` the content passed down to it
1598
+ * should be already parsed. So We're parsing the elements into it's corresponding
1599
+ * HTML version before setting it.
1600
+ */
1601
+ insertContent() {
1602
+ this.parseMentions();
1603
+ this.parseChannels();
1604
+ this.parseEmojis();
1605
+ this.editor.commands.setContent(this.internalValue, true);
1606
+ },
1607
+ parseEmojis() {
1608
+ const matches = [...this.value.matchAll(emojiRegex()), ...this.value.matchAll(emojiShortCodeRegex)];
1609
+ if (!matches)
1610
+ return;
1611
+ matches.forEach((match) => {
1612
+ const emoji = codeToEmojiData(match[0]);
1613
+ if (!emoji)
1614
+ return;
1615
+ this.internalValue = this.internalValue.replace(new RegExp(` ${match[0]}`), ` <emoji-component code="${emoji.shortname}"></emoji-component>`);
1616
+ });
1617
+ },
1618
+ parseChannels() {
1619
+ if (!this.channelSuggestion)
1620
+ return;
1621
+ const suggestions = this.channelSuggestion.items({ query: "" });
1622
+ const matches = [...this.value.matchAll(channelRegex)].filter((match) => suggestions.some(({ id }) => id === match[1]));
1623
+ if (!matches)
1624
+ return;
1625
+ matches.forEach((match) => {
1626
+ const channel = suggestions.find(({ id }) => id === match[1]);
1627
+ this.internalValue = this.internalValue.replace(
1628
+ `#${match[1]}`,
1629
+ /** The space at the beginning is important as tiptap removes that while rendering.
1630
+ * So if multiple mentions, channels or emojis are next to each other it will fail
1631
+ */
1632
+ ` <channel-component name="${channel.name}" id="${channel.id}"></channel-component>`
1633
+ );
1634
+ });
1635
+ },
1636
+ parseMentions() {
1637
+ if (!this.mentionSuggestion)
1638
+ return;
1639
+ const suggestions = this.mentionSuggestion.items({ query: "" });
1640
+ const matches = [...this.value.matchAll(mentionRegex)].filter((match) => suggestions.some(({ id }) => id === match[1]));
1641
+ if (!matches)
1642
+ return;
1643
+ matches.forEach((match) => {
1644
+ const mention = suggestions.find(({ id }) => id === match[1]);
1645
+ this.internalValue = this.internalValue.replace(`@${match[1]}`, ` <mention-component name="${mention.name}" id="${mention.id}"></mention-component>`);
1646
+ });
1647
+ },
1252
1648
  destroyEditor() {
1253
1649
  this.editor.destroy();
1254
1650
  },
@@ -1295,9 +1691,9 @@ const _sfc_main = {
1295
1691
  }
1296
1692
  }
1297
1693
  };
1298
- var _sfc_render = function render8() {
1694
+ var _sfc_render = function render10() {
1299
1695
  var _vm = this, _c = _vm._self._c;
1300
- return _c("editor-content", { staticClass: "dt-rich-text-editor", attrs: { "editor": _vm.editor, "data-qa": "dt-rich-text-editor" } });
1696
+ return _c("editor-content", { staticClass: "dt-rich-text-editor", attrs: { "editor": _vm.editor, "data-qa": "dt-rich-text-editor" }, on: { "selected-command": _vm.onSelectedCommand } });
1301
1697
  };
1302
1698
  var _sfc_staticRenderFns = [];
1303
1699
  var __component__ = /* @__PURE__ */ normalizeComponent(