@dialpad/dialtone-vue 2.129.0 → 2.130.2

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