@dialpad/dialtone-vue 3.122.0 → 3.123.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.
- package/dist/common/utils.cjs +8 -1
- package/dist/common/utils.cjs.map +1 -1
- package/dist/common/utils.js +8 -1
- package/dist/common/utils.js.map +1 -1
- package/dist/lib/message-input.cjs +46 -40
- package/dist/lib/message-input.cjs.map +1 -1
- package/dist/lib/message-input.js +47 -41
- package/dist/lib/message-input.js.map +1 -1
- package/dist/lib/rich-text-editor.cjs +173 -11
- package/dist/lib/rich-text-editor.cjs.map +1 -1
- package/dist/lib/rich-text-editor.js +174 -12
- package/dist/lib/rich-text-editor.js.map +1 -1
- package/dist/lib/tooltip.cjs +5 -4
- package/dist/lib/tooltip.cjs.map +1 -1
- package/dist/lib/tooltip.js +5 -4
- package/dist/lib/tooltip.js.map +1 -1
- package/dist/types/common/utils/index.d.ts.map +1 -1
- package/dist/types/components/datepicker/datepicker.vue.d.ts +1 -1
- package/dist/types/components/emoji_picker/emoji_picker.vue.d.ts +1 -1
- package/dist/types/components/emoji_picker/modules/emoji_selector.vue.d.ts +1 -1
- package/dist/types/components/emoji_picker/modules/emoji_skin_selector.vue.d.ts +1 -1
- package/dist/types/components/emoji_picker/modules/emoji_tabset.vue.d.ts +1 -1
- package/dist/types/components/hovercard/hovercard.vue.d.ts +1 -1
- package/dist/types/components/rich_text_editor/extensions/channels/channel.d.ts +2 -1
- package/dist/types/components/rich_text_editor/extensions/channels/channel.d.ts.map +1 -1
- package/dist/types/components/rich_text_editor/extensions/emoji/emoji.d.ts +1 -0
- package/dist/types/components/rich_text_editor/extensions/emoji/emoji.d.ts.map +1 -1
- package/dist/types/components/rich_text_editor/extensions/mentions/mention.d.ts +2 -1
- package/dist/types/components/rich_text_editor/extensions/mentions/mention.d.ts.map +1 -1
- package/dist/types/components/rich_text_editor/rich_text_editor.vue.d.ts +12 -1
- package/dist/types/components/rich_text_editor/rich_text_editor.vue.d.ts.map +1 -1
- package/dist/types/recipes/conversation_view/message_input/message_input.vue.d.ts +3 -2
- package/package.json +24 -24
|
@@ -19,7 +19,7 @@ import { Node, mergeAttributes, nodeInputRule, nodePasteRule, getMarksBetween, c
|
|
|
19
19
|
import { resolveComponent, openBlock, createBlock, withCtx, createVNode, createElementBlock, withDirectives, createElementVNode, Fragment, renderList, normalizeClass, withModifiers, resolveDynamicComponent, vShow, createTextVNode, toDisplayString, markRaw } from "vue";
|
|
20
20
|
import { _export_sfc } from "../chunks/_plugin-vue_export-helper-caHeSgYY.js";
|
|
21
21
|
import { DtEmoji } from "./emoji.js";
|
|
22
|
-
import {
|
|
22
|
+
import { codeToEmojiData } from "../common/emoji.js";
|
|
23
23
|
import { PluginKey, Plugin } from "@tiptap/pm/state";
|
|
24
24
|
import Suggestion from "@tiptap/suggestion";
|
|
25
25
|
import { emojisIndexed } from "@dialpad/dialtone-emojis";
|
|
@@ -32,10 +32,10 @@ import { DtLink } from "./link.js";
|
|
|
32
32
|
import { DtAvatar } from "./avatar.js";
|
|
33
33
|
import DtIconHash from "@dialpad/dialtone-icons/vue3/hash";
|
|
34
34
|
import DtIconLock from "@dialpad/dialtone-icons/vue3/lock";
|
|
35
|
+
import emojiRegex from "emoji-regex";
|
|
35
36
|
import "./skeleton.js";
|
|
36
37
|
import "../chunks/icon_constants-Dy4MEUJL.js";
|
|
37
38
|
import "@dialpad/dialtone-icons/icons.json";
|
|
38
|
-
import "emoji-regex";
|
|
39
39
|
import "../chunks/list_item_constants-u1xcN9Dd.js";
|
|
40
40
|
import "./item-layout.js";
|
|
41
41
|
import "./icon.js";
|
|
@@ -305,7 +305,7 @@ const suggestionOptions = {
|
|
|
305
305
|
};
|
|
306
306
|
const EmojiPluginKey = new PluginKey("emoji");
|
|
307
307
|
const inputShortCodeRegex = /:\w+:$/;
|
|
308
|
-
const
|
|
308
|
+
const emojiShortCodeRegex = /:\w+:/g;
|
|
309
309
|
const inputUnicodeRegex = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])$/;
|
|
310
310
|
const pasteUnicodeRegex = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g;
|
|
311
311
|
const inputRuleMatch = (match) => {
|
|
@@ -318,7 +318,7 @@ const inputRuleMatch = (match) => {
|
|
|
318
318
|
}
|
|
319
319
|
};
|
|
320
320
|
const shortCodePasteMatch = (text) => {
|
|
321
|
-
const matches = [...text.matchAll(
|
|
321
|
+
const matches = [...text.matchAll(emojiShortCodeRegex)];
|
|
322
322
|
return matches.filter((match) => codeToEmojiData(match[0])).map((match) => ({
|
|
323
323
|
index: match.index,
|
|
324
324
|
text: match[0],
|
|
@@ -387,7 +387,7 @@ const Emoji = Node.create({
|
|
|
387
387
|
},
|
|
388
388
|
type: this.type,
|
|
389
389
|
getAttributes(attrs) {
|
|
390
|
-
const unicode =
|
|
390
|
+
const unicode = codeToEmojiData(attrs[0]).unicode_output;
|
|
391
391
|
const emoji = String.fromCodePoint(parseInt(unicode, 16));
|
|
392
392
|
return {
|
|
393
393
|
code: emoji,
|
|
@@ -565,7 +565,7 @@ function autolink(options) {
|
|
|
565
565
|
});
|
|
566
566
|
}
|
|
567
567
|
const defaultAttributes = {
|
|
568
|
-
class: "d-link d-c-text d-d-inline-block",
|
|
568
|
+
class: "d-link d-c-text d-d-inline-block d-wb-break-all",
|
|
569
569
|
rel: "noopener noreferrer nofollow"
|
|
570
570
|
};
|
|
571
571
|
const Link = Mark.create({
|
|
@@ -619,6 +619,30 @@ function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
619
619
|
});
|
|
620
620
|
}
|
|
621
621
|
const MentionComponent = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$4]]);
|
|
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
|
+
};
|
|
622
646
|
const MentionPlugin = Mention.extend({
|
|
623
647
|
addNodeView() {
|
|
624
648
|
return VueNodeViewRenderer(MentionComponent);
|
|
@@ -647,7 +671,38 @@ const MentionPlugin = Mention.extend({
|
|
|
647
671
|
return `@${node.attrs.id}`;
|
|
648
672
|
},
|
|
649
673
|
renderHTML({ HTMLAttributes }) {
|
|
650
|
-
return ["mention-component", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)
|
|
674
|
+
return ["mention-component", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
|
|
675
|
+
},
|
|
676
|
+
addInputRules() {
|
|
677
|
+
var _a;
|
|
678
|
+
const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" });
|
|
679
|
+
return [
|
|
680
|
+
nodeInputRule({
|
|
681
|
+
find: (text) => mentionInputMatch(text, suggestions),
|
|
682
|
+
type: this.type,
|
|
683
|
+
getAttributes(attrs) {
|
|
684
|
+
return suggestions.find(({ id }) => id === attrs[0].replace("@", "").trim());
|
|
685
|
+
}
|
|
686
|
+
})
|
|
687
|
+
];
|
|
688
|
+
},
|
|
689
|
+
addPasteRules() {
|
|
690
|
+
var _a;
|
|
691
|
+
const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" });
|
|
692
|
+
return [
|
|
693
|
+
nodePasteRule({
|
|
694
|
+
find: (text) => mentionPasteMatch(text, suggestions),
|
|
695
|
+
type: this.type,
|
|
696
|
+
getAttributes(attrs) {
|
|
697
|
+
return suggestions.find(({ id }) => id === attrs[0].trim());
|
|
698
|
+
}
|
|
699
|
+
})
|
|
700
|
+
];
|
|
701
|
+
}
|
|
702
|
+
}).configure({
|
|
703
|
+
suggestion: {
|
|
704
|
+
char: "@",
|
|
705
|
+
pluginKey: new PluginKey("mentionSuggestion")
|
|
651
706
|
}
|
|
652
707
|
});
|
|
653
708
|
const _sfc_main$3 = {
|
|
@@ -679,8 +734,34 @@ function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
679
734
|
});
|
|
680
735
|
}
|
|
681
736
|
const ChannelComponent = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3]]);
|
|
737
|
+
const channelRegex = /#([\w-]+)[^\w-]?/g;
|
|
738
|
+
const channelPasteMatch = (text, suggestions) => {
|
|
739
|
+
const matches = [...text.matchAll(channelRegex)];
|
|
740
|
+
return matches.filter((match) => suggestions.some(({ id }) => id === match[1].trim())).map((match) => {
|
|
741
|
+
let channel = match[1];
|
|
742
|
+
if (!channel.endsWith(" "))
|
|
743
|
+
channel += " ";
|
|
744
|
+
return {
|
|
745
|
+
index: match.index,
|
|
746
|
+
text: channel,
|
|
747
|
+
match
|
|
748
|
+
};
|
|
749
|
+
});
|
|
750
|
+
};
|
|
751
|
+
const channelInputMatch = (text, suggestions) => {
|
|
752
|
+
const match = text.match(/#([\w-]+)[^\w-]$/);
|
|
753
|
+
if (!match || !suggestions.some(({ id }) => id === match[1]))
|
|
754
|
+
return;
|
|
755
|
+
return {
|
|
756
|
+
index: match.index,
|
|
757
|
+
text: match[0],
|
|
758
|
+
match
|
|
759
|
+
};
|
|
760
|
+
};
|
|
682
761
|
const ChannelPlugin = Mention.extend({
|
|
683
762
|
name: "channel",
|
|
763
|
+
group: "inline",
|
|
764
|
+
inline: true,
|
|
684
765
|
addNodeView() {
|
|
685
766
|
return VueNodeViewRenderer(ChannelComponent);
|
|
686
767
|
},
|
|
@@ -708,7 +789,33 @@ const ChannelPlugin = Mention.extend({
|
|
|
708
789
|
return `#${node.attrs.id}`;
|
|
709
790
|
},
|
|
710
791
|
renderHTML({ HTMLAttributes }) {
|
|
711
|
-
return ["channel-component", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)
|
|
792
|
+
return ["channel-component", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
|
|
793
|
+
},
|
|
794
|
+
addInputRules() {
|
|
795
|
+
var _a;
|
|
796
|
+
const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" });
|
|
797
|
+
return [
|
|
798
|
+
nodeInputRule({
|
|
799
|
+
find: (text) => channelInputMatch(text, suggestions),
|
|
800
|
+
type: this.type,
|
|
801
|
+
getAttributes(attrs) {
|
|
802
|
+
return suggestions.find(({ id }) => id === attrs[0].replace("#", "").trim());
|
|
803
|
+
}
|
|
804
|
+
})
|
|
805
|
+
];
|
|
806
|
+
},
|
|
807
|
+
addPasteRules() {
|
|
808
|
+
var _a;
|
|
809
|
+
const suggestions = (_a = this.options.suggestion) == null ? void 0 : _a.items({ query: "" });
|
|
810
|
+
return [
|
|
811
|
+
nodePasteRule({
|
|
812
|
+
find: (text) => channelPasteMatch(text, suggestions),
|
|
813
|
+
type: this.type,
|
|
814
|
+
getAttributes(attrs) {
|
|
815
|
+
return suggestions.find(({ id }) => id === attrs[0].trim());
|
|
816
|
+
}
|
|
817
|
+
})
|
|
818
|
+
];
|
|
712
819
|
}
|
|
713
820
|
}).configure({
|
|
714
821
|
suggestion: {
|
|
@@ -1098,7 +1205,7 @@ const _sfc_main = {
|
|
|
1098
1205
|
"input",
|
|
1099
1206
|
/**
|
|
1100
1207
|
* Event to sync the value with the parent
|
|
1101
|
-
* @event
|
|
1208
|
+
* @event update:value
|
|
1102
1209
|
* @type {String|JSON}
|
|
1103
1210
|
*/
|
|
1104
1211
|
"update:modelValue",
|
|
@@ -1118,7 +1225,8 @@ const _sfc_main = {
|
|
|
1118
1225
|
data() {
|
|
1119
1226
|
return {
|
|
1120
1227
|
editor: null,
|
|
1121
|
-
popoverOpened: false
|
|
1228
|
+
popoverOpened: false,
|
|
1229
|
+
internalValue: this.modelValue
|
|
1122
1230
|
};
|
|
1123
1231
|
},
|
|
1124
1232
|
computed: {
|
|
@@ -1235,7 +1343,8 @@ const _sfc_main = {
|
|
|
1235
1343
|
if (newValue === currentValue) {
|
|
1236
1344
|
return;
|
|
1237
1345
|
}
|
|
1238
|
-
this.
|
|
1346
|
+
this.internalValue = newValue;
|
|
1347
|
+
this.insertContent();
|
|
1239
1348
|
}
|
|
1240
1349
|
},
|
|
1241
1350
|
created() {
|
|
@@ -1248,7 +1357,6 @@ const _sfc_main = {
|
|
|
1248
1357
|
createEditor() {
|
|
1249
1358
|
this.editor = new Editor({
|
|
1250
1359
|
autofocus: this.autoFocus,
|
|
1251
|
-
content: this.modelValue,
|
|
1252
1360
|
editable: this.editable,
|
|
1253
1361
|
extensions: this.extensions,
|
|
1254
1362
|
editorProps: {
|
|
@@ -1258,8 +1366,62 @@ const _sfc_main = {
|
|
|
1258
1366
|
}
|
|
1259
1367
|
}
|
|
1260
1368
|
});
|
|
1369
|
+
this.insertContent();
|
|
1261
1370
|
this.addEditorListeners();
|
|
1262
1371
|
},
|
|
1372
|
+
/**
|
|
1373
|
+
* This function is necessary as tiptap doesn't render the content passed
|
|
1374
|
+
* directly through `editor.commands.setContent` the content passed down to it
|
|
1375
|
+
* should be already parsed. So We're parsing the elements into it's corresponding
|
|
1376
|
+
* HTML version before setting it.
|
|
1377
|
+
*/
|
|
1378
|
+
insertContent() {
|
|
1379
|
+
this.parseMentions();
|
|
1380
|
+
this.parseChannels();
|
|
1381
|
+
this.parseEmojis();
|
|
1382
|
+
this.editor.commands.setContent(this.internalValue, true);
|
|
1383
|
+
},
|
|
1384
|
+
parseEmojis() {
|
|
1385
|
+
const matches = [...this.modelValue.matchAll(emojiRegex()), ...this.modelValue.matchAll(emojiShortCodeRegex)];
|
|
1386
|
+
if (!matches)
|
|
1387
|
+
return;
|
|
1388
|
+
matches.forEach((match) => {
|
|
1389
|
+
const emoji = codeToEmojiData(match[0]);
|
|
1390
|
+
if (!emoji)
|
|
1391
|
+
return;
|
|
1392
|
+
this.internalValue = this.internalValue.replace(new RegExp(` ${match[0]}`), ` <emoji-component code="${emoji.shortname}"></emoji-component>`);
|
|
1393
|
+
});
|
|
1394
|
+
},
|
|
1395
|
+
parseChannels() {
|
|
1396
|
+
if (!this.channelSuggestion)
|
|
1397
|
+
return;
|
|
1398
|
+
const suggestions = this.channelSuggestion.items({ query: "" });
|
|
1399
|
+
const matches = [...this.modelValue.matchAll(channelRegex)].filter((match) => suggestions.some(({ id }) => id === match[1]));
|
|
1400
|
+
if (!matches)
|
|
1401
|
+
return;
|
|
1402
|
+
matches.forEach((match) => {
|
|
1403
|
+
const channel = suggestions.find(({ id }) => id === match[1]);
|
|
1404
|
+
this.internalValue = this.internalValue.replace(
|
|
1405
|
+
`#${match[1]}`,
|
|
1406
|
+
/** The space at the beginning is important as tiptap removes that while rendering.
|
|
1407
|
+
* So if multiple mentions, channels or emojis are next to each other it will fail
|
|
1408
|
+
*/
|
|
1409
|
+
` <channel-component name="${channel.name}" id="${channel.id}"></channel-component>`
|
|
1410
|
+
);
|
|
1411
|
+
});
|
|
1412
|
+
},
|
|
1413
|
+
parseMentions() {
|
|
1414
|
+
if (!this.mentionSuggestion)
|
|
1415
|
+
return;
|
|
1416
|
+
const suggestions = this.mentionSuggestion.items({ query: "" });
|
|
1417
|
+
const matches = [...this.modelValue.matchAll(mentionRegex)].filter((match) => suggestions.some(({ id }) => id === match[1]));
|
|
1418
|
+
if (!matches)
|
|
1419
|
+
return;
|
|
1420
|
+
matches.forEach((match) => {
|
|
1421
|
+
const mention = suggestions.find(({ id }) => id === match[1]);
|
|
1422
|
+
this.internalValue = this.internalValue.replace(`@${match[1]}`, ` <mention-component name="${mention.name}" id="${mention.id}"></mention-component>`);
|
|
1423
|
+
});
|
|
1424
|
+
},
|
|
1263
1425
|
destroyEditor() {
|
|
1264
1426
|
this.editor.destroy();
|
|
1265
1427
|
},
|